diff --git a/compliance/controls/aws/aws_account_alternate_contact_security_registered.yaml b/compliance/controls/aws/aws_account_alternate_contact_security_registered.yaml old mode 100755 new mode 100644 index b9fd67eb4..6db850001 --- a/compliance/controls/aws/aws_account_alternate_contact_security_registered.yaml +++ b/compliance/controls/aws/aws_account_alternate_contact_security_registered.yaml @@ -1,42 +1,42 @@ +Description: This control checks if an AWS Web Services (AWS) account has security contact information. The control fails if security contact information is not provided for the account. ID: aws_account_alternate_contact_security_registered -Title: "Security contact information should be provided for an AWS account" -Description: "This control checks if an AWS Web Services (AWS) account has security contact information. The control fails if security contact information is not provided for the account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_account + - aws_account_alternate_contact + Parameters: [] + PrimaryTable: aws_account QueryToExecute: | - with alternate_security_contact as ( - select + WITH alternate_security_contact AS ( + SELECT name, account_id - from + FROM aws_account_alternate_contact - where + WHERE contact_type = 'SECURITY' ) - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when a.partition = 'aws-us-gov' then 'info' - -- Name is a required field if setting a security contact - when c.name is not null then 'ok' - else 'alarm' - end as status, - case - when a.partition = 'aws-us-gov' then a.title || ' in GovCloud, manual verification required.' - when c.name is not null then a.title || ' has security contact ' || c.name || ' registered.' - else a.title || ' security contact not registered.' - end as reason - , a.account_id - from - aws_account as a - left join alternate_security_contact as c on c.account_id = a.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_account - - aws_account_alternate_contact - Parameters: [] + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN a.partition = 'aws-us-gov' THEN 'info' + WHEN c.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.partition = 'aws-us-gov' THEN a.title || ' in GovCloud, manual verification required.' + WHEN c.name IS NOT NULL THEN a.title || ' has security contact ' || c.name || ' registered.' + ELSE a.title || ' security contact not registered.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN alternate_security_contact AS c ON c.account_id = a.account_id; Severity: low Tags: category: @@ -57,5 +57,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Security contact information should be provided for an AWS account \ No newline at end of file diff --git a/compliance/controls/aws/aws_account_part_of_organizations.yaml b/compliance/controls/aws/aws_account_part_of_organizations.yaml old mode 100755 new mode 100644 index 5f50a59bb..ad25ba8c7 --- a/compliance/controls/aws/aws_account_part_of_organizations.yaml +++ b/compliance/controls/aws/aws_account_part_of_organizations.yaml @@ -1,28 +1,30 @@ +Description: Ensure that an AWS account is part of AWS Organizations. The rule is non-compliant if an AWS account is not part of AWS Organizations, or AWS Organizations' master account ID does not match rule parameter MasterAccountId. ID: aws_account_part_of_organizations -Title: "AWS account should be part of AWS Organizations" -Description: "Ensure that an AWS account is part of AWS Organizations. The rule is non-compliant if an AWS account is not part of AWS Organizations or AWS Organizations master account ID does not match rule parameter MasterAccountId." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when organization_id is not null then 'ok' - else 'alarm' - end as status, - case - when organization_id is not null then title || ' is part of organization(s).' - else title || ' is not part of organization.' - end as reason - , region, account_id - from - aws_account; - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN organization_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN organization_id IS NOT NULL THEN title || ' is part of organization(s).' + ELSE title || ' is not part of organization.' + END AS reason, + region, + account_id + FROM + aws_account; Severity: medium Tags: category: @@ -39,5 +41,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: AWS account should be part of AWS Organizations \ No newline at end of file diff --git a/compliance/controls/aws/aws_acm_certificate_expires_30_days.yaml b/compliance/controls/aws/aws_acm_certificate_expires_30_days.yaml old mode 100755 new mode 100644 index bb57612bb..14c7f391f --- a/compliance/controls/aws/aws_acm_certificate_expires_30_days.yaml +++ b/compliance/controls/aws/aws_acm_certificate_expires_30_days.yaml @@ -1,13 +1,32 @@ +Description: Ensure network integrity is protected by ensuring X509 certificates are issued by AWS ACM. ID: aws_acm_certificate_expires_30_days -Title: "ACM certificates should not expire within 30 days" -Description: "Ensure network integrity is protected by ensuring X509 certificates are issued by AWS ACM." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n certificate_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when renewal_eligibility = 'INELIGIBLE' then 'skip'\n when date(not_after) - date(current_date) >= 30 then 'ok'\n else 'alarm'\n end as status,\n case\n when renewal_eligibility = 'INELIGIBLE' then title || ' not eligible for renewal.'\n else title || ' expires ' || to_char(not_after, 'DD-Mon-YYYY') ||\n ' (' || extract(day from not_after - current_date) || ' days).'\n end as reason\n \n , region, account_id\nfrom\n aws_acm_certificate;\n" - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN renewal_eligibility = 'INELIGIBLE' THEN 'skip' + WHEN DATE(not_after) - DATE(current_date) >= 30 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN renewal_eligibility = 'INELIGIBLE' THEN title || ' not eligible for renewal.' + ELSE title || ' expires ' || TO_CHAR(not_after, 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM not_after - current_date) || ' days).' + END AS reason, + region, + account_id + FROM + aws_acm_certificate; Severity: high Tags: category: @@ -26,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -44,5 +63,4 @@ Tags: - AWS/ACM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: ACM certificates should not expire within 30 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_acm_certificate_no_failed_certificate.yaml b/compliance/controls/aws/aws_acm_certificate_no_failed_certificate.yaml old mode 100755 new mode 100644 index 2bf30575c..e307e4574 --- a/compliance/controls/aws/aws_acm_certificate_no_failed_certificate.yaml +++ b/compliance/controls/aws/aws_acm_certificate_no_failed_certificate.yaml @@ -1,14 +1,25 @@ +Description: This control ensures that ACM certificates are not in failed state. ID: aws_acm_certificate_no_failed_certificate -Title: "Ensure that ACM certificates are not in failed state" -Description: "This control ensures that ACM certificates are not in failed state." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n certificate_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when status in ('VALIDATION_TIMED_OUT', 'FAILED') then 'alarm'\n else 'ok'\n end as status,\n title || ' status is ' || status || '.' as reason\n \n \nfrom\n aws_acm_certificate;" - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN status IN ('VALIDATION_TIMED_OUT', 'FAILED') THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' status is ' || status || '.' AS reason + FROM + aws_acm_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure that ACM certificates are not in failed state \ No newline at end of file diff --git a/compliance/controls/aws/aws_acm_certificate_no_pending_validation_certificate.yaml b/compliance/controls/aws/aws_acm_certificate_no_pending_validation_certificate.yaml old mode 100755 new mode 100644 index d281f82f7..51b2ab376 --- a/compliance/controls/aws/aws_acm_certificate_no_pending_validation_certificate.yaml +++ b/compliance/controls/aws/aws_acm_certificate_no_pending_validation_certificate.yaml @@ -1,14 +1,25 @@ +Description: This control ensures that ACM certificates are not in pending validation state. When certificates are not validated within 72 hours after the request is made, those certificates become invalid. ID: aws_acm_certificate_no_pending_validation_certificate -Title: "Ensure that ACM certificates are not in pending validation state" -Description: "This control ensures that ACM certificates are not in pending validation state. When certificates are not validated within 72 hours after the request is made, those certificates become invalid." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n certificate_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when status = 'PENDING_VALIDATION' then 'info'\n else 'ok'\n end as status,\n title || ' status is ' || status || '.' as reason\n \n \nfrom\n aws_acm_certificate;" - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN status = 'PENDING_VALIDATION' THEN 'info' + ELSE 'ok' + END AS status, + title || ' status is ' || status || '.' AS reason + FROM + aws_acm_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure that ACM certificates are not in pending validation state \ No newline at end of file diff --git a/compliance/controls/aws/aws_acm_certificate_no_wildcard_domain_name.yaml b/compliance/controls/aws/aws_acm_certificate_no_wildcard_domain_name.yaml old mode 100755 new mode 100644 index bd2ec98d9..31b875a41 --- a/compliance/controls/aws/aws_acm_certificate_no_wildcard_domain_name.yaml +++ b/compliance/controls/aws/aws_acm_certificate_no_wildcard_domain_name.yaml @@ -1,28 +1,28 @@ +Description: Ensure that ACM single domain name certificates are used instead of wildcard certificates within your AWS account in order to follow security best practices and protect each domain/subdomain with its own unique private key. ID: aws_acm_certificate_no_wildcard_domain_name -Title: "ACM certificates should not use wildcard certificates" -Description: "Ensure that ACM single domain name certificates are used instead of wildcard certificates within your AWS account in order to follow security best practices and protect each domain/subdomain with its own unique private key." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - certificate_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when domain_name like '*%' then 'alarm' - else 'ok' - end as status, - case - when domain_name like '*%' then title || ' uses wildcard domain name.' - else title || ' does not use wildcard domain name.' - end as reason - from - aws_acm_certificate; - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN domain_name LIKE '*%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN domain_name LIKE '*%' THEN title || ' uses wildcard domain name.' + ELSE title || ' does not use wildcard domain name.' + END AS reason + FROM + aws_acm_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ACM certificates should not use wildcard certificates \ No newline at end of file diff --git a/compliance/controls/aws/aws_acm_certificate_not_expired.yaml b/compliance/controls/aws/aws_acm_certificate_not_expired.yaml old mode 100755 new mode 100644 index 6e261eeee..642d8013c --- a/compliance/controls/aws/aws_acm_certificate_not_expired.yaml +++ b/compliance/controls/aws/aws_acm_certificate_not_expired.yaml @@ -1,14 +1,32 @@ +Description: This control ensures that all expired ACM certificates are removed from AWS account. ID: aws_acm_certificate_not_expired -Title: "Ensure that all the expired ACM certificates are removed" -Description: "This control ensures that all expired ACM certificates are removed from AWS account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n certificate_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when renewal_eligibility = 'INELIGIBLE' then 'skip'\n when date(not_after) < (current_date - interval '1' minute) then 'alarm'\n else 'ok'\n end as status,\n case\n when renewal_eligibility = 'INELIGIBLE' then title || ' not eligible for renewal.'\n when date(not_after) < (current_date - interval '1' minute) then title || ' expired ' || to_char(not_after, 'DD-Mon-YYYY') ||\n ' (' || extract(day from not_after - current_date) || ' days ago).'\n else title || ' expires ' || to_char(not_after, 'DD-Mon-YYYY') ||\n ' (' || extract(day from not_after - current_date) || ' days).'\n end as reason\n \n \nfrom\n aws_acm_certificate;" - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN renewal_eligibility = 'INELIGIBLE' THEN 'skip' + WHEN DATE(not_after) < (CURRENT_DATE - INTERVAL '1' minute) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN renewal_eligibility = 'INELIGIBLE' THEN title || ' not eligible for renewal.' + WHEN DATE(not_after) < (CURRENT_DATE - INTERVAL '1' minute) THEN title || ' expired ' || TO_CHAR(not_after, 'DD-Mon-YYYY') || + ' (' || EXTRACT(day FROM not_after - CURRENT_DATE) || ' days ago).' + ELSE title || ' expires ' || TO_CHAR(not_after, 'DD-Mon-YYYY') || + ' (' || EXTRACT(day FROM not_after - CURRENT_DATE) || ' days).' + END AS reason + FROM + aws_acm_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure that all the expired ACM certificates are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_acm_certificate_rsa_key_length_2048_bits_or_greater.yaml b/compliance/controls/aws/aws_acm_certificate_rsa_key_length_2048_bits_or_greater.yaml old mode 100755 new mode 100644 index 99440a64d..98e24e323 --- a/compliance/controls/aws/aws_acm_certificate_rsa_key_length_2048_bits_or_greater.yaml +++ b/compliance/controls/aws/aws_acm_certificate_rsa_key_length_2048_bits_or_greater.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether RSA certificates managed by AWS Certificate Manager use a key length of at least 2,048 bits. The control fails if the key length is smaller than 2,048 bits. ID: aws_acm_certificate_rsa_key_length_2048_bits_or_greater -Title: "RSA certificates managed by ACM should use a key length of at least 2,048 bits" -Description: "This control checks whether RSA certificates managed by AWS Certificate Manager use a key length of at least 2,048 bits. The control fails if the key length is smaller than 2,048 bits." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n certificate_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when not key_algorithm like 'RSA-%' then 'skip'\n when key_algorithm = 'RSA_1024' then 'alarm'\n else 'ok'\n end as status,\n case\n when not key_algorithm like 'RSA-%' then title || ' is not a RSA certificate.'\n when key_algorithm = 'RSA_1024' then title || ' is using 1024 bits key length.'\n else title || ' is using ' || split_part(key_algorithm, '-', 2) || ' bits key length.'\n end as reason\n \n \nfrom\n aws_acm_certificate;" - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT key_algorithm LIKE 'RSA-%' THEN 'skip' + WHEN key_algorithm = 'RSA_1024' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT key_algorithm LIKE 'RSA-%' THEN title || ' is not a RSA certificate.' + WHEN key_algorithm = 'RSA_1024' THEN title || ' is using 1024 bits key length.' + ELSE title || ' is using ' || split_part(key_algorithm, '-', 2) || ' bits key length.' + END AS reason + FROM + aws_acm_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RSA certificates managed by ACM should use a key length of at least 2,048 bits \ No newline at end of file diff --git a/compliance/controls/aws/aws_acm_certificate_transparency_logging_enabled.yaml b/compliance/controls/aws/aws_acm_certificate_transparency_logging_enabled.yaml old mode 100755 new mode 100644 index 57f08c954..bd7af6b98 --- a/compliance/controls/aws/aws_acm_certificate_transparency_logging_enabled.yaml +++ b/compliance/controls/aws/aws_acm_certificate_transparency_logging_enabled.yaml @@ -1,30 +1,30 @@ +Description: Ensure ACM certificates transparency logging is enabled as certificate transparency logging guards against SSL/TLS certificates issued by mistake or by a compromised certificate authority. ID: aws_acm_certificate_transparency_logging_enabled -Title: "ACM certificates should have transparency logging enabled" -Description: "Ensure ACM certificates transparency logging is enabled as certificate transparency logging guards against SSL/TLS certificates issued by mistake or by a compromised certificate authority." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - certificate_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when type = 'IMPORTED' then 'skip' - when certificate_transparency_logging_preference = 'ENABLED' then 'ok' - else 'alarm' - end as status, - case - when type = 'IMPORTED' then title || ' is imported.' - when certificate_transparency_logging_preference = 'ENABLED' then title || ' transparency logging enabled.' - else title || ' transparency logging disabled.' - end as reason - from - aws_acm_certificate; - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN type = 'IMPORTED' THEN 'skip' + WHEN certificate_transparency_logging_preference = 'ENABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN type = 'IMPORTED' THEN title || ' is imported.' + WHEN certificate_transparency_logging_preference = 'ENABLED' THEN title || ' transparency logging enabled.' + ELSE title || ' transparency logging disabled.' + END AS reason + FROM + aws_acm_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ACM certificates should have transparency logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_acmpca_root_certificate_authority_disabled.yaml b/compliance/controls/aws/aws_acmpca_root_certificate_authority_disabled.yaml old mode 100755 new mode 100644 index 91b653880..e558b5af7 --- a/compliance/controls/aws/aws_acmpca_root_certificate_authority_disabled.yaml +++ b/compliance/controls/aws/aws_acmpca_root_certificate_authority_disabled.yaml @@ -1,14 +1,30 @@ +Description: This control checks if AWS Private CA has a root certificate authority (CA) that is disabled. The control fails if the root CA is enabled. ID: aws_acmpca_root_certificate_authority_disabled -Title: "AWS Private CA root certificate authority should be disabled" -Description: "This control checks if AWS Private CA has a root certificate authority (CA) that is disabled. The control fails if the root CA is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when type <> 'ROOT' then 'skip'\n when status = 'DISABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when type <> 'ROOT' then title || ' is not root CA.'\n when status = 'DISABLED' then title || ' root CA disabled.'\n else title || ' root CA not disabled.'\n end as reason\n \n \nfrom\n aws_acmpca_certificate_authority;" - PrimaryTable: aws_acmpca_certificate_authority ListOfTables: - aws_acmpca_certificate_authority Parameters: [] + PrimaryTable: aws_acmpca_certificate_authority + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN type <> 'ROOT' THEN 'skip' + WHEN status = 'DISABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN type <> 'ROOT' THEN title || ' is not root CA.' + WHEN status = 'DISABLED' THEN title || ' root CA disabled.' + ELSE title || ' root CA not disabled.' + END AS reason + FROM + aws_acmpca_certificate_authority; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: AWS Private CA root certificate authority should be disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_api_gateway_method_authorization_type_configured.yaml b/compliance/controls/aws/aws_api_gateway_method_authorization_type_configured.yaml old mode 100755 new mode 100644 index 78751e216..b915219b9 --- a/compliance/controls/aws/aws_api_gateway_method_authorization_type_configured.yaml +++ b/compliance/controls/aws/aws_api_gateway_method_authorization_type_configured.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether API Gateway method has an authorizer configured. This rule is non-compliant if API Gateway method has no authorizers configured. ID: aws_api_gateway_method_authorization_type_configured -Title: "API Gateway methods authorizer should be configured" -Description: "This control checks whether API Gateway method has an authorizer configured. This rule is non-compliant if API Gateway method has no authorizers configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n resource_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when authorization_type = 'NONE' then 'alarm'\n else 'ok'\n end as status,\n case\n when authorization_type = 'NONE' then title || ' authorization type not configured.'\n else title || ' authorization type ' || authorization_type || ' configured.'\n end as reason\n \nfrom\n aws_api_gateway_method;" - PrimaryTable: aws_api_gateway_method ListOfTables: - aws_api_gateway_method Parameters: [] + PrimaryTable: aws_api_gateway_method + QueryToExecute: | + SELECT + resource_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN authorization_type = 'NONE' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN authorization_type = 'NONE' THEN title || ' authorization type not configured.' + ELSE title || ' authorization type ' || authorization_type || ' configured.' + END AS reason + FROM + aws_api_gateway_method; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: API Gateway methods authorizer should be configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_api_gateway_method_request_parameter_validated.yaml b/compliance/controls/aws/aws_api_gateway_method_request_parameter_validated.yaml old mode 100755 new mode 100644 index d527d068a..7dd60d7fe --- a/compliance/controls/aws/aws_api_gateway_method_request_parameter_validated.yaml +++ b/compliance/controls/aws/aws_api_gateway_method_request_parameter_validated.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether API Gateway method request parameter is validated. This rule is non-compliant if API Gateway method request parameter is not validated. ID: aws_api_gateway_method_request_parameter_validated -Title: "API Gateway methods request parameter should be validated" -Description: "This control checks whether API Gateway method request parameter is validated. This rule is non-compliant if API Gateway method request parameter is not validated." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - resource_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when request_validator_id is null then 'alarm' - else 'ok' - end as status, - case - when request_validator_id is null then title || ' request parameter not validated.' - else title || ' request parameter validated.' - end as reason - from - aws_api_gateway_method; - PrimaryTable: aws_api_gateway_method ListOfTables: - aws_api_gateway_method Parameters: [] + PrimaryTable: aws_api_gateway_method + QueryToExecute: | + SELECT + resource_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN request_validator_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN request_validator_id IS NULL THEN title || ' request parameter not validated.' + ELSE title || ' request parameter validated.' + END AS reason + FROM + aws_api_gateway_method; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: API Gateway methods request parameter should be validated \ No newline at end of file diff --git a/compliance/controls/aws/aws_api_gateway_rest_api_public_endpoint_with_authorizer.yaml b/compliance/controls/aws/aws_api_gateway_rest_api_public_endpoint_with_authorizer.yaml old mode 100755 new mode 100644 index be07fb295..7acda1839 --- a/compliance/controls/aws/aws_api_gateway_rest_api_public_endpoint_with_authorizer.yaml +++ b/compliance/controls/aws/aws_api_gateway_rest_api_public_endpoint_with_authorizer.yaml @@ -1,32 +1,41 @@ +Description: Ensure API Gateway REST API public endpoint is configured with authorizer. This rule is non-compliant if API Gateway REST API public endpoint has no authorizer configured. ID: aws_api_gateway_rest_api_public_endpoint_with_authorizer -Title: "API Gateway REST API public endpoints should be configured with authorizer" -Description: "Ensure API Gateway REST API public endpoint is configured with authorizer. This rule is non-compliant if API Gateway REST API public endpoint has no authorizer configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || p.partition || ':apigateway:' || p.region || '::/apis/' || p.api_id as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when not (endpoint_configuration_types ? 'PRIVATE') and (a.provider_arns is not null and jsonb_array_length(a.provider_arns) > 0 ) then 'ok' - when not (endpoint_configuration_types ? 'PRIVATE') and ( a.provider_arns is null or jsonb_array_length(a.provider_arns) = 0 ) then 'alarm' - else 'ok' - end as status, - case - when not (endpoint_configuration_types ? 'PRIVATE') and (a.provider_arns is not null and jsonb_array_length(a.provider_arns) > 0 ) then p.name || ' has public endpoint with authorizer.' - when not (endpoint_configuration_types ? 'PRIVATE') and ( a.provider_arns is null or jsonb_array_length(a.provider_arns) = 0 ) then p.name || ' has public endpoint without authorizer.' - else p.name || ' has private endpoint.' - end as reason - from - aws_api_gateway_rest_api as p - left join aws_api_gateway_authorizer as a on p.api_id = a.rest_api_id; - PrimaryTable: aws_api_gateway_rest_api ListOfTables: - aws_api_gateway_rest_api - aws_api_gateway_authorizer Parameters: [] + PrimaryTable: aws_api_gateway_rest_api + QueryToExecute: | + SELECT + 'arn:' || p.partition || ':apigateway:' || p.region || '::/apis/' || p.api_id AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN NOT (endpoint_configuration_types ? 'PRIVATE') + AND (a.provider_arns IS NOT NULL AND jsonb_array_length(a.provider_arns) > 0) + THEN 'ok' + WHEN NOT (endpoint_configuration_types ? 'PRIVATE') + AND (a.provider_arns IS NULL OR jsonb_array_length(a.provider_arns) = 0) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (endpoint_configuration_types ? 'PRIVATE') + AND (a.provider_arns IS NOT NULL AND jsonb_array_length(a.provider_arns) > 0) + THEN p.name || ' has public endpoint with authorizer.' + WHEN NOT (endpoint_configuration_types ? 'PRIVATE') + AND (a.provider_arns IS NULL OR jsonb_array_length(a.provider_arns) = 0) + THEN p.name || ' has public endpoint without authorizer.' + ELSE p.name || ' has private endpoint.' + END AS reason + FROM + aws_api_gateway_rest_api AS p + LEFT JOIN aws_api_gateway_authorizer AS a + ON p.api_id = a.rest_api_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: API Gateway REST API public endpoints should be configured with authorizer \ No newline at end of file diff --git a/compliance/controls/aws/aws_api_gatewayv2_route_authorization_type_configured.yaml b/compliance/controls/aws/aws_api_gatewayv2_route_authorization_type_configured.yaml old mode 100755 new mode 100644 index 1f505756a..5323a6919 --- a/compliance/controls/aws/aws_api_gatewayv2_route_authorization_type_configured.yaml +++ b/compliance/controls/aws/aws_api_gatewayv2_route_authorization_type_configured.yaml @@ -1,28 +1,30 @@ +Description: This control checks if AWS API Gateway routes have an authorization type. The control fails if the API Gateway route does not specify an authorization type. ID: aws_api_gatewayv2_route_authorization_type_configured -Title: "API Gateway routes should specify an authorization type" -Description: "This control checks if AWS API Gateway routes have an authorization type. The control fails if the API Gateway route does not specify an authorization type." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/routes/' || route_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when authorization_type is null then 'alarm' - else 'ok' - end as status, - case - when authorization_type is null then route_id || ' authorization type not configured.' - else route_id || ' authorization type ' || authorization_type || ' configured.' - end as reason - , region, account_id - from - aws_api_gatewayv2_route; - PrimaryTable: aws_api_gatewayv2_route ListOfTables: - aws_api_gatewayv2_route Parameters: [] + PrimaryTable: aws_api_gatewayv2_route + QueryToExecute: | + SELECT + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/routes/' || route_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN authorization_type IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN authorization_type IS NULL THEN route_id || ' authorization type not configured.' + ELSE route_id || ' authorization type ' || authorization_type || ' configured.' + END AS reason, + region, + account_id + FROM + aws_api_gatewayv2_route; Severity: medium Tags: aws_foundational_security: @@ -37,5 +39,4 @@ Tags: - aws service: - AWS/APIGateway -IntegrationType: - - aws_cloud_account +Title: API Gateway routes should specify an authorization type \ No newline at end of file diff --git a/compliance/controls/aws/aws_api_gatewayv2_route_authorizer_configured.yaml b/compliance/controls/aws/aws_api_gatewayv2_route_authorizer_configured.yaml old mode 100755 new mode 100644 index 9bcd89c64..64a08ad54 --- a/compliance/controls/aws/aws_api_gatewayv2_route_authorizer_configured.yaml +++ b/compliance/controls/aws/aws_api_gatewayv2_route_authorizer_configured.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether API Gateway V2 has an authorizer configured. This rule is non-compliant if API Gateway V2 has no authorizers configured. ID: aws_api_gatewayv2_route_authorizer_configured -Title: "API Gateway V2 authorizer should be configured" -Description: "This control checks whether API Gateway V2 has an authorizer configured. This rule is non-compliant if API Gateway V2 has no authorizers configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/routes/' || route_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when authorizer_id is null then 'alarm' - else 'ok' - end as status, - case - when authorizer_id is null then route_id || ' authorizer not configured.' - else route_id || ' authorizer ' || authorizer_id || ' configured.' - end as reason - from - aws_api_gatewayv2_route; - PrimaryTable: aws_api_gatewayv2_route ListOfTables: - aws_api_gatewayv2_route Parameters: [] + PrimaryTable: aws_api_gatewayv2_route + QueryToExecute: | + SELECT + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/routes/' || route_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN authorizer_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN authorizer_id IS NULL THEN route_id || ' authorizer not configured.' + ELSE route_id || ' authorizer ' || authorizer_id || ' configured.' + END AS reason + FROM + aws_api_gatewayv2_route; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: API Gateway V2 authorizer should be configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_apigateway_rest_api_authorizers_configured.yaml b/compliance/controls/aws/aws_apigateway_rest_api_authorizers_configured.yaml old mode 100755 new mode 100644 index ef97d3b74..ab3e345c6 --- a/compliance/controls/aws/aws_apigateway_rest_api_authorizers_configured.yaml +++ b/compliance/controls/aws/aws_apigateway_rest_api_authorizers_configured.yaml @@ -1,30 +1,33 @@ +Description: Ensure API Gateway stages have authorizers configured. ID: aws_apigateway_rest_api_authorizers_configured -Title: "API Gateway stages should have authorizers configured" -Description: "Ensure API Gateway stages have authorizers configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - p.name as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when jsonb_array_length(a.provider_arns) > 0 then 'ok' - else 'alarm' - end as status, - case - when jsonb_array_length(a.provider_arns) > 0 then p.name || ' authorizers configured.' - else p.name || ' authorizers not configured.' - end as reason - from - aws_api_gateway_rest_api as p - left join aws_api_gateway_authorizer as a on p.api_id = a.rest_api_id; - PrimaryTable: aws_api_gateway_rest_api ListOfTables: - aws_api_gateway_rest_api - aws_api_gateway_authorizer Parameters: [] + PrimaryTable: aws_api_gateway_rest_api + QueryToExecute: | + SELECT + p.name AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(a.provider_arns) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(a.provider_arns) > 0 THEN p.name || ' authorizers configured.' + ELSE p.name || ' authorizers not configured.' + END AS reason + FROM + aws_api_gateway_rest_api AS p + LEFT JOIN + aws_api_gateway_authorizer AS a + ON + p.api_id = a.rest_api_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: API Gateway stages should have authorizers configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_apigateway_rest_api_endpoint_restrict_public_access.yaml b/compliance/controls/aws/aws_apigateway_rest_api_endpoint_restrict_public_access.yaml old mode 100755 new mode 100644 index 2acc36efa..448391576 --- a/compliance/controls/aws/aws_apigateway_rest_api_endpoint_restrict_public_access.yaml +++ b/compliance/controls/aws/aws_apigateway_rest_api_endpoint_restrict_public_access.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether API Gateway endpoint is public or private. This rule is non-compliant if API Gateway endpoint is public. ID: aws_apigateway_rest_api_endpoint_restrict_public_access -Title: "API Gateway REST API endpoint type should be configured to private" -Description: "This control checks whether API Gateway endpoint is public or private. This rule is non-compliant if API Gateway endpoint is public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when endpoint_configuration_types ? 'PRIVATE' then 'ok' - else 'alarm' - end as status, - case - when endpoint_configuration_types ? 'PRIVATE' then name || ' not publicly accessible.' - else name || ' publicly accessible.' - end as reason - from - aws_api_gateway_rest_api; - PrimaryTable: aws_api_gateway_rest_api ListOfTables: - aws_api_gateway_rest_api Parameters: [] + PrimaryTable: aws_api_gateway_rest_api + QueryToExecute: | + SELECT + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN endpoint_configuration_types ? 'PRIVATE' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN endpoint_configuration_types ? 'PRIVATE' THEN name || ' not publicly accessible.' + ELSE name || ' publicly accessible.' + END AS reason + FROM + aws_api_gateway_rest_api; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: API Gateway REST API endpoint type should be configured to private \ No newline at end of file diff --git a/compliance/controls/aws/aws_apigateway_rest_api_stage_use_ssl_certificate.yaml b/compliance/controls/aws/aws_apigateway_rest_api_stage_use_ssl_certificate.yaml old mode 100755 new mode 100644 index a3c4239d5..14dfefd0c --- a/compliance/controls/aws/aws_apigateway_rest_api_stage_use_ssl_certificate.yaml +++ b/compliance/controls/aws/aws_apigateway_rest_api_stage_use_ssl_certificate.yaml @@ -1,13 +1,30 @@ +Description: Ensure that a REST API stage uses a Secure Sockets Layer (SSL) certificate. This rule is compliant if the REST API stage does not have an associated SSL certificate. ID: aws_apigateway_rest_api_stage_use_ssl_certificate -Title: "API Gateway stage should uses SSL certificate" -Description: "Ensure that a REST API stage uses a Secure Sockets Layer (SSL) certificate. This rule is compliant if the REST API stage does not have an associated SSL certificate." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when client_certificate_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when client_certificate_id is null then title || ' does not use SSL certificate.'\n else title || ' uses SSL certificate.'\n end as reason\n \n , region, account_id\nfrom\n aws_api_gateway_stage;\n" - PrimaryTable: aws_api_gateway_stage ListOfTables: - aws_api_gateway_stage Parameters: [] + PrimaryTable: aws_api_gateway_stage + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN client_certificate_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN client_certificate_id IS NULL THEN title || ' does not use SSL certificate.' + ELSE title || ' uses SSL certificate.' + END AS reason, + region, + account_id + FROM + aws_api_gateway_stage; Severity: low Tags: category: @@ -22,10 +39,10 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -34,5 +51,4 @@ Tags: - "true" service: - AWS/APIGateway -IntegrationType: - - aws_cloud_account +Title: API Gateway stage should uses SSL certificate \ No newline at end of file diff --git a/compliance/controls/aws/aws_apigateway_rest_api_stage_xray_tracing_enabled.yaml b/compliance/controls/aws/aws_apigateway_rest_api_stage_xray_tracing_enabled.yaml old mode 100755 new mode 100644 index f1a7c2819..3521c126f --- a/compliance/controls/aws/aws_apigateway_rest_api_stage_xray_tracing_enabled.yaml +++ b/compliance/controls/aws/aws_apigateway_rest_api_stage_xray_tracing_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether AWS X-Ray active tracing is enabled for your AWS API Gateway REST API stages. ID: aws_apigateway_rest_api_stage_xray_tracing_enabled -Title: "API Gateway REST API stages should have AWS X-Ray tracing enabled" -Description: "This control checks whether AWS X-Ray active tracing is enabled for your AWS API Gateway REST API stages." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when tracing_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when tracing_enabled then title || ' X-Ray tracing enabled.'\n else title || ' X-Ray tracing disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_api_gateway_stage;\n" - PrimaryTable: aws_api_gateway_stage ListOfTables: - aws_api_gateway_stage Parameters: [] + PrimaryTable: aws_api_gateway_stage + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN tracing_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN tracing_enabled THEN title || ' X-Ray tracing enabled.' + ELSE title || ' X-Ray tracing disabled.' + END AS reason, + region, + account_id + FROM + aws_api_gateway_stage; Severity: low Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/APIGateway -IntegrationType: - - aws_cloud_account +Title: API Gateway REST API stages should have AWS X-Ray tracing enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_apigateway_stage_cache_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_apigateway_stage_cache_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 4ee19ac48..d6b7d08eb --- a/compliance/controls/aws/aws_apigateway_stage_cache_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_apigateway_stage_cache_encryption_at_rest_enabled.yaml @@ -1,13 +1,34 @@ +Description: To help protect data at rest, ensure encryption is enabled for your API Gateway stage's cache. ID: aws_apigateway_stage_cache_encryption_at_rest_enabled -Title: "API Gateway stage cache encryption at rest should be enabled" -Description: "To help protect data at rest, ensure encryption is enabled for your API Gateway stage's cache." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':apigateway:' || region || '::/apis/' || rest_api_id || '/stages/' || name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when method_settings -> '*/*' ->> 'CachingEnabled' = 'true'\n and method_settings -> '*/*' ->> 'CacheDataEncrypted' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when method_settings -> '*/*' ->> 'CachingEnabled' = 'true'\n and method_settings -> '*/*' ->> 'CacheDataEncrypted' = 'true'\n then title || ' API cache and encryption enabled.'\n else title || ' API cache and encryption not enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_api_gateway_stage;\n" - PrimaryTable: aws_api_gateway_stage ListOfTables: - aws_api_gateway_stage Parameters: [] + PrimaryTable: aws_api_gateway_stage + QueryToExecute: | + SELECT + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || rest_api_id || '/stages/' || name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN method_settings -> '*/*' ->> 'CachingEnabled' = 'true' + AND method_settings -> '*/*' ->> 'CacheDataEncrypted' = 'true' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN method_settings -> '*/*' ->> 'CachingEnabled' = 'true' + AND method_settings -> '*/*' ->> 'CacheDataEncrypted' = 'true' + THEN title || ' API cache and encryption enabled.' + ELSE title || ' API cache and encryption not enabled.' + END AS reason, + region, + account_id + FROM + aws_api_gateway_stage; Severity: medium Tags: category: @@ -26,12 +47,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -44,5 +65,4 @@ Tags: - AWS/APIGateway soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: API Gateway stage cache encryption at rest should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_apigateway_stage_logging_enabled.yaml b/compliance/controls/aws/aws_apigateway_stage_logging_enabled.yaml old mode 100755 new mode 100644 index f6ddf3aa5..6801c715b --- a/compliance/controls/aws/aws_apigateway_stage_logging_enabled.yaml +++ b/compliance/controls/aws/aws_apigateway_stage_logging_enabled.yaml @@ -1,14 +1,63 @@ +Description: API Gateway logging displays detailed views of users who accessed the API and the way they accessed the API. ID: aws_apigateway_stage_logging_enabled -Title: "API Gateway stage logging should be enabled" -Description: "API Gateway logging displays detailed views of users who accessed the API and the way they accessed the API." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_stages as (\n select\n name as stage_name,\n 'arn:' || partition || ':apigateway:' || region || '::/apis/' || rest_api_id || '/stages/' || name as arn,\n method_settings -> '*/*' ->> 'LoggingLevel' as log_level,\n title,\n region,\n account_id,\n tags,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_api_gateway_stage' as og_table_name,\n _ctx\n from\n aws_api_gateway_stage\n union\n select\n stage_name,\n 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/stages/' || stage_name as arn,\n default_route_logging_level as log_level,\n title,\n region,\n account_id,\n tags,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_api_gatewayv2_stage' as og_table_name,\n _ctx\n from\n aws_api_gatewayv2_stage\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n og_table_name as og_table_name,\n case\n when log_level is null or log_level = '' or log_level = 'OFF' then 'alarm'\n else 'ok'\n end as status,\n case\n when log_level is null or log_level = '' or log_level = 'OFF' then title || ' logging not enabled.'\n else title || ' logging enabled.'\n end as reason\n \n , region, account_id\nfrom\n all_stages;\n" - PrimaryTable: "" ListOfTables: - aws_api_gateway_stage - aws_api_gatewayv2_stage Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH all_stages AS ( + SELECT + name AS stage_name, + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || rest_api_id || '/stages/' || name AS arn, + method_settings -> '*/*' ->> 'LoggingLevel' AS log_level, + title, + region, + account_id, + tags, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_api_gateway_stage' AS og_table_name, + _ctx + FROM + aws_api_gateway_stage + UNION + SELECT + stage_name, + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/stages/' || stage_name AS arn, + default_route_logging_level AS log_level, + title, + region, + account_id, + tags, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_api_gatewayv2_stage' AS og_table_name, + _ctx + FROM + aws_api_gatewayv2_stage + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + og_table_name AS og_table_name, + CASE + WHEN log_level IS NULL OR log_level = '' OR log_level = 'OFF' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN log_level IS NULL OR log_level = '' OR log_level = 'OFF' THEN title || ' logging not enabled.' + ELSE title || ' logging enabled.' + END AS reason, + region, + account_id + FROM + all_stages; Severity: high Tags: category: @@ -29,12 +78,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -47,5 +96,4 @@ Tags: - AWS/APIGateway soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: API Gateway stage logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_apigateway_stage_use_waf_web_acl.yaml b/compliance/controls/aws/aws_apigateway_stage_use_waf_web_acl.yaml old mode 100755 new mode 100644 index 3099efc17..4150269fe --- a/compliance/controls/aws/aws_apigateway_stage_use_waf_web_acl.yaml +++ b/compliance/controls/aws/aws_apigateway_stage_use_waf_web_acl.yaml @@ -1,13 +1,30 @@ +Description: Ensure that an AWS API Gateway API stage is using a WAF Web ACL. This rule is non-compliant if an AWS WAF Web ACL is not used. ID: aws_apigateway_stage_use_waf_web_acl -Title: "API Gateway stage should be associated with waf" -Description: "Ensure that an AWS API Gateway API stage is using a WAF Web ACL. This rule is non-compliant if an AWS WAF Web ACL is not used." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when web_acl_arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when web_acl_arn is not null then title || ' associated with WAF web ACL.'\n else title || ' not associated with WAF web ACL.'\n end as reason\n \n , region, account_id\nfrom\n aws_api_gateway_stage;\n" - PrimaryTable: aws_api_gateway_stage ListOfTables: - aws_api_gateway_stage Parameters: [] + PrimaryTable: aws_api_gateway_stage + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN web_acl_arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN web_acl_arn IS NOT NULL THEN title || ' associated with WAF web ACL.' + ELSE title || ' not associated with WAF web ACL.' + END AS reason, + region, + account_id + FROM + aws_api_gateway_stage; Severity: medium Tags: category: @@ -22,10 +39,10 @@ Tags: - "true" ffiec: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -36,5 +53,4 @@ Tags: - "true" service: - AWS/APIGateway -IntegrationType: - - aws_cloud_account +Title: API Gateway stage should be associated with waf \ No newline at end of file diff --git a/compliance/controls/aws/aws_appstream_fleet_default_internet_access_disabled.yaml b/compliance/controls/aws/aws_appstream_fleet_default_internet_access_disabled.yaml old mode 100755 new mode 100644 index 1d6fc1b2e..123c704eb --- a/compliance/controls/aws/aws_appstream_fleet_default_internet_access_disabled.yaml +++ b/compliance/controls/aws/aws_appstream_fleet_default_internet_access_disabled.yaml @@ -1,28 +1,28 @@ +Description: Enabling default internet access for AppStream fleet is not recommended. This control will be considered non-compliant if default internet access is enabled for AppStream fleet. ID: aws_appstream_fleet_default_internet_access_disabled -Title: "AppStream fleet default internet access should be disabled" -Description: "Enabling default internet access for AppStream fleet is not recommended. This control will be considered non-compliant if default internet access is enabled for AppStream fleet." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when enable_default_internet_access then 'alarm' - else 'ok' - end as status, - case - when enable_default_internet_access then title || ' has default internet access enabled.' - else title || ' has default internet access disabled.' - end as reason - from - aws_appstream_fleet; - PrimaryTable: aws_appstream_fleet ListOfTables: - aws_appstream_fleet Parameters: [] + PrimaryTable: aws_appstream_fleet + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enable_default_internet_access THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN enable_default_internet_access THEN title || ' has default internet access enabled.' + ELSE title || ' has default internet access disabled.' + END AS reason + FROM + aws_appstream_fleet; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: AppStream fleet default internet access should be disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_appstream_fleet_idle_disconnect_timeout_600_seconds.yaml b/compliance/controls/aws/aws_appstream_fleet_idle_disconnect_timeout_600_seconds.yaml old mode 100755 new mode 100644 index 68b85fa7d..3ba6f4b71 --- a/compliance/controls/aws/aws_appstream_fleet_idle_disconnect_timeout_600_seconds.yaml +++ b/compliance/controls/aws/aws_appstream_fleet_idle_disconnect_timeout_600_seconds.yaml @@ -1,25 +1,25 @@ +Description: Ensure session idle disconnect timeout is set to 10 minutes or less. ID: aws_appstream_fleet_idle_disconnect_timeout_600_seconds -Title: "AppStream fleet idle disconnect timeout should be set to less than or equal to 10 mins" -Description: "Ensure session idle disconnect timeout is set to 10 minutes or less." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when idle_disconnect_timeout_in_seconds <= 600 then 'ok' - else 'alarm' - end as status, - title || ' idle disconnect timeout in seconds is set to ' || idle_disconnect_timeout_in_seconds || ' seconds.' as reason - from - aws_appstream_fleet; - PrimaryTable: aws_appstream_fleet ListOfTables: - aws_appstream_fleet Parameters: [] + PrimaryTable: aws_appstream_fleet + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN idle_disconnect_timeout_in_seconds <= 600 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' idle disconnect timeout in seconds is set to ' || idle_disconnect_timeout_in_seconds || ' seconds.' AS reason + FROM + aws_appstream_fleet; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: AppStream fleet idle disconnect timeout should be set to less than or equal to 10 mins \ No newline at end of file diff --git a/compliance/controls/aws/aws_appstream_fleet_max_user_duration_36000_seconds.yaml b/compliance/controls/aws/aws_appstream_fleet_max_user_duration_36000_seconds.yaml old mode 100755 new mode 100644 index a27bf4fd8..6e4f49bee --- a/compliance/controls/aws/aws_appstream_fleet_max_user_duration_36000_seconds.yaml +++ b/compliance/controls/aws/aws_appstream_fleet_max_user_duration_36000_seconds.yaml @@ -1,14 +1,25 @@ +Description: Ensure user maximum session duration is no longer than 10 hours. A session duration exceeding 10 hours is unnecessary and may offer malicious users an extended period of unauthorized usage beyond acceptable limits. ID: aws_appstream_fleet_max_user_duration_36000_seconds -Title: "AppStream fleet max user duration should be set to less than 10 hours" -Description: "Ensure user maximum session duration is no longer than 10 hours. A session duration exceeding 10 hours is unnecessary and may offer malicious users an extended period of unauthorized usage beyond acceptable limits." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when max_user_duration_in_seconds < 36000 then 'ok'\n else 'alarm'\n end as status,\n title || ' max user duration in seconds is set to ' || max_user_duration_in_seconds || ' seconds.' as reason\n \n \nfrom\n aws_appstream_fleet;" - PrimaryTable: aws_appstream_fleet ListOfTables: - aws_appstream_fleet Parameters: [] + PrimaryTable: aws_appstream_fleet + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN max_user_duration_in_seconds < 36000 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' max user duration in seconds is set to ' || max_user_duration_in_seconds || ' seconds.' AS reason + FROM + aws_appstream_fleet; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: AppStream fleet max user duration should be set to less than 10 hours \ No newline at end of file diff --git a/compliance/controls/aws/aws_appstream_fleet_session_disconnect_timeout_300_seconds.yaml b/compliance/controls/aws/aws_appstream_fleet_session_disconnect_timeout_300_seconds.yaml old mode 100755 new mode 100644 index 5cf7eb00c..ee1adad3d --- a/compliance/controls/aws/aws_appstream_fleet_session_disconnect_timeout_300_seconds.yaml +++ b/compliance/controls/aws/aws_appstream_fleet_session_disconnect_timeout_300_seconds.yaml @@ -1,14 +1,25 @@ +Description: The disconnect timeout in minutes refers to the duration for which a streaming session remains active even after users have disconnected. It is recommended to set the disconnect timeout to 5 minutes or less for the AppStream Fleet. ID: aws_appstream_fleet_session_disconnect_timeout_300_seconds -Title: "AppStream fleet session disconnect timeout should be set to less than or equal to 5 mins" -Description: "The disconnect timeout in minutes refers to the duration for which a streaming session remains active even after users have disconnected. It is recommended to set the disconnect timeout to 5 minutes or less for the AppStream Fleet." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when disconnect_timeout_in_seconds <= 300 then 'ok'\n else 'alarm'\n end as status,\n title || ' disconnect timeout in seconds is set to ' || disconnect_timeout_in_seconds || ' seconds.' as reason\n \n \nfrom\n aws_appstream_fleet;" - PrimaryTable: aws_appstream_fleet ListOfTables: - aws_appstream_fleet Parameters: [] + PrimaryTable: aws_appstream_fleet + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN disconnect_timeout_in_seconds <= 300 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' disconnect timeout in seconds is set to ' || disconnect_timeout_in_seconds || ' seconds.' AS reason + FROM + aws_appstream_fleet; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: AppStream fleet session disconnect timeout should be set to less than or equal to 5 mins \ No newline at end of file diff --git a/compliance/controls/aws/aws_appsync_graphql_api_field_level_logging_enabled.yaml b/compliance/controls/aws/aws_appsync_graphql_api_field_level_logging_enabled.yaml old mode 100755 new mode 100644 index b0ff1ae80..3782fa8f8 --- a/compliance/controls/aws/aws_appsync_graphql_api_field_level_logging_enabled.yaml +++ b/compliance/controls/aws/aws_appsync_graphql_api_field_level_logging_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an AWS AppSync API has field-level logging turned on. The control fails if the field resolver log level is set to None. Unless you provide custom parameter values to indicate that a specific log type should be enabled, Security Hub produces a passed finding if the field resolver log level is either ERROR or ALL. ID: aws_appsync_graphql_api_field_level_logging_enabled -Title: "AppSync graphql API logging should be enabled" -Description: "This control checks whether an AWS AppSync API has field-level logging turned on. The control fails if the field resolver log level is set to None. Unless you provide custom parameter values to indicate that a specific log type should be enabled, Security Hub produces a passed finding if the field resolver log level is either ERROR or ALL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - name as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_config ->> 'FieldLogLevel' in ('ERROR', 'ALL') then 'ok' - else 'alarm' - end as status, - case - when log_config ->> 'FieldLogLevel' in ('ERROR', 'ALL') then title || ' field level logging enabled.' - else name || ' field level logging disabled.' - end as reason - from - aws_appsync_graphql_api; - PrimaryTable: aws_appsync_graphql_api ListOfTables: - aws_appsync_graphql_api Parameters: [] + PrimaryTable: aws_appsync_graphql_api + QueryToExecute: | + SELECT + name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_config ->> 'FieldLogLevel' IN ('ERROR', 'ALL') THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_config ->> 'FieldLogLevel' IN ('ERROR', 'ALL') THEN title || ' field level logging enabled.' + ELSE name || ' field level logging disabled.' + END AS reason + FROM + aws_appsync_graphql_api; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: AppSync graphql API logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_athena_workgroup_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_athena_workgroup_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 0a2f4a0db..4c5635b48 --- a/compliance/controls/aws/aws_athena_workgroup_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_athena_workgroup_encryption_at_rest_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks if an Athena workgroup is encrypted at rest. The control fails if an Athena workgroup isn't encrypted at rest. ID: aws_athena_workgroup_encryption_at_rest_enabled -Title: "Athena workgroups should be encrypted at rest" -Description: "This control checks if an Athena workgroup is encrypted at rest. The control fails if an Athena workgroup isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encryption_option is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption_option is not null then name || ' encryption at rest enabled.'\n else name || ' encryption at rest disabled.'\n end as reason\n \nfrom\n aws_athena_workgroup;" - PrimaryTable: aws_athena_workgroup ListOfTables: - aws_athena_workgroup Parameters: [] + PrimaryTable: aws_athena_workgroup + QueryToExecute: | + SELECT + name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encryption_option IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_option IS NOT NULL THEN name || ' encryption at rest enabled.' + ELSE name || ' encryption at rest disabled.' + END AS reason + FROM + aws_athena_workgroup; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Athena workgroups should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_athena_workgroup_enforce_configuration_enabled.yaml b/compliance/controls/aws/aws_athena_workgroup_enforce_configuration_enabled.yaml old mode 100755 new mode 100644 index dc363fb17..48804f45f --- a/compliance/controls/aws/aws_athena_workgroup_enforce_configuration_enabled.yaml +++ b/compliance/controls/aws/aws_athena_workgroup_enforce_configuration_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks if an Athena workgroup enforces configuration. The control fails if an Athena workgroup doesn't enforce configuration. ID: aws_athena_workgroup_enforce_configuration_enabled -Title: "Athena workgroups should enforce configuration" -Description: "This control checks if an Athena workgroup enforces configuration. The control fails if an Athena workgroup doesn't enforce configuration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when enforce_workgroup_configuration then 'ok'\n else 'alarm'\n end as status,\n case\n when enforce_workgroup_configuration then name || ' has enforce workgroup configuration enabled.'\n else name || ' has enforce workgroup configuration disabled.'\n end as reason\n \nfrom\n aws_athena_workgroup;" - PrimaryTable: aws_athena_workgroup ListOfTables: - aws_athena_workgroup Parameters: [] + PrimaryTable: aws_athena_workgroup + QueryToExecute: | + SELECT + name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enforce_workgroup_configuration THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enforce_workgroup_configuration THEN name || ' has enforce workgroup configuration enabled.' + ELSE name || ' has enforce workgroup configuration disabled.' + END AS reason + FROM + aws_athena_workgroup; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Athena workgroups should enforce configuration \ No newline at end of file diff --git a/compliance/controls/aws/aws_autoscaling_ec2_launch_configuration_no_sensitive_data.yaml b/compliance/controls/aws/aws_autoscaling_ec2_launch_configuration_no_sensitive_data.yaml old mode 100755 new mode 100644 index 331efbdf6..a5f8246b2 --- a/compliance/controls/aws/aws_autoscaling_ec2_launch_configuration_no_sensitive_data.yaml +++ b/compliance/controls/aws/aws_autoscaling_ec2_launch_configuration_no_sensitive_data.yaml @@ -1,14 +1,32 @@ +Description: Ensure that sensitive information is not included in the user data of the launch configuration. It is recommended to utilize Secrets Manager as an alternative for securely managing sensitive data. ID: aws_autoscaling_ec2_launch_configuration_no_sensitive_data -Title: "EC2 auto scaling group launch configurations user data should not have any sensitive data" -Description: "Ensure that sensitive information is not included in the user data of the launch configuration. It is recommended to utilize Secrets Manager as an alternative for securely managing sensitive data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n launch_configuration_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when\n user_data like any (array [ '%pass%', '%secret%', '%token%', '%key%' ])\n or user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]' then 'alarm'\n else 'ok'\n end as status,\n case\n when\n user_data like any (array [ '%pass%', '%secret%', '%token%', '%key%' ])\n or user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]' then title || ' has potential secret patterns in user data.'\n else title || ' does not contain secret patterns in user data.'\n end as reason\n \nfrom\n aws_ec2_launch_configuration;" - PrimaryTable: aws_ec2_launch_configuration ListOfTables: - aws_ec2_launch_configuration Parameters: [] + PrimaryTable: aws_ec2_launch_configuration + QueryToExecute: | + SELECT + launch_configuration_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN + user_data LIKE ANY (ARRAY [ '%pass%', '%secret%', '%token%', '%key%' ]) + OR user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + user_data LIKE ANY (ARRAY [ '%pass%', '%secret%', '%token%', '%key%' ]) + OR user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' THEN title || ' has potential secret patterns in user data.' + ELSE title || ' does not contain secret patterns in user data.' + END AS reason + FROM + aws_ec2_launch_configuration; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 auto scaling group launch configurations user data should not have any sensitive data \ No newline at end of file diff --git a/compliance/controls/aws/aws_autoscaling_group_multiple_az_configured.yaml b/compliance/controls/aws/aws_autoscaling_group_multiple_az_configured.yaml old mode 100755 new mode 100644 index bed87f6cf..932d52fff --- a/compliance/controls/aws/aws_autoscaling_group_multiple_az_configured.yaml +++ b/compliance/controls/aws/aws_autoscaling_group_multiple_az_configured.yaml @@ -1,13 +1,27 @@ +Description: This control checks whether an AWS EC2 Auto Scaling group spans multiple availability zones. The control fails if an auto scaling group does not span multiple availability zones. ID: aws_autoscaling_group_multiple_az_configured -Title: "EC2 auto scaling groups should cover multiple availability zones" -Description: "This control checks whether an AWS EC2 Auto Scaling group spans multiple availability zones. The control fails if an auto scaling group does not span multiple availability zones." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n autoscaling_group_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(availability_zones) > 1 then 'ok'\n else 'alarm'\n end as status,\n title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason\n \n , region, account_id\nfrom\n aws_ec2_autoscaling_group;\n" - PrimaryTable: aws_ec2_autoscaling_group ListOfTables: - aws_ec2_autoscaling_group Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + SELECT + autoscaling_group_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(availability_zones) > 1 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason, + region, + account_id + FROM + aws_ec2_autoscaling_group; Severity: medium Tags: aws_foundational_security: @@ -22,5 +36,4 @@ Tags: - aws service: - AWS/AutoScaling -IntegrationType: - - aws_cloud_account +Title: EC2 auto scaling groups should cover multiple availability zones \ No newline at end of file diff --git a/compliance/controls/aws/aws_autoscaling_group_no_suspended_process.yaml b/compliance/controls/aws/aws_autoscaling_group_no_suspended_process.yaml old mode 100755 new mode 100644 index b205f7bb4..a352a7a32 --- a/compliance/controls/aws/aws_autoscaling_group_no_suspended_process.yaml +++ b/compliance/controls/aws/aws_autoscaling_group_no_suspended_process.yaml @@ -1,14 +1,28 @@ +Description: Ensure that there are no Auto Scaling Groups (ASGs) with suspended processes provisioned in your AWS account in order to avoid disrupting the auto scaling workflow. ID: aws_autoscaling_group_no_suspended_process -Title: "Auto Scaling groups should not have any suspended processes" -Description: "Ensure that there are no Auto Scaling Groups (ASGs) with suspended processes provisioned in your AWS account in order to avoid disrupting the auto scaling workflow." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n autoscaling_group_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when suspended_processes is null then 'ok'\n else 'alarm'\n end as status,\n case\n when suspended_processes is null then title || ' has no suspended process.'\n else title || ' has suspended process.'\n end as reason\n \n \nfrom\n aws_ec2_autoscaling_group;" - PrimaryTable: aws_ec2_autoscaling_group ListOfTables: - aws_ec2_autoscaling_group Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + SELECT + autoscaling_group_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN suspended_processes IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN suspended_processes IS NULL THEN title || ' has no suspended process.' + ELSE title || ' has suspended process.' + END AS reason + FROM + aws_ec2_autoscaling_group; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Auto Scaling groups should not have any suspended processes \ No newline at end of file diff --git a/compliance/controls/aws/aws_autoscaling_group_propagate_tags_to_ec2_instance_enabled.yaml b/compliance/controls/aws/aws_autoscaling_group_propagate_tags_to_ec2_instance_enabled.yaml old mode 100755 new mode 100644 index b609b9914..bfb15f9d7 --- a/compliance/controls/aws/aws_autoscaling_group_propagate_tags_to_ec2_instance_enabled.yaml +++ b/compliance/controls/aws/aws_autoscaling_group_propagate_tags_to_ec2_instance_enabled.yaml @@ -1,41 +1,42 @@ +Description: Tags can help with managing, identifying, organizing, searching for, and filtering resources. Additionally, tags can help with security and compliance. Tags can be propagated from an Auto Scaling group to the EC2 instances that it launches. ID: aws_autoscaling_group_propagate_tags_to_ec2_instance_enabled -Title: "Ensure EC2 Auto Scaling Groups Propagate Tags to EC2 Instances that it launches" -Description: "Tags can help with managing, identifying, organizing, searching for, and filtering resources. Additionally, tags can help with security and compliance. Tags can be propagated from an Auto Scaling group to the EC2 instances that it launches." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with propagate_tags_to_ec2_instance as ( - select + ListOfTables: + - aws_ec2_autoscaling_group + Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + WITH propagate_tags_to_ec2_instance AS ( + SELECT autoscaling_group_arn, - count(*) as count - from + COUNT(*) AS count + FROM aws_ec2_autoscaling_group, - jsonb_array_elements(tags_src) as t - where + jsonb_array_elements(tags_src) AS t + WHERE (t ->> 'PropagateAtLaunch' = 'false') - group by + GROUP BY autoscaling_group_arn ) - select - p.autoscaling_group_arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when count > 0 then 'alarm' - else 'ok' - end as status, - case - when count > 0 then title || ' does not propagate all tags to the EC2 instance' - else title || ' propagate all tags to the EC2 instance.' - end as reason - from - aws_ec2_autoscaling_group as p - left join propagate_tags_to_ec2_instance as i on i.autoscaling_group_arn = p.autoscaling_group_arn; - PrimaryTable: aws_ec2_autoscaling_group - ListOfTables: - - aws_ec2_autoscaling_group - Parameters: [] + SELECT + p.autoscaling_group_arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN count > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN count > 0 THEN title || ' does not propagate all tags to the EC2 instance' + ELSE title || ' propagate all tags to the EC2 instance.' + END AS reason + FROM + aws_ec2_autoscaling_group AS p + LEFT JOIN propagate_tags_to_ec2_instance AS i + ON i.autoscaling_group_arn = p.autoscaling_group_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure EC2 Auto Scaling Groups Propagate Tags to EC2 Instances that it launches \ No newline at end of file diff --git a/compliance/controls/aws/aws_autoscaling_group_uses_ec2_launch_template.yaml b/compliance/controls/aws/aws_autoscaling_group_uses_ec2_launch_template.yaml old mode 100755 new mode 100644 index 0ab52232e..c215394cf --- a/compliance/controls/aws/aws_autoscaling_group_uses_ec2_launch_template.yaml +++ b/compliance/controls/aws/aws_autoscaling_group_uses_ec2_launch_template.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether an AWS EC2 Auto Scaling group is created from an EC2 launch template. This control fails if an AWS EC2 Auto Scaling group is not created with a launch template or if a launch template is not specified in a mixed instances policy. ID: aws_autoscaling_group_uses_ec2_launch_template -Title: "EC2 Auto Scaling groups should use EC2 launch templates" -Description: "This control checks whether an AWS EC2 Auto Scaling group is created from an EC2 launch template. This control fails if an AWS EC2 Auto Scaling group is not created with a launch template or if a launch template is not specified in a mixed instances policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n autoscaling_group_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when launch_template_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when launch_template_id is not null then title || ' using an EC2 launch template.'\n else title || ' not using an EC2 launch template.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_autoscaling_group;\n" - PrimaryTable: aws_ec2_autoscaling_group ListOfTables: - aws_ec2_autoscaling_group Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + SELECT + autoscaling_group_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN launch_template_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN launch_template_id IS NOT NULL THEN title || ' using an EC2 launch template.' + ELSE title || ' not using an EC2 launch template.' + END AS reason, + region, + account_id + FROM + aws_ec2_autoscaling_group; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/AutoScaling -IntegrationType: - - aws_cloud_account +Title: EC2 Auto Scaling groups should use EC2 launch templates \ No newline at end of file diff --git a/compliance/controls/aws/aws_autoscaling_group_with_lb_use_health_check.yaml b/compliance/controls/aws/aws_autoscaling_group_with_lb_use_health_check.yaml old mode 100755 new mode 100644 index 5d525a5fb..e69a86e97 --- a/compliance/controls/aws/aws_autoscaling_group_with_lb_use_health_check.yaml +++ b/compliance/controls/aws/aws_autoscaling_group_with_lb_use_health_check.yaml @@ -1,13 +1,32 @@ +Description: The Elastic Load Balancer (ELB) health checks for AWS Elastic Compute Cloud (AWS EC2) Auto Scaling groups support maintenance of adequate capacity and availability. ID: aws_autoscaling_group_with_lb_use_health_check -Title: "Auto Scaling groups with a load balancer should use health checks" -Description: "The Elastic Load Balancer (ELB) health checks for AWS Elastic Compute Cloud (AWS EC2) Auto Scaling groups support maintenance of adequate capacity and availability." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n autoscaling_group_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when load_balancer_names is null and target_group_arns is null then 'alarm'\n when health_check_type != 'ELB' then 'alarm'\n else 'ok'\n end as status,\n case\n when load_balancer_names is null and target_group_arns is null then title || ' not associated with a load balancer.'\n when health_check_type != 'ELB' then title || ' does not use ELB health check.'\n else title || ' uses ELB health check.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_autoscaling_group;\n" - PrimaryTable: aws_ec2_autoscaling_group ListOfTables: - aws_ec2_autoscaling_group Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + SELECT + autoscaling_group_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN load_balancer_names IS NULL AND target_group_arns IS NULL THEN 'alarm' + WHEN health_check_type != 'ELB' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN load_balancer_names IS NULL AND target_group_arns IS NULL THEN title || ' not associated with a load balancer.' + WHEN health_check_type != 'ELB' THEN title || ' does not use ELB health check.' + ELSE title || ' uses ELB health check.' + END AS reason, + region, + account_id + FROM + aws_ec2_autoscaling_group; Severity: low Tags: category: @@ -24,12 +43,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -38,5 +57,4 @@ Tags: - aws service: - AWS/AutoScaling -IntegrationType: - - aws_cloud_account +Title: Auto Scaling groups with a load balancer should use health checks \ No newline at end of file diff --git a/compliance/controls/aws/aws_autoscaling_launch_config_hop_limit.yaml b/compliance/controls/aws/aws_autoscaling_launch_config_hop_limit.yaml old mode 100755 new mode 100644 index 54388bdfa..9297d58a0 --- a/compliance/controls/aws/aws_autoscaling_launch_config_hop_limit.yaml +++ b/compliance/controls/aws/aws_autoscaling_launch_config_hop_limit.yaml @@ -1,30 +1,31 @@ +Description: This control checks the number of network hops that a metadata token can travel. The control fails if the metadata response hop limit is greater than 1. ID: aws_autoscaling_launch_config_hop_limit -Title: "EC2 auto scaling group launch configurations should not have metadata response hop limit greater than 1" -Description: "This control checks the number of network hops that a metadata token can travel. The control fails if the metadata response hop limit is greater than 1." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - launch_configuration_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when metadata_options_put_response_hop_limit is null then 'ok' - when metadata_options_put_response_hop_limit > 1 then 'alarm' - else 'ok' - end as status, - case - --If you do not specify a value, the hop limit default is 1. - when metadata_options_put_response_hop_limit is null then title || ' metadata response hop limit set to default.' - else title || ' has a metadata response hop limit of ' || metadata_options_put_response_hop_limit || '.' - end as reason - , region, account_id - from - aws_ec2_launch_configuration; - PrimaryTable: aws_ec2_launch_configuration ListOfTables: - aws_ec2_launch_configuration Parameters: [] + PrimaryTable: aws_ec2_launch_configuration + QueryToExecute: | + SELECT + launch_configuration_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN metadata_options_put_response_hop_limit IS NULL THEN 'ok' + WHEN metadata_options_put_response_hop_limit > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN metadata_options_put_response_hop_limit IS NULL THEN title || ' metadata response hop limit set to default.' + ELSE title || ' has a metadata response hop limit of ' || metadata_options_put_response_hop_limit || '.' + END AS reason, + region, + account_id + FROM + aws_ec2_launch_configuration; Severity: high Tags: aws_foundational_security: @@ -39,5 +40,4 @@ Tags: - aws service: - AWS/AutoScaling -IntegrationType: - - aws_cloud_account +Title: EC2 auto scaling group launch configurations should not have metadata response hop limit greater than 1 \ No newline at end of file diff --git a/compliance/controls/aws/aws_autoscaling_launch_config_public_ip_disabled.yaml b/compliance/controls/aws/aws_autoscaling_launch_config_public_ip_disabled.yaml old mode 100755 new mode 100644 index 2244f1cc0..704f3c211 --- a/compliance/controls/aws/aws_autoscaling_launch_config_public_ip_disabled.yaml +++ b/compliance/controls/aws/aws_autoscaling_launch_config_public_ip_disabled.yaml @@ -1,28 +1,30 @@ +Description: Ensure that AWS EC2 Auto Scaling groups have public IP addresses enabled through Launch Configurations. This rule is non-compliant if the Launch Configuration for an Auto Scaling group has AssociatePublicIpAddress set to 'true'. ID: aws_autoscaling_launch_config_public_ip_disabled -Title: "Auto Scaling launch config public IP should be disabled" -Description: "Ensure that AWS EC2 Auto Scaling groups have public IP addresses enabled through Launch Configurations. This rule is non-compliant if the Launch Configuration for an Auto Scaling group has AssociatePublicIpAddress set to 'true'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - launch_configuration_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when associate_public_ip_address then 'alarm' - else 'ok' - end as status, - case - when associate_public_ip_address then title || ' public IP enabled.' - else title || ' public IP disabled.' - end as reason - , region, account_id - from - aws_ec2_launch_configuration; - PrimaryTable: aws_ec2_launch_configuration ListOfTables: - aws_ec2_launch_configuration Parameters: [] + PrimaryTable: aws_ec2_launch_configuration + QueryToExecute: | + SELECT + launch_configuration_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN associate_public_ip_address THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN associate_public_ip_address THEN title || ' public IP enabled.' + ELSE title || ' public IP disabled.' + END AS reason, + region, + account_id + FROM + aws_ec2_launch_configuration; Severity: high Tags: category: @@ -41,10 +43,10 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -55,5 +57,4 @@ Tags: - "true" service: - AWS/AutoScaling -IntegrationType: - - aws_cloud_account +Title: Auto Scaling launch config public IP should be disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_autoscaling_launch_config_requires_imdsv2.yaml b/compliance/controls/aws/aws_autoscaling_launch_config_requires_imdsv2.yaml old mode 100755 new mode 100644 index 8ecf8b34e..586410e9b --- a/compliance/controls/aws/aws_autoscaling_launch_config_requires_imdsv2.yaml +++ b/compliance/controls/aws/aws_autoscaling_launch_config_requires_imdsv2.yaml @@ -1,28 +1,30 @@ +Description: This control checks whether IMDSv2 is enabled on all instances launched by AWS EC2 Auto Scaling groups. The control fails if the Instance Metadata Service (IMDS) version is not included in the launch configuration or if both IMDSv1 and IMDSv2 are enabled. ID: aws_autoscaling_launch_config_requires_imdsv2 -Title: "Auto Scaling group should configure EC2 instances to require Instance Metadata Service Version 2 (IMDSv2)" -Description: "This control checks whether IMDSv2 is enabled on all instances launched by AWS EC2 Auto Scaling groups. The control fails if the Instance Metadata Service (IMDS) version is not included in the launch configuration or if both IMDSv1 and IMDSv2 are enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - launch_configuration_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when metadata_options_http_tokens = 'required' then 'ok' - else 'alarm' - end as status, - case - when metadata_options_http_tokens = 'required' then title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' - else title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' - end as reason - , region, account_id - from - aws_ec2_launch_configuration; - PrimaryTable: aws_ec2_launch_configuration ListOfTables: - aws_ec2_launch_configuration Parameters: [] + PrimaryTable: aws_ec2_launch_configuration + QueryToExecute: | + SELECT + launch_configuration_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN metadata_options_http_tokens = 'required' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN metadata_options_http_tokens = 'required' THEN title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' + ELSE title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' + END AS reason, + region, + account_id + FROM + aws_ec2_launch_configuration; Severity: high Tags: aws_foundational_security: @@ -37,5 +39,4 @@ Tags: - aws service: - AWS/AutoScaling -IntegrationType: - - aws_cloud_account +Title: Auto Scaling group should configure EC2 instances to require Instance Metadata Service Version 2 (IMDSv2) \ No newline at end of file diff --git a/compliance/controls/aws/aws_autoscaling_use_multiple_instance_types_in_multiple_az.yaml b/compliance/controls/aws/aws_autoscaling_use_multiple_instance_types_in_multiple_az.yaml old mode 100755 new mode 100644 index 6c6b35c34..0ab3e33fa --- a/compliance/controls/aws/aws_autoscaling_use_multiple_instance_types_in_multiple_az.yaml +++ b/compliance/controls/aws/aws_autoscaling_use_multiple_instance_types_in_multiple_az.yaml @@ -1,13 +1,57 @@ +Description: This control checks whether an AWS EC2 Auto Scaling group uses multiple instance types. The control fails if the Auto Scaling group has only one instance type defined. ID: aws_autoscaling_use_multiple_instance_types_in_multiple_az -Title: "EC2 auto scaling groups should use multiple instance types in multiple availability zones" -Description: "This control checks whether an AWS EC2 Auto Scaling group uses multiple instance types. The control fails if the Auto Scaling group has only one instance type defined." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with autoscaling_groups as (\n select\n autoscaling_group_arn,\n title,\n mixed_instances_policy_launch_template_overrides,\n region,\n tags,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n _ctx,\n account_id\nfrom\n aws_ec2_autoscaling_group\n),\ndistinct_instance_types_count as (\n select\n autoscaling_group_arn,\n count(distinct(e -> 'InstanceType')) as distinct_instance_types\nfrom\n autoscaling_groups,\n jsonb_array_elements(mixed_instances_policy_launch_template_overrides) as e\ngroup by\n autoscaling_group_arn,\n title,\n mixed_instances_policy_launch_template_overrides\n)\nselect\n a.autoscaling_group_arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.distinct_instance_types > 1 then 'ok'\n else 'alarm'\n end as status,\n case\n when b.distinct_instance_types > 1 then title || ' uses ' || b.distinct_instance_types || ' instance types.'\n else title || ' does not use multiple instance types.'\n end as reason\n \n , a.region, a.account_id\nfrom\n autoscaling_groups as a\n left join distinct_instance_types_count as b on a.autoscaling_group_arn = b.autoscaling_group_arn;\n" - PrimaryTable: aws_ec2_autoscaling_group ListOfTables: - aws_ec2_autoscaling_group Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + WITH autoscaling_groups AS ( + SELECT + autoscaling_group_arn, + title, + mixed_instances_policy_launch_template_overrides, + region, + tags, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + _ctx, + account_id + FROM + aws_ec2_autoscaling_group + ), + distinct_instance_types_count AS ( + SELECT + autoscaling_group_arn, + COUNT(DISTINCT(e -> 'InstanceType')) AS distinct_instance_types + FROM + autoscaling_groups, + jsonb_array_elements(mixed_instances_policy_launch_template_overrides) AS e + GROUP BY + autoscaling_group_arn, + title, + mixed_instances_policy_launch_template_overrides + ) + SELECT + a.autoscaling_group_arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.distinct_instance_types > 1 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.distinct_instance_types > 1 THEN title || ' uses ' || b.distinct_instance_types || ' instance types.' + ELSE title || ' does not use multiple instance types.' + END AS reason, + a.region, + a.account_id + FROM + autoscaling_groups AS a + LEFT JOIN distinct_instance_types_count AS b ON a.autoscaling_group_arn = b.autoscaling_group_arn; Severity: medium Tags: aws_foundational_security: @@ -22,5 +66,4 @@ Tags: - aws service: - AWS/AutoScaling -IntegrationType: - - aws_cloud_account +Title: EC2 auto scaling groups should use multiple instance types in multiple availability zones \ No newline at end of file diff --git a/compliance/controls/aws/aws_backup_plan_min_retention_35_days.yaml b/compliance/controls/aws/aws_backup_plan_min_retention_35_days.yaml old mode 100755 new mode 100644 index 44fdfb578..8f006af93 --- a/compliance/controls/aws/aws_backup_plan_min_retention_35_days.yaml +++ b/compliance/controls/aws/aws_backup_plan_min_retention_35_days.yaml @@ -1,48 +1,47 @@ +Description: Checks if a backup plan has a backup rule that satisfies the required frequency and retention period(35 Days). The rule is non-compliant if recovery points are not created at least as often as the specified frequency or expire before the specified period. ID: aws_backup_plan_min_retention_35_days -Title: "Backup plan min frequency and min retention check" -Description: "Checks if a backup plan has a backup rule that satisfies the required frequency and retention period(35 Days). The rule is non-compliant if recovery points are not created at least as often as the specified frequency or expire before the specified period." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_backup_plan + Parameters: [] + PrimaryTable: aws_backup_plan QueryToExecute: | - with all_plans as ( - select + WITH all_plans AS ( + SELECT arn, - r as Rules, + r AS rules, title, region, account_id, - og_account_id as og_account_id, - og_resource_id as og_resource_id, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, _ctx - from + FROM aws_backup_plan, - jsonb_array_elements(backup_plan -> 'Rules') as r + jsonb_array_elements(backup_plan -> 'Rules') AS r ) - select - -- The resource ARN can be duplicate as we are checking all the associated rules to the backup-plan - -- Backup plans are composed of one or more backup rules. - -- https://docs.aws.amazon.com/aws-backup/latest/devguide/creating-a-backup-plan.html - r.arn as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - when r.Rules is null then 'alarm' - when r.Rules ->> 'Lifecycle' is null then 'ok' - when (r.Rules -> 'Lifecycle' ->> 'DeleteAfterDays')::int >= 35 then 'ok' - else 'alarm' - end as status, - case - when r.Rules is null then r.title || ' retention period not set.' - when r.Rules ->> 'Lifecycle' is null then (r.Rules ->> 'RuleName') || ' retention period set to never expire.' - else (r.Rules ->> 'RuleName') || ' retention period set to ' || (r.Rules -> 'Lifecycle' ->> 'DeleteAfterDays') || ' days.' - end as reason - , region, account_id - from - all_plans as r; - PrimaryTable: aws_backup_plan - ListOfTables: - - aws_backup_plan - Parameters: [] + SELECT + r.arn AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN r.rules IS NULL THEN 'alarm' + WHEN r.rules ->> 'Lifecycle' IS NULL THEN 'ok' + WHEN (r.rules -> 'Lifecycle' ->> 'DeleteAfterDays')::int >= 35 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.rules IS NULL THEN r.title || ' retention period not set.' + WHEN r.rules ->> 'Lifecycle' IS NULL THEN (r.rules ->> 'RuleName') || ' retention period set to never expire.' + ELSE (r.rules ->> 'RuleName') || ' retention period set to ' || (r.rules -> 'Lifecycle' ->> 'DeleteAfterDays') || ' days.' + END AS reason, + region, + account_id + FROM + all_plans AS r; Severity: medium Tags: category: @@ -75,5 +74,4 @@ Tags: - AWS/Backup soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Backup plan min frequency and min retention check \ No newline at end of file diff --git a/compliance/controls/aws/aws_backup_plan_region_configured.yaml b/compliance/controls/aws/aws_backup_plan_region_configured.yaml old mode 100755 new mode 100644 index f22a9d28c..b13ca93a0 --- a/compliance/controls/aws/aws_backup_plan_region_configured.yaml +++ b/compliance/controls/aws/aws_backup_plan_region_configured.yaml @@ -1,41 +1,43 @@ +Description: Ensure that there exists at least one backup plan in a region. The rule is non-compliant if there are no backup plans in a region. ID: aws_backup_plan_region_configured -Title: "Backup plan should exist in a region" -Description: "Ensure that there exists at least one backup plan in a region. The rule is non-compliant if there are no backup plans in a region." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with count_plans as ( - select + ListOfTables: + - aws_backup_plan + - aws_region + Parameters: [] + PrimaryTable: aws_backup_plan + QueryToExecute: | + WITH count_plans AS ( + SELECT region, account_id, - count(*) as count - from + COUNT(*) AS count + FROM aws_backup_plan - group by + GROUP BY region, account_id ) - select - 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - when cp.count > 0 then 'ok' - else 'alarm' - end as status, - case - when cp.count > 0 then cp.count || ' backup plan(s) exist in region ' || r.region || '.' - else 'No backup plans exist in region ' || r.region || '.' - end as reason - from - aws_region as r - left join count_plans as cp on r.account_id = cp.account_id and r.region = cp.region; - PrimaryTable: aws_backup_plan - ListOfTables: - - aws_backup_plan - - aws_region - Parameters: [] + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN cp.count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cp.count > 0 THEN cp.count || ' backup plan(s) exist in region ' || r.region || '.' + ELSE 'No backup plans exist in region ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN count_plans AS cp + ON r.account_id = cp.account_id + AND r.region = cp.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Backup plan should exist in a region \ No newline at end of file diff --git a/compliance/controls/aws/aws_backup_recovery_point_encryption_enabled.yaml b/compliance/controls/aws/aws_backup_recovery_point_encryption_enabled.yaml old mode 100755 new mode 100644 index 2f1abcf89..90aa6d2ed --- a/compliance/controls/aws/aws_backup_recovery_point_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_backup_recovery_point_encryption_enabled.yaml @@ -1,28 +1,30 @@ +Description: Ensure that a recovery point is encrypted. The rule is non-compliant if the recovery point is not encrypted. ID: aws_backup_recovery_point_encryption_enabled -Title: "Backup recovery points should be encrypted" -Description: "Ensure that a recovery point is encrypted. The rule is non-compliant if the recovery point is not encrypted." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - recovery_point_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when is_encrypted then 'ok' - else 'alarm' - end as status, - case - when is_encrypted then recovery_point_arn || ' encryption enabled.' - else recovery_point_arn || ' encryption disabled.' - end as reason - , region, account_id - from - aws_backup_recovery_point; - PrimaryTable: aws_backup_recovery_point ListOfTables: - aws_backup_recovery_point Parameters: [] + PrimaryTable: aws_backup_recovery_point + QueryToExecute: | + SELECT + recovery_point_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN is_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN is_encrypted THEN recovery_point_arn || ' encryption enabled.' + ELSE recovery_point_arn || ' encryption disabled.' + END AS reason, + region, + account_id + FROM + aws_backup_recovery_point; Severity: high Tags: category: @@ -51,5 +53,4 @@ Tags: - AWS/Backup soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Backup recovery points should be encrypted \ No newline at end of file diff --git a/compliance/controls/aws/aws_backup_recovery_point_manual_deletion_disabled.yaml b/compliance/controls/aws/aws_backup_recovery_point_manual_deletion_disabled.yaml old mode 100755 new mode 100644 index 7e65277ae..85045fcae --- a/compliance/controls/aws/aws_backup_recovery_point_manual_deletion_disabled.yaml +++ b/compliance/controls/aws/aws_backup_recovery_point_manual_deletion_disabled.yaml @@ -1,42 +1,45 @@ +Description: Checks if a backup vault has an attached resource-based policy which prevents deletion of recovery points. The rule is non-compliant if the Backup Vault does not have resource-based policies or has policies without a suitable 'Deny' statement. ID: aws_backup_recovery_point_manual_deletion_disabled -Title: "Backup recovery points manual deletion should be disabled" -Description: "Checks if a backup vault has an attached resource-based policy which prevents deletion of recovery points. The rule is non-compliant if the Backup Vault does not have resource-based policies or has policies without a suitable 'Deny' statement." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_backup_vault + Parameters: [] + PrimaryTable: aws_backup_vault QueryToExecute: | - with recovery_point_manual_deletion_disabled as ( - select + WITH recovery_point_manual_deletion_disabled AS ( + SELECT arn - from + FROM aws_backup_vault, - jsonb_array_elements(policy -> 'Statement') as s - where - s ->> 'Effect' = 'Deny' and - s -> 'Action' @> '["backup:DeleteRecoveryPoint","backup:UpdateRecoveryPointLifecycle","backup:PutBackupVaultAccessPolicy"]' - and s ->> 'Resource' = '*' - group by + jsonb_array_elements(policy -> 'Statement') AS s + WHERE + s ->> 'Effect' = 'Deny' + AND s -> 'Action' @> '["backup:DeleteRecoveryPoint", "backup:UpdateRecoveryPointLifecycle", "backup:PutBackupVaultAccessPolicy"]' + AND s ->> 'Resource' = '*' + GROUP BY arn ) - select - v.arn as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when d.arn is not null then 'ok' - else 'alarm' - end as status, - case - when d.arn is not null then v.title || ' recovery point manual deletion disabled.' - else v.title || ' recovery point manual deletion not disabled.' - end as reason - , v.region, v.account_id - from - aws_backup_vault as v - left join recovery_point_manual_deletion_disabled as d on v.arn = d.arn; - PrimaryTable: aws_backup_vault - ListOfTables: - - aws_backup_vault - Parameters: [] + SELECT + v.arn AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN d.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.arn IS NOT NULL THEN v.title || ' recovery point manual deletion disabled.' + ELSE v.title || ' recovery point manual deletion not disabled.' + END AS reason, + v.region, + v.account_id + FROM + aws_backup_vault AS v + LEFT JOIN recovery_point_manual_deletion_disabled AS d + ON v.arn = d.arn; Severity: high Tags: category: @@ -65,5 +68,4 @@ Tags: - AWS/Backup soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Backup recovery points manual deletion should be disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_backup_recovery_point_min_retention_35_days.yaml b/compliance/controls/aws/aws_backup_recovery_point_min_retention_35_days.yaml old mode 100755 new mode 100644 index edfb7d520..76b512afd --- a/compliance/controls/aws/aws_backup_recovery_point_min_retention_35_days.yaml +++ b/compliance/controls/aws/aws_backup_recovery_point_min_retention_35_days.yaml @@ -1,29 +1,32 @@ +Description: Ensure a recovery point expires no earlier than after the specified period. The rule is non-compliant if the recovery point has a retention point less than 35 days. ID: aws_backup_recovery_point_min_retention_35_days -Title: "Backup recovery points should not expire before retention period" -Description: "Ensure a recovery point expires no earlier than after the specified period. The rule is non-compliant if the recovery point has a retention point less than 35 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - recovery_point_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when (lifecycle -> 'DeleteAfterDays') is null then 'ok' - when (lifecycle -> 'DeleteAfterDays')::int >= 35 then 'ok' - else 'alarm' - end as status, - case - when (lifecycle -> 'DeleteAfterDays') is null then split_part(recovery_point_arn, ':', -1) || ' retention period set to never expire.' - else split_part(recovery_point_arn, ':', -1) || ' recovery point has a retention period of ' || (lifecycle -> 'DeleteAfterDays')::int || ' days.' - end as reason - , region, account_id - from - aws_backup_recovery_point; - PrimaryTable: aws_backup_recovery_point ListOfTables: - aws_backup_recovery_point Parameters: [] + PrimaryTable: aws_backup_recovery_point + QueryToExecute: | + SELECT + recovery_point_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (lifecycle -> 'DeleteAfterDays') IS NULL THEN 'ok' + WHEN (lifecycle -> 'DeleteAfterDays')::int >= 35 THEN 'ok' + ELSE 'alarm' + END as status, + CASE + WHEN (lifecycle -> 'DeleteAfterDays') IS NULL + THEN split_part(recovery_point_arn, ':', -1) || ' retention period set to never expire.' + ELSE split_part(recovery_point_arn, ':', -1) || ' recovery point has a retention period of ' || (lifecycle -> 'DeleteAfterDays')::int || ' days.' + END AS reason, + region, + account_id + FROM + aws_backup_recovery_point; Severity: medium Tags: category: @@ -52,5 +55,4 @@ Tags: - AWS/Backup soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Backup recovery points should not expire before retention period \ No newline at end of file diff --git a/compliance/controls/aws/aws_backup_vault_region_configured.yaml b/compliance/controls/aws/aws_backup_vault_region_configured.yaml old mode 100755 new mode 100644 index 73bc37f55..c44f98abf --- a/compliance/controls/aws/aws_backup_vault_region_configured.yaml +++ b/compliance/controls/aws/aws_backup_vault_region_configured.yaml @@ -1,41 +1,41 @@ +Description: Ensure that there exists at least one backup vault in a region. The rule is non-compliant if there are no backup vaults in a region. ID: aws_backup_vault_region_configured -Title: "Backup vaults should exist in a region" -Description: "Ensure that there exists at least one backup vault in a region. The rule is non-compliant if there are no backup vaults in a region." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with count_vaults as ( - select + ListOfTables: + - aws_backup_vault + - aws_region + Parameters: [] + PrimaryTable: aws_backup_vault + QueryToExecute: | + WITH count_vaults AS ( + SELECT region, account_id, - count(*) as count - from + COUNT(*) AS count + FROM aws_backup_vault - group by + GROUP BY region, account_id ) - select - 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - when v.count > 0 then 'ok' - else 'alarm' - end as status, - case - when v.count > 0 then v.count || ' backup vault(s) exist in region ' || r.region || '.' - else 'No backup vault exists in region ' || r.region || '.' - end as reason - from - aws_region as r - left join count_vaults as v on r.account_id = v.account_id and r.region = v.region; - PrimaryTable: aws_backup_vault - ListOfTables: - - aws_backup_vault - - aws_region - Parameters: [] + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN v.count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.count > 0 THEN v.count || ' backup vault(s) exist in region ' || r.region || '.' + ELSE 'No backup vault exists in region ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN count_vaults AS v ON r.account_id = v.account_id AND r.region = v.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Backup vaults should exist in a region \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_10_1.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_10_1.yaml old mode 100755 new mode 100644 index 7b7d71328..769fd5a31 --- a/compliance/controls/aws/aws_cis_compute_service_v100_10_1.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_10_1.yaml @@ -1,14 +1,22 @@ +Description: App Runner needs access to your application source, so it can't be encrypted. Therefore, be sure to secure the connection between your development or deployment environment and App Runner. ID: aws_cis_compute_service_v100_10_1 -Title: "10.1 Ensure you are using VPC Endpoints for source code access" -Description: "App Runner needs access to your application source, so it can't be encrypted. Therefore, be sure to secure the connection between your development or deployment environment and App Runner." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 10.1 Ensure you are using VPC Endpoints for source code access \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_11_1.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_11_1.yaml old mode 100755 new mode 100644 index 3614332aa..30d7a23c9 --- a/compliance/controls/aws/aws_cis_compute_service_v100_11_1.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_11_1.yaml @@ -1,14 +1,22 @@ +Description: SimSpace Weaver doesn't manage communications between your apps and the clients. ID: aws_cis_compute_service_v100_11_1 -Title: "11.1 Ensure communications between your applications and clients is encrypted" -Description: "SimSpace Weaver doesn't manage communications between your apps and the clients." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 11.1 Ensure communications between your applications and clients is encrypted \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_10.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_10.yaml old mode 100755 new mode 100644 index d0e1fdcfa..8ab60cd41 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_10.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_10.yaml @@ -1,28 +1,28 @@ +Description: Identify and delete any unused Amazon AWS Elastic Network Interfaces in order to adhere to best practices and to avoid reaching the service limit. An AWS Elastic Network Interface (ENI) is pronounced unused when is not attached anymore to an EC2 instance. ID: aws_cis_compute_service_v100_2_10 -Title: "2.10 Ensure unused ENIs are removed" -Description: "Identify and delete any unused Amazon AWS Elastic Network Interfaces in order to adhere to best practices and to avoid reaching the service limit. An AWS Elastic Network Interface (ENI) is pronounced unused when is not attached anymore to an EC2 instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - network_interface_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when status = 'available' and attached_instance_id is null then 'alarm' - else 'ok' - end as status, - case - when status = 'available' and attached_instance_id is null then title || ' not in use.' - else title || ' in use.' - end as reason - from - aws_ec2_network_interface; - PrimaryTable: aws_ec2_network_interface ListOfTables: - aws_ec2_network_interface Parameters: [] + PrimaryTable: aws_ec2_network_interface + QueryToExecute: | + SELECT + network_interface_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN status = 'available' AND attached_instance_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status = 'available' AND attached_instance_id IS NULL THEN title || ' not in use.' + ELSE title || ' in use.' + END AS reason + FROM + aws_ec2_network_interface; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.10 Ensure unused ENIs are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_11.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_11.yaml old mode 100755 new mode 100644 index 41c93d1d2..eb6c5c076 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_11.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_11.yaml @@ -1,14 +1,29 @@ +Description: Enable this rule to help with the baseline configuration of Amazon Elastic Compute Cloud (Amazon EC2) instances by checking whether Amazon EC2 instances have been stopped for more than the allowed number of days, according to your organization's standards. ID: aws_cis_compute_service_v100_2_11 -Title: "2.11 Ensure instances stopped for over 90 days are removed" -Description: "Enable this rule to help with the baseline configuration of Amazon Elastic Compute Cloud (Amazon EC2) instances by checking whether Amazon EC2 instances have been stopped for more than the allowed number of days, according to your organization's standards." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when instance_state not in ('stopped', 'stopping') then 'skip'\n when state_transition_time <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end as status,\n case\n when instance_state not in ('stopped', 'stopping') then title || ' is in ' || instance_state || ' state.'\n else title || ' stopped since ' || to_char(state_transition_time , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - state_transition_time) || ' days).'\n end as reason\n \n \nfrom\n aws_ec2_instance;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN instance_state NOT IN ('stopped', 'stopping') THEN 'skip' + WHEN state_transition_time <= (current_date - INTERVAL '90' day) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN instance_state NOT IN ('stopped', 'stopping') THEN title || ' is in ' || instance_state || ' state.' + ELSE title || ' stopped since ' || TO_CHAR(state_transition_time, 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM current_timestamp - state_transition_time) || ' days).' + END AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.11 Ensure instances stopped for over 90 days are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_12.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_12.yaml old mode 100755 new mode 100644 index e8dfaea29..bac2ce277 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_12.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_12.yaml @@ -1,41 +1,42 @@ +Description: This rule ensures that Amazon Elastic Block Store volumes that are attached to Amazon Elastic Compute Cloud (Amazon EC2) instances are marked for deletion when an instance is terminated. If an Amazon EBS volume isn't deleted when the instance that it's attached to is terminated, it may violate the concept of least functionality. ID: aws_cis_compute_service_v100_2_12 -Title: "2.12 Ensure EBS volumes attached to an EC2 instance is marked for deletion upon instance termination" -Description: "This rule ensures that Amazon Elastic Block Store volumes that are attached to Amazon Elastic Compute Cloud (Amazon EC2) instances are marked for deletion when an instance is terminated. If an Amazon EBS volume isn't deleted when the instance that it's attached to is terminated, it may violate the concept of least functionality." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ebs_volume_with_delete_on_termination_enabled as ( - select - count(*) as count, + ListOfTables: + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH ebs_volume_with_delete_on_termination_enabled AS ( + SELECT + COUNT(*) AS count, arn - from + FROM aws_ec2_instance, - jsonb_array_elements(block_device_mappings) as p - where + jsonb_array_elements(block_device_mappings) AS p + WHERE p -> 'Ebs' ->> 'DeleteOnTermination' = 'false' - group by + GROUP BY arn ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when e.count > 0 then 'alarm' - else 'ok' - end as status, - case - when e.count > 0 then ' EBS volume(s) attached to ' || title || ' has delete on termination disabled.' - else ' EBS volume(s) attached to ' || title || ' has delete on termination enabled.' - end as reason - from - aws_ec2_instance as i - left join ebs_volume_with_delete_on_termination_enabled as e on e.arn = i.arn; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - Parameters: [] + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN e.count > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN e.count > 0 THEN 'EBS volume(s) attached to ' || title || ' has delete on termination disabled.' + ELSE 'EBS volume(s) attached to ' || title || ' has delete on termination enabled.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN ebs_volume_with_delete_on_termination_enabled AS e + ON e.arn = i.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.12 Ensure EBS volumes attached to an EC2 instance is marked for deletion upon instance termination \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_13.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_13.yaml old mode 100755 new mode 100644 index e0ae2a094..859cb454c --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_13.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_13.yaml @@ -1,14 +1,32 @@ +Description: User Data can be specified when launching an ec2 instance. Examples include specifying parameters for configuring the instance or including a simple script. ID: aws_cis_compute_service_v100_2_13 -Title: "2.13 Ensure Secrets and Sensitive Data are not stored directly in EC2 User Data" -Description: "User Data can be specified when launching an ec2 instance. Examples include specifying parameters for configuring the instance or including a simple script." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when user_data like any (array ['%pass%', '%secret%','%token%','%key%'])\n or user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]' then 'alarm'\n else 'ok'\n end as status,\n case\n when user_data like any (array ['%pass%', '%secret%','%token%','%key%'])\n or user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]' then instance_id ||' potential secret found in user data.'\n else instance_id || ' no secrets found in user data.'\n end as reason\n \n \nfrom\n aws_ec2_instance;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_data LIKE ANY (ARRAY ['%pass%', '%secret%', '%token%', '%key%']) + OR user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN user_data LIKE ANY (ARRAY ['%pass%', '%secret%', '%token%', '%key%']) + OR user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' + THEN instance_id || ' potential secret found in user data.' + ELSE instance_id || ' no secrets found in user data.' + END AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.13 Ensure Secrets and Sensitive Data are not stored directly in EC2 User Data \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_14.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_14.yaml old mode 100755 new mode 100644 index e3a37b40a..e37c3aaed --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_14.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_14.yaml @@ -1,41 +1,42 @@ +Description: Tags can help with managing, identifying, organizing, searching for, and filtering resources. Additionally, tags can help with security and compliance. Tags can be propagated from an Auto Scaling group to the EC2 instances that it launches. ID: aws_cis_compute_service_v100_2_14 -Title: "2.14 Ensure EC2 Auto Scaling Groups Propagate Tags to EC2 Instances that it launches" -Description: "Tags can help with managing, identifying, organizing, searching for, and filtering resources. Additionally, tags can help with security and compliance. Tags can be propagated from an Auto Scaling group to the EC2 instances that it launches." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with propagate_tags_to_ec2_instance as ( - select + ListOfTables: + - aws_ec2_autoscaling_group + Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + WITH propagate_tags_to_ec2_instance AS ( + SELECT autoscaling_group_arn, - count(*) as count - from + COUNT(*) AS count + FROM aws_ec2_autoscaling_group, - jsonb_array_elements(tags_src) as t - where - (t ->> 'PropagateAtLaunch' = 'false') - group by + jsonb_array_elements(tags_src) AS t + WHERE + t ->> 'PropagateAtLaunch' = 'false' + GROUP BY autoscaling_group_arn ) - select - p.autoscaling_group_arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when count > 0 then 'alarm' - else 'ok' - end as status, - case - when count > 0 then title || ' does not propagate all tags to the EC2 instance' - else title || ' propagate all tags to the EC2 instance.' - end as reason - from - aws_ec2_autoscaling_group as p - left join propagate_tags_to_ec2_instance as i on i.autoscaling_group_arn = p.autoscaling_group_arn; - PrimaryTable: aws_ec2_autoscaling_group - ListOfTables: - - aws_ec2_autoscaling_group - Parameters: [] + SELECT + p.autoscaling_group_arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN count > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN count > 0 THEN title || ' does not propagate all tags to the EC2 instance' + ELSE title || ' propagate all tags to the EC2 instance.' + END AS reason + FROM + aws_ec2_autoscaling_group AS p + LEFT JOIN propagate_tags_to_ec2_instance AS i + ON i.autoscaling_group_arn = p.autoscaling_group_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.14 Ensure EC2 Auto Scaling Groups Propagate Tags to EC2 Instances that it launches \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_1_1.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_1_1.yaml old mode 100755 new mode 100644 index 8d909ef70..c53bfe6f8 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_1_1.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_1_1.yaml @@ -1,14 +1,22 @@ +Description: The naming convention for AMI (Amazon Machine Images) should be documented and followed for any AMI's created. ID: aws_cis_compute_service_v100_2_1_1 -Title: "2.1.1 Ensure Consistent Naming Convention is used for Organizational AMI" -Description: "The naming convention for AMI (Amazon Machine Images) should be documented and followed for any AMI's created." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.1 Ensure Consistent Naming Convention is used for Organizational AMI \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_1_2.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_1_2.yaml old mode 100755 new mode 100644 index 34c9d099a..e3762709f --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_1_2.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_1_2.yaml @@ -1,46 +1,46 @@ +Description: Amazon Machine Images should utilize EBS Encrypted snapshots ID: aws_cis_compute_service_v100_2_1_2 -Title: "2.1.2 Ensure Images (AMI's) are encrypted" -Description: "Amazon Machine Images should utilize EBS Encrypted snapshots" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with encryption_status as ( - select - image_id as resource, + ListOfTables: + - aws_ec2_ami + Parameters: [] + PrimaryTable: aws_ec2_ami + QueryToExecute: | + WITH encryption_status AS ( + SELECT + image_id AS resource, region, account_id, tags, _ctx, - bool_and(coalesce((mapping -> 'Ebs' ->> 'Encrypted')::text = 'true', false)) as all_encrypted - from + BOOL_AND(COALESCE((mapping -> 'Ebs' ->> 'Encrypted')::text = 'true', FALSE)) AS all_encrypted + FROM aws_ec2_ami - cross join jsonb_array_elements(block_device_mappings) as mapping - group by + CROSS JOIN jsonb_array_elements(block_device_mappings) AS mapping + GROUP BY image_id, region, account_id, tags, _ctx ) - select + SELECT resource, - image_id as og_account_id, - image_id as og_resource_id, - case - when all_encrypted then 'ok' - else 'alarm' - end as status, - case - when all_encrypted then resource || ' all EBS volumes are encrypted.' - else resource || ' all EBS volumes are not encrypted.' - end as reason - from + image_id AS og_account_id, + image_id AS og_resource_id, + CASE + WHEN all_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN all_encrypted THEN resource || ' all EBS volumes are encrypted.' + ELSE resource || ' all EBS volumes are not encrypted.' + END AS reason + FROM encryption_status; - PrimaryTable: aws_ec2_ami - ListOfTables: - - aws_ec2_ami - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.2 Ensure Images (AMI's) are encrypted \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_1_3.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_1_3.yaml old mode 100755 new mode 100644 index 7df031878..c2bde5e07 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_1_3.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_1_3.yaml @@ -1,14 +1,22 @@ +Description: Ensure that all base AMIs utilized are approved for use by your organization. ID: aws_cis_compute_service_v100_2_1_3 -Title: "2.1.3 Ensure Only Approved AMIs (Images) are Used" -Description: "Ensure that all base AMIs utilized are approved for use by your organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.3 Ensure Only Approved AMIs (Images) are Used \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_1_4.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_1_4.yaml old mode 100755 new mode 100644 index eaeff9f3d..221eaa83d --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_1_4.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_1_4.yaml @@ -1,14 +1,26 @@ +Description: Ensure that your AMIs are not older than 90 days. ID: aws_cis_compute_service_v100_2_1_4 -Title: "2.1.4 Ensure Images (AMI) are not older than 90 days" -Description: "Ensure that your AMIs are not older than 90 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n image_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when creation_date >= (current_date - interval '90 days') then 'ok'\n else 'alarm'\n end as status,\n title || ' created ' || to_char(creation_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - creation_date) || ' days).' as reason\n \n \nfrom\n aws_ec2_ami;" - PrimaryTable: aws_ec2_ami ListOfTables: - aws_ec2_ami Parameters: [] + PrimaryTable: aws_ec2_ami + QueryToExecute: | + SELECT + image_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN creation_date >= (CURRENT_DATE - INTERVAL '90 days') THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' created ' || TO_CHAR(creation_date, 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - creation_date) || ' days).' AS reason + FROM + aws_ec2_ami; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.4 Ensure Images (AMI) are not older than 90 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_1_5.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_1_5.yaml old mode 100755 new mode 100644 index 3cd019df7..e7f02d121 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_1_5.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_1_5.yaml @@ -1,14 +1,28 @@ +Description: EC2 allows you to make an AMI public, sharing it with all AWS accounts. ID: aws_cis_compute_service_v100_2_1_5 -Title: "2.1.5 Ensure Images are not Publicly Available" -Description: "EC2 allows you to make an AMI public, sharing it with all AWS accounts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':image/' || image_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when public then 'alarm'\n else 'ok'\n end status,\n case\n when public then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end reason\n \n \nfrom\n aws_ec2_ami;" - PrimaryTable: aws_ec2_ami ListOfTables: - aws_ec2_ami Parameters: [] + PrimaryTable: aws_ec2_ami + QueryToExecute: | + SELECT + 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':image/' || image_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN public THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_ec2_ami; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.5 Ensure Images are not Publicly Available \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_2_1.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_2_1.yaml old mode 100755 new mode 100644 index f3176aa62..2fb0946b9 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_2_1.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_2_1.yaml @@ -1,28 +1,28 @@ +Description: Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported. ID: aws_cis_compute_service_v100_2_2_1 -Title: "2.2.1 Ensure EBS volume encryption is enabled" -Description: "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when encrypted then 'ok' - else 'alarm' - end as status, - case - when encrypted then volume_id || ' encrypted.' - else volume_id || ' not encrypted.' - end as reason - from - aws_ebs_volume; - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN volume_id || ' encrypted.' + ELSE volume_id || ' not encrypted.' + END AS reason + FROM + aws_ebs_volume; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.2.1 Ensure EBS volume encryption is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_2_2.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_2_2.yaml old mode 100755 new mode 100644 index 0be2263ee..d4b4a6acb --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_2_2.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_2_2.yaml @@ -1,14 +1,28 @@ +Description: To protect your data disable the public mode of EBS snapshots. ID: aws_cis_compute_service_v100_2_2_2 -Title: "2.2.2 Ensure public access to EBS Snapshots is disabled" -Description: "To protect your data disable the public mode of EBS snapshots." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':snapshot/' || snapshot_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when create_volume_permissions @> '[{\"Group\": \"all\", \"UserId\": null}]' then 'alarm'\n else 'ok'\n end as status,\n case\n when create_volume_permissions @> '[{\"Group\": \"all\", \"UserId\": null}]' then title || ' is publicly restorable.'\n else title || ' is not publicly restorable.'\n end as reason\n \n \nfrom\n aws_ebs_snapshot;" - PrimaryTable: aws_ebs_snapshot ListOfTables: - aws_ebs_snapshot Parameters: [] + PrimaryTable: aws_ebs_snapshot + QueryToExecute: | + SELECT + 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':snapshot/' || snapshot_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_volume_permissions @> '[{"Group": "all", "UserId": null}]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN create_volume_permissions @> '[{"Group": "all", "UserId": null}]' THEN title || ' is publicly restorable.' + ELSE title || ' is not publicly restorable.' + END AS reason + FROM + aws_ebs_snapshot; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.2.2 Ensure public access to EBS Snapshots is disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_2_3.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_2_3.yaml old mode 100755 new mode 100644 index c9806e843..1960abbe3 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_2_3.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_2_3.yaml @@ -1,14 +1,28 @@ +Description: Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. ID: aws_cis_compute_service_v100_2_2_3 -Title: "2.2.3 Ensure EBS volume snapshots are encrypted" -Description: "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then title || ' encryption enabled.'\n else title || ' encryption disabled.'\n end as reason\n \n \nfrom\n aws_ebs_snapshot;" - PrimaryTable: aws_ebs_snapshot ListOfTables: - aws_ebs_snapshot Parameters: [] + PrimaryTable: aws_ebs_snapshot + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN title || ' encryption enabled.' + ELSE title || ' encryption disabled.' + END AS reason + FROM + aws_ebs_snapshot; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.2.3 Ensure EBS volume snapshots are encrypted \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_2_4.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_2_4.yaml old mode 100755 new mode 100644 index 132ebab12..d41832a83 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_2_4.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_2_4.yaml @@ -1,28 +1,28 @@ +Description: Identify any unused Elastic Block Store (EBS) volumes in your AWS account and remove them. ID: aws_cis_compute_service_v100_2_2_4 -Title: "2.2.4 Ensure unused EBS volumes are removed" -Description: "Identify any unused Elastic Block Store (EBS) volumes in your AWS account and remove them." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when state = 'in-use' then 'ok' - else 'alarm' - end as status, - case - when state = 'in-use' then title || ' attached to EC2 instance.' - else title || ' not attached to EC2 instance.' - end as reason - from - aws_ebs_volume; - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN state = 'in-use' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN state = 'in-use' THEN title || ' attached to EC2 instance.' + ELSE title || ' not attached to EC2 instance.' + END AS reason + FROM + aws_ebs_volume; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.2.4 Ensure unused EBS volumes are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_3.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_3.yaml old mode 100755 new mode 100644 index 3b9702cd4..50f5cef47 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_3.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_3.yaml @@ -1,43 +1,43 @@ +Description: Tag policies help you standardize tags on all tagged resources across your organization. ID: aws_cis_compute_service_v100_2_3 -Title: "2.3 Ensure Tag Policies are enabled" -Description: "Tag policies help you standardize tags on all tagged resources across your organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with tag_policy_enabled as ( - select + ListOfTables: + - aws_organizations_policy + Parameters: [] + PrimaryTable: aws_organizations_policy + QueryToExecute: | + WITH tag_policy_enabled AS ( + SELECT _ctx, account_id, region, - count(*) as count - from + COUNT(*) AS count + FROM aws_organizations_policy - where + WHERE type = 'TAG_POLICY' - group by + GROUP BY _ctx, region, account_id ) - select - account_id as resource, - _ctx.og_account_id as og_account_id, - _ctx.og_resource_id as og_resource_id, - case - when count > 0 then 'ok' - else 'alarm' - end as status, - case - when count > 0 then 'Organizational tag policies are enabled.' - else 'Organizational tag policies are disabled.' - end as reason - from + SELECT + account_id AS resource, + _ctx.og_account_id AS og_account_id, + _ctx.og_resource_id AS og_resource_id, + CASE + WHEN count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN count > 0 THEN 'Organizational tag policies are enabled.' + ELSE 'Organizational tag policies are disabled.' + END AS reason + FROM tag_policy_enabled; - PrimaryTable: aws_organizations_policy - ListOfTables: - - aws_organizations_policy - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3 Ensure Tag Policies are enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_4.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_4.yaml old mode 100755 new mode 100644 index 9626530f9..95925710e --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_4.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_4.yaml @@ -1,14 +1,22 @@ +Description: A tag policy enables you to define tag compliance rules to help you maintain consistency in the tags attached to your organization's resources. ID: aws_cis_compute_service_v100_2_4 -Title: "2.4 Ensure an Organizational EC2 Tag Policy has been created" -Description: "A tag policy enables you to define tag compliance rules to help you maintain consistency in the tags attached to your organization's resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.4 Ensure an Organizational EC2 Tag Policy has been created \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_5.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_5.yaml old mode 100755 new mode 100644 index d332091d1..718111327 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_5.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_5.yaml @@ -1,14 +1,26 @@ +Description: Identify any running AWS EC2 instances older than 180 days. ID: aws_cis_compute_service_v100_2_5 -Title: "2.5 Ensure no AWS EC2 Instances are older than 180 days" -Description: "Identify any running AWS EC2 instances older than 180 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n instance_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n launch_time,\n case\n when launch_time >= (current_date - interval '180 days') then 'ok'\n else 'alarm'\n end as status,\n title || ' created ' || to_char(launch_time , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - launch_time) || ' days).' as reason\n \n \nfrom\n aws_ec2_instance;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + instance_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + launch_time, + CASE + WHEN launch_time >= (CURRENT_DATE - INTERVAL '180 days') THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' created ' || TO_CHAR(launch_time, 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM CURRENT_TIMESTAMP - launch_time) || ' days).' AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.5 Ensure no AWS EC2 Instances are older than 180 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_6.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_6.yaml old mode 100755 new mode 100644 index f54414006..8e4e8264c --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_6.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_6.yaml @@ -1,28 +1,28 @@ +Description: Ensure that detailed monitoring is enabled for your Amazon EC2 instances. ID: aws_cis_compute_service_v100_2_6 -Title: "2.6 Ensure detailed monitoring is enable for production EC2 Instances" -Description: "Ensure that detailed monitoring is enabled for your Amazon EC2 instances." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when monitoring_state = 'enabled' then 'ok' - else 'alarm' - end as status, - case - when monitoring_state = 'enabled' then instance_id || ' detailed monitoring enabled.' - else instance_id || ' detailed monitoring disabled.' - end as reason - from - aws_ec2_instance; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN monitoring_state = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN monitoring_state = 'enabled' THEN instance_id || ' detailed monitoring enabled.' + ELSE instance_id || ' detailed monitoring disabled.' + END AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.6 Ensure detailed monitoring is enable for production EC2 Instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_8.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_8.yaml old mode 100755 new mode 100644 index 40ac70b30..f91769d90 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_8.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_8.yaml @@ -1,28 +1,28 @@ +Description: Ensure the Instance Metadata Service Version 2 (IMDSv2) method is enabled on all running instances. ID: aws_cis_compute_service_v100_2_8 -Title: "2.8 Ensure the Use of IMDSv2 is Enforced on All Existing Instances" -Description: "Ensure the Instance Metadata Service Version 2 (IMDSv2) method is enabled on all running instances." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when metadata_options ->> 'HttpTokens' = 'optional' then 'alarm' - else 'ok' - end as status, - case - when metadata_options ->> 'HttpTokens' = 'optional' then title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' - else title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' - end as reason - from - aws_ec2_instance; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' + ELSE title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' + END AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.8 Ensure the Use of IMDSv2 is Enforced on All Existing Instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_2_9.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_2_9.yaml old mode 100755 new mode 100644 index 1e520aca2..53d9e97a6 --- a/compliance/controls/aws/aws_cis_compute_service_v100_2_9.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_2_9.yaml @@ -1,32 +1,33 @@ +Description: An inventory and management of Amazon Elastic Compute Cloud (Amazon EC2) instances is made possible with AWS Systems Manager. ID: aws_cis_compute_service_v100_2_9 -Title: "2.9 Ensure use of AWS Systems Manager to manage EC2 instances" -Description: "An inventory and management of Amazon Elastic Compute Cloud (Amazon EC2) instances is made possible with AWS Systems Manager." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when i.instance_state = 'stopped' then 'info' - when m.instance_id is null then 'alarm' - else 'ok' - end as status, - case - when i.instance_state = 'stopped' then i.title || ' is in stopped state.' - when m.instance_id is null then i.title || ' not managed by AWS SSM.' - else i.title || ' managed by AWS SSM.' - end as reason - from - aws_ec2_instance i - left join aws_ssm_managed_instance m on m.instance_id = i.instance_id; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance - aws_ssm_managed_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN i.instance_state = 'stopped' THEN 'info' + WHEN m.instance_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.instance_state = 'stopped' THEN i.title || ' is in stopped state.' + WHEN m.instance_id IS NULL THEN i.title || ' not managed by AWS SSM.' + ELSE i.title || ' managed by AWS SSM.' + END AS reason + FROM + aws_ec2_instance i + LEFT JOIN + aws_ssm_managed_instance m ON m.instance_id = i.instance_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.9 Ensure use of AWS Systems Manager to manage EC2 instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_1.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_1.yaml old mode 100755 new mode 100644 index 16c9f6670..2f77b5241 --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_1.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_1.yaml @@ -1,14 +1,22 @@ +Description: Amazon Lightsail is a virtual private server (VPS) provider and is the easiest way to get started with AWS for developers, small businesses, students, and other users who need a solution to build and host their applications on cloud. ID: aws_cis_compute_service_v100_3_1 -Title: "3.1 Apply updates to any apps running in Lightsail" -Description: "Amazon Lightsail is a virtual private server (VPS) provider and is the easiest way to get started with AWS for developers, small businesses, students, and other users who need a solution to build and host their applications on cloud." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.1 Apply updates to any apps running in Lightsail \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_10.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_10.yaml old mode 100755 new mode 100644 index 471fff00d..f97ab07ee --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_10.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_10.yaml @@ -1,14 +1,22 @@ +Description: Access logging provides detailed records for the requests that are made to this bucket. This information can include the request type, the resources that are specified in the request, and the time and date that the request was processed. Access logs are useful for many applications. ID: aws_cis_compute_service_v100_3_10 -Title: "3.10 Enable storage bucket access logging" -Description: "Access logging provides detailed records for the requests that are made to this bucket. This information can include the request type, the resources that are specified in the request, and the time and date that the request was processed. Access logs are useful for many applications." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;\n" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.10 Enable storage bucket access logging \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_11.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_11.yaml old mode 100755 new mode 100644 index 92dc9c9f6..b943b593f --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_11.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_11.yaml @@ -1,14 +1,22 @@ +Description: Windows server based Lightsail instances are still managed by the consumer and any security updates or patches have to be installed and maintained by the user. ID: aws_cis_compute_service_v100_3_11 -Title: "3.11 Ensure your Windows Server based lightsail instances are updated with the latest security patches" -Description: "Windows server based Lightsail instances are still managed by the consumer and any security updates or patches have to be installed and maintained by the user." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.11 Ensure your Windows Server based lightsail instances are updated with the latest security patches \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_12.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_12.yaml old mode 100755 new mode 100644 index 9847df0e4..474b040a2 --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_12.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_12.yaml @@ -1,14 +1,22 @@ +Description: When you create a Windows Server-based instance, Lightsail randomly generates a long password that is hard to guess. You use this password uniquely with your new instance. You can use the default password to connect quickly to your instance using remote desktop (RDP). You are always logged in as the Administrator on your Lightsail instance. ID: aws_cis_compute_service_v100_3_12 -Title: "3.12 Change the auto-generated password for Windows based instances" -Description: "When you create a Windows Server-based instance, Lightsail randomly generates a long password that is hard to guess. You use this password uniquely with your new instance. You can use the default password to connect quickly to your instance using remote desktop (RDP). You are always logged in as the Administrator on your Lightsail instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.12 Change the auto-generated password for Windows based instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_2.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_2.yaml old mode 100755 new mode 100644 index 32ac8c21c..ccb6dcbb9 --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_2.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_2.yaml @@ -1,14 +1,22 @@ +Description: Change the default settings for the administrator login names and passwords of the application software that you install on Lightsail instances. ID: aws_cis_compute_service_v100_3_2 -Title: "3.2 Change default Administrator login names and passwords for applications" -Description: "Change the default settings for the administrator login names and passwords of the application software that you install on Lightsail instances." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'INFO' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.2 Change default Administrator login names and passwords for applications \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_3.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_3.yaml old mode 100755 new mode 100644 index eb284bbba..ecef773c8 --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_3.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_3.yaml @@ -1,59 +1,59 @@ +Description: Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should remove and disable these ports when not is use. ID: aws_cis_compute_service_v100_3_3 -Title: "3.3 Disable SSH and RDP ports for Lightsail instances when not needed" -Description: "Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should remove and disable these ports when not is use." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with open_ports as ( - select + ListOfTables: + - aws_lightsail_instance + Parameters: [] + PrimaryTable: aws_lightsail_instance + QueryToExecute: | + WITH open_ports AS ( + SELECT i.name, - jsonb_array_elements(i.networking -> 'Ports') as port - from + jsonb_array_elements(i.networking -> 'Ports') AS port + FROM aws_lightsail_instance i ), - port_cidrs as ( - select + port_cidrs AS ( + SELECT op.name, - (op.port ->> 'FromPort')::int as from_port, - (op.port ->> 'ToPort')::int as to_port, - op.port ->> 'Protocol' as protocol, - jsonb_array_elements_text(op.port -> 'Cidrs') as cidr, - jsonb_array_elements_text(op.port -> 'Ipv6Cidrs') as ipv6_cidr - from + (op.port ->> 'FromPort')::int AS from_port, + (op.port ->> 'ToPort')::int AS to_port, + op.port ->> 'Protocol' AS protocol, + jsonb_array_elements_text(op.port -> 'Cidrs') AS cidr, + jsonb_array_elements_text(op.port -> 'Ipv6Cidrs') AS ipv6_cidr + FROM open_ports op ), - insecure_ports as ( - select + insecure_ports AS ( + SELECT name - from + FROM port_cidrs - where - from_port in (22, 3389, 80) - and to_port in (22, 338, 80) - and protocol = 'tcp' - and (cidr = '0.0.0.0/0' or ipv6_cidr = '::/0') + WHERE + from_port IN (22, 3389, 80) + AND to_port IN (22, 3389, 80) + AND protocol = 'tcp' + AND (cidr = '0.0.0.0/0' OR ipv6_cidr = '::/0') ) - select - i.name as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.name is null then 'ok' - else 'alarm' - end as status, - case - when p.name is null then i.name || ' does not have SSH (22) or RDP (3389) or HTTP (80) ports open to 0.0.0.0/0 or ::/0.' - else i.name || ' has SSH (22) or RDP (3389) or HTTP (80) ports open to 0.0.0.0/0 or ::/0.' - end as reason, + SELECT + i.name AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.name IS NULL THEN i.name || ' does not have SSH (22) or RDP (3389) or HTTP (80) ports open to 0.0.0.0/0 or ::/0.' + ELSE i.name || ' has SSH (22) or RDP (3389) or HTTP (80) ports open to 0.0.0.0/0 or ::/0.' + END AS reason, i.tags - from + FROM aws_lightsail_instance i - left join insecure_ports p on i.name = p.name; - PrimaryTable: aws_lightsail_instance - ListOfTables: - - aws_lightsail_instance - Parameters: [] + LEFT JOIN insecure_ports p ON i.name = p.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.3 Disable SSH and RDP ports for Lightsail instances when not needed \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_5.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_5.yaml old mode 100755 new mode 100644 index 32b4e3f9d..29a0b2d01 --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_5.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_5.yaml @@ -1,58 +1,58 @@ +Description: Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should identify which IP address need access. ID: aws_cis_compute_service_v100_3_5 -Title: "3.5 Ensure RDP is restricted to only IP address that should have this access" -Description: "Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should identify which IP address need access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with open_ports as ( - select + ListOfTables: + - aws_lightsail_instance + Parameters: [] + PrimaryTable: aws_lightsail_instance + QueryToExecute: | + WITH open_ports AS ( + SELECT name, - jsonb_array_elements(networking -> 'Ports') as port - from + jsonb_array_elements(networking -> 'Ports') AS port + FROM aws_lightsail_instance ), - port_cidrs as ( - select + port_cidrs AS ( + SELECT op.name, - (op.port ->> 'FromPort')::int as from_port, - (op.port ->> 'ToPort')::int as to_port, - op.port ->> 'Protocol' as protocol, - jsonb_array_elements_text(op.port -> 'Cidrs') as cidr - from + (op.port ->> 'FromPort')::int AS from_port, + (op.port ->> 'ToPort')::int AS to_port, + op.port ->> 'Protocol' AS protocol, + jsonb_array_elements_text(op.port -> 'Cidrs') AS cidr + FROM open_ports op ), - unrestricted_rdp_ports as ( - select + unrestricted_rdp_ports AS ( + SELECT name - from + FROM port_cidrs - where + WHERE from_port = 3389 - and to_port = 3389 - and protocol = 'tcp' - and cidr = '0.0.0.0/0' + AND to_port = 3389 + AND protocol = 'tcp' + AND cidr = '0.0.0.0/0' ) - select - i.name as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when urp.name is null then 'ok' - else 'alarm' - end as status, - case - when urp.name is null then i.name || ' has RDP (3389) restricted to specific IP addresses.' - else i.name || ' has RDP (3389) open to the world (0.0.0.0/0).' - end as reason, + SELECT + i.name AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN urp.name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN urp.name IS NULL THEN i.name || ' has RDP (3389) restricted to specific IP addresses.' + ELSE i.name || ' has RDP (3389) open to the world (0.0.0.0/0).' + END AS reason, i.tags - from + FROM aws_lightsail_instance i - left join unrestricted_rdp_ports urp on i.name = urp.name; - PrimaryTable: aws_lightsail_instance - ListOfTables: - - aws_lightsail_instance - Parameters: [] + LEFT JOIN unrestricted_rdp_ports urp ON i.name = urp.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.5 Ensure RDP is restricted to only IP address that should have this access \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_6.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_6.yaml old mode 100755 new mode 100644 index 9c3429594..593801532 --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_6.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_6.yaml @@ -1,14 +1,28 @@ +Description: Any protocols enable within Lightsail by default that aren't being used should be disabled. ID: aws_cis_compute_service_v100_3_6 -Title: "3.6 Disable IPv6 Networking if not in use within your organization" -Description: "Any protocols enable within Lightsail by default that aren't being used should be disabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when ip_v6_addresses is null then 'ok'\n else 'alarm'\n end as status,\n case\n when ip_v6_addresses is null then name || ' has IPv6 networking disabled.'\n else name || ' has IPv6 networking enabled.'\n end as reason\n \n \nfrom\n aws_lightsail_instance;" - PrimaryTable: aws_lightsail_instance ListOfTables: - aws_lightsail_instance Parameters: [] + PrimaryTable: aws_lightsail_instance + QueryToExecute: | + SELECT + name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ip_v6_addresses IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ip_v6_addresses IS NULL THEN name || ' has IPv6 networking disabled.' + ELSE name || ' has IPv6 networking enabled.' + END AS reason + FROM + aws_lightsail_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.6 Disable IPv6 Networking if not in use within your organization \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_7.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_7.yaml old mode 100755 new mode 100644 index 8b0a8edb1..1ffa7c932 --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_7.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_7.yaml @@ -1,14 +1,22 @@ +Description: The following policy grants a user access to manage a specific bucket in the Amazon Lightsail object storage service. ID: aws_cis_compute_service_v100_3_7 -Title: "3.7 Ensure you are using an IAM policy to manage access to buckets in Lightsail" -Description: "The following policy grants a user access to manage a specific bucket in the Amazon Lightsail object storage service." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.7 Ensure you are using an IAM policy to manage access to buckets in Lightsail \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_8.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_8.yaml old mode 100755 new mode 100644 index 795393c52..ca14b9bb9 --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_8.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_8.yaml @@ -1,14 +1,22 @@ +Description: Attaching an Amazon Lightsail instance to a Lightsail storage bucket gives it full programmatic access to the bucket and its objects. ID: aws_cis_compute_service_v100_3_8 -Title: "3.8 Ensure Lightsail instances are attached to the buckets" -Description: "Attaching an Amazon Lightsail instance to a Lightsail storage bucket gives it full programmatic access to the bucket and its objects." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.8 Ensure Lightsail instances are attached to the buckets \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_3_9.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_3_9.yaml old mode 100755 new mode 100644 index 72fd55a51..b8300cf42 --- a/compliance/controls/aws/aws_cis_compute_service_v100_3_9.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_3_9.yaml @@ -1,14 +1,22 @@ +Description: You can make all objects private, public (read-only) or private while making individual objects public (read-only). By default when creating a bucket the permissions are set to 'All objects are private'. ID: aws_cis_compute_service_v100_3_9 -Title: "3.9 Ensure that your Lightsail buckets are not publicly accessible" -Description: "You can make all objects private, public (read-only) or private while making individual objects public (read-only). By default when creating a bucket the permissions are set to 'All objects are private'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.9 Ensure that your Lightsail buckets are not publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_1.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_1.yaml old mode 100755 new mode 100644 index 36f207fff..41d46891b --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_1.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_1.yaml @@ -1,14 +1,22 @@ +Description: With AWS Config, you can track configuration changes to the Lambda functions (including deleted functions), runtime environments, tags, handler name, code size, memory allocation, timeout settings, and concurrency settings, along with Lambda IAM execution role, subnet, and security group associations. ID: aws_cis_compute_service_v100_4_1 -Title: "4.1 Ensure AWS Config is enabled for Lambda and serverless" -Description: "With AWS Config, you can track configuration changes to the Lambda functions (including deleted functions), runtime environments, tags, handler name, code size, memory allocation, timeout settings, and concurrency settings, along with Lambda IAM execution role, subnet, and security group associations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.1 Ensure AWS Config is enabled for Lambda and serverless \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_10.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_10.yaml old mode 100755 new mode 100644 index 1f5b8a5ea..ffb6cb851 --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_10.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_10.yaml @@ -1,14 +1,22 @@ +Description: Ensure that all your Amazon Lambda functions are configured to allow access only to trusted AWS accounts in order to protect against unauthorized cross-account access. ID: aws_cis_compute_service_v100_4_10 -Title: "4.10 Ensure Lambda functions do not allow unknown cross account access via permission policies" -Description: "Ensure that all your Amazon Lambda functions are configured to allow access only to trusted AWS accounts in order to protect against unauthorized cross-account access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.10 Ensure Lambda functions do not allow unknown cross account access via permission policies \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_11.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_11.yaml old mode 100755 new mode 100644 index 62a62394c..f6b6a90cf --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_11.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_11.yaml @@ -1,14 +1,22 @@ +Description: Always using a recent version of the execution environment configured for your Amazon Lambda functions adheres to best practices for the newest software features, the latest security patches and bug fixes, and performance and reliability. ID: aws_cis_compute_service_v100_4_11 -Title: "4.11 Ensure that the runtime environment versions used for your Lambda functions do not have end of support dates" -Description: "Always using a recent version of the execution environment configured for your Amazon Lambda functions adheres to best practices for the newest software features, the latest security patches and bug fixes, and performance and reliability." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.11 Ensure that the runtime environment versions used for your Lambda functions do not have end of support dates \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_12.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_12.yaml old mode 100755 new mode 100644 index a1f3b933b..55d1ce820 --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_12.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_12.yaml @@ -1,14 +1,28 @@ +Description: As you can set your own environmental variables for Lambda it is important to also encrypt them for in transit protection. ID: aws_cis_compute_service_v100_4_12 -Title: "4.12 Ensure encryption in transit is enabled for Lambda environment variables" -Description: "As you can set your own environmental variables for Lambda it is important to also encrypt them for in transit protection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kms_key_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_key_arn is null then title || ' encryption is disabled.'\n else title || ' encryption is enabled.'\n end as reason\n \n \nfrom\n aws_lambda_function;" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_arn IS NULL THEN title || ' encryption is disabled.' + ELSE title || ' encryption is enabled.' + END AS reason + FROM + aws_lambda_function; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.12 Ensure encryption in transit is enabled for Lambda environment variables \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_2.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_2.yaml old mode 100755 new mode 100644 index 7638979ff..1547feb1a --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_2.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_2.yaml @@ -1,14 +1,36 @@ +Description: Ensure that Amazon CloudWatch Lambda Insights is enabled for your Amazon Lambda functions for enhanced monitoring. ID: aws_cis_compute_service_v100_4_2 -Title: "4.2 Ensure Cloudwatch Lambda insights is enabled" -Description: "Ensure that Amazon CloudWatch Lambda Insights is enabled for your Amazon Lambda functions for enhanced monitoring." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when exists (\n select 1\n from jsonb_array_elements(layers) as l\n where l ->> 'Arn' like '%:layer:LambdaInsightsExtension:%'\n ) then 'ok'\n else 'alarm'\n end as status,\n case\n when exists (\n select 1\n from jsonb_array_elements(layers) as l\n where l ->> 'Arn' like '%:layer:LambdaInsightsExtension:%'\n ) then title || ' CloudWatch Insights enabled.'\n else title || ' CloudWatch Insights disabled.'\n end as reason\n \n \nfrom\n aws_lambda_function;" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(layers) AS l + WHERE l ->> 'Arn' LIKE '%:layer:LambdaInsightsExtension:%' + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(layers) AS l + WHERE l ->> 'Arn' LIKE '%:layer:LambdaInsightsExtension:%' + ) THEN title || ' CloudWatch Insights enabled.' + ELSE title || ' CloudWatch Insights disabled.' + END AS reason + FROM + aws_lambda_function; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.2 Ensure Cloudwatch Lambda insights is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_3.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_3.yaml old mode 100755 new mode 100644 index b13fea3c6..964c05a5a --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_3.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_3.yaml @@ -1,14 +1,22 @@ +Description: Lambda functions often have to access a database or other services within your environment. ID: aws_cis_compute_service_v100_4_3 -Title: "4.3 Ensure AWS Secrets manager is configured and being used by Lambda for databases" -Description: "Lambda functions often have to access a database or other services within your environment." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.3 Ensure AWS Secrets manager is configured and being used by Lambda for databases \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_4.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_4.yaml old mode 100755 new mode 100644 index 6c090edc3..236e847bc --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_4.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_4.yaml @@ -1,14 +1,22 @@ +Description: Lambda is fully integrated with IAM, allowing you to control precisely what each Lambda function can do within the AWS Cloud. As you develop a Lambda function, you expand the scope of this policy to enable access to other resources. For example, for a function that processes objects put into an S3 bucket, it requires read access to objects stored in that bucket. ID: aws_cis_compute_service_v100_4_4 -Title: "4.4 Ensure least privilege is used with Lambda function access" -Description: "Lambda is fully integrated with IAM, allowing you to control precisely what each Lambda function can do within the AWS Cloud. As you develop a Lambda function, you expand the scope of this policy to enable access to other resources. For example, for a function that processes objects put into an S3 bucket, it requires read access to objects stored in that bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.4 Ensure least privilege is used with Lambda function access \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_5.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_5.yaml old mode 100755 new mode 100644 index 94b7650d3..8d90e6566 --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_5.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_5.yaml @@ -1,14 +1,22 @@ +Description: Every Lambda function should have a one to one IAM execution role and the roles should not be shared between functions. ID: aws_cis_compute_service_v100_4_5 -Title: "4.5 Ensure every Lambda function has its own IAM Role" -Description: "Every Lambda function should have a one to one IAM execution role and the roles should not be shared between functions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.5 Ensure every Lambda function has its own IAM Role \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_6.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_6.yaml old mode 100755 new mode 100644 index d4ec18007..6821f9ed8 --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_6.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_6.yaml @@ -1,46 +1,46 @@ +Description: A publicly accessible Amazon Lambda function is open to the public and can be reviewed by anyone. To protect against unauthorized users that are sending requests to invoke these functions they need to be changed so they are not exposed to the public ID: aws_cis_compute_service_v100_4_6 -Title: "4.6 Ensure Lambda functions are not exposed to everyone" -Description: "A publicly accessible Amazon Lambda function is open to the public and can be reviewed by anyone. To protect against unauthorized users that are sending requests to invoke these functions they need to be changed so they are not exposed to the public" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with wildcard_action_policies as ( - select + ListOfTables: + - aws_lambda_function + Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_lambda_function, - jsonb_array_elements(policy_std -> 'Statement') as s - where + JSONB_ARRAY_ELEMENTS(policy_std -> 'Statement') AS s + WHERE s ->> 'Effect' = 'Allow' - and ( - ( s -> 'Principal' -> 'AWS') = '["*"]' - or s ->> 'Principal' = '*' + AND ( + (s -> 'Principal' -> 'AWS') = '["*"]' + OR s ->> 'Principal' = '*' ) - group by + GROUP BY arn ) - select - f.arn as resource, - f.og_account_id as og_account_id, - f.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end as status, - case - when p.arn is null then title || ' does not allow public access.' - else title || ' contains ' || coalesce(p.statements_num,0) || + SELECT + f.arn AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' does not allow public access.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || ' statements that allows public access.' - end as reason - from - aws_lambda_function as f - left join wildcard_action_policies as p on p.arn = f.arn; - PrimaryTable: aws_lambda_function - ListOfTables: - - aws_lambda_function - Parameters: [] + END AS reason + FROM + aws_lambda_function AS f + LEFT JOIN wildcard_action_policies AS p ON p.arn = f.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.6 Ensure Lambda functions are not exposed to everyone \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_7.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_7.yaml old mode 100755 new mode 100644 index 59469eda6..0f41729a6 --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_7.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_7.yaml @@ -1,14 +1,22 @@ +Description: In order to have the necessary permissions to access the AWS cloud services and resources Amazon Lambda functions should be associated with active(available) execution roles. ID: aws_cis_compute_service_v100_4_7 -Title: "4.7 Ensure Lambda functions are referencing active execution" -Description: "In order to have the necessary permissions to access the AWS cloud services and resources Amazon Lambda functions should be associated with active(available) execution roles." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.7 Ensure Lambda functions are referencing active execution \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_8.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_8.yaml old mode 100755 new mode 100644 index beb6a775e..2a6c04d49 --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_8.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_8.yaml @@ -1,14 +1,22 @@ +Description: Ensure that all your Amazon Lambda functions are configured to use the Code Signing feature in order to restrict the deployment of unverified code. ID: aws_cis_compute_service_v100_4_8 -Title: "4.8 Ensure that Code Signing is enabled for Lambda functions" -Description: "Ensure that all your Amazon Lambda functions are configured to use the Code Signing feature in order to restrict the deployment of unverified code." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.8 Ensure that Code Signing is enabled for Lambda functions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_4_9.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_4_9.yaml old mode 100755 new mode 100644 index fbae6a6a4..62f40fd2c --- a/compliance/controls/aws/aws_cis_compute_service_v100_4_9.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_4_9.yaml @@ -1,14 +1,22 @@ +Description: Ensure that your Amazon Lambda functions don't have administrative permissions potentially giving the function access to all AWS cloud services and resources. ID: aws_cis_compute_service_v100_4_9 -Title: "4.9 Ensure there are no Lambda functions with admin privileges within your AWS account" -Description: "Ensure that your Amazon Lambda functions don't have administrative permissions potentially giving the function access to all AWS cloud services and resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.9 Ensure there are no Lambda functions with admin privileges within your AWS account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_5_1.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_5_1.yaml old mode 100755 new mode 100644 index 614086338..dd9b0a5b7 --- a/compliance/controls/aws/aws_cis_compute_service_v100_5_1.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_5_1.yaml @@ -1,14 +1,22 @@ +Description: You can configure Batch jobs to send log information to CloudWatch Logs. ID: aws_cis_compute_service_v100_5_1 -Title: "5.1 Ensure AWS Batch is configured with AWS Cloudwatch Logs" -Description: "You can configure Batch jobs to send log information to CloudWatch Logs." -Query: +IntegrationType: + - aws_cloud_account +Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account - ListOfTables: + ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.1 Ensure AWS Batch is configured with AWS Cloudwatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_5_2.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_5_2.yaml old mode 100755 new mode 100644 index d567e2d3b..c431b4fa6 --- a/compliance/controls/aws/aws_cis_compute_service_v100_5_2.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_5_2.yaml @@ -1,14 +1,22 @@ +Description: The Cross-service confused deputy problem is a security issue where an entity that doesn't have permission to perform an action can coerce a more-privileged entity to perform the action. ID: aws_cis_compute_service_v100_5_2 -Title: "5.2 Ensure Batch roles are configured for cross-service confused deputy prevention" -Description: "The Cross-service confused deputy problem is a security issue where an entity that doesn't have permission to perform an action can coerce a more-privileged entity to perform the action." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.2 Ensure Batch roles are configured for cross-service confused deputy prevention \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_6_1.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_6_1.yaml old mode 100755 new mode 100644 index e19c0726c..09b40f638 --- a/compliance/controls/aws/aws_cis_compute_service_v100_6_1.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_6_1.yaml @@ -1,14 +1,22 @@ +Description: AWS Elastic Beanstalk regularly releases platform updates to provide fixes, software updates, and new features. With managed platform updates, you can configure your environment to automatically upgrade to the latest version of a platform during a scheduled maintenance window. ID: aws_cis_compute_service_v100_6_1 -Title: "6.1 Ensure Managed Platform updates is configured" -Description: "AWS Elastic Beanstalk regularly releases platform updates to provide fixes, software updates, and new features. With managed platform updates, you can configure your environment to automatically upgrade to the latest version of a platform during a scheduled maintenance window." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6.1 Ensure Managed Platform updates is configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_6_2.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_6_2.yaml old mode 100755 new mode 100644 index 65b0a0ec1..54b83eb58 --- a/compliance/controls/aws/aws_cis_compute_service_v100_6_2.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_6_2.yaml @@ -1,42 +1,42 @@ +Description: Elastic Beanstalk can be configured to automatically stream logs to the CloudWatch service. ID: aws_cis_compute_service_v100_6_2 -Title: "6.2 Ensure Persistent logs is setup and configured to S3" -Description: "Elastic Beanstalk can be configured to automatically stream logs to the CloudWatch service." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with beanstalk_environment_logs_enabled as ( - select - distinct e.arn - from - aws_elastic_beanstalk_environment as e, - jsonb_array_elements(e.configuration_settings) as c, - jsonb_array_elements(c -> 'OptionSettings') as s - where - s ->> 'OptionName' = 'StreamLogs' - and s ->> 'Value' = 'true' - group by - arn - ) - select - e.arn as resource, - e.og_account_id as og_account_id, - e.og_resource_id as og_resource_id, - case - when l.arn is not null then 'ok' - else 'alarm' - end as status, - case - when l.arn is not null then title || ' send logs to AWS CloudWatch.' - else title || ' does not send logs to AWS CloudWatch.' - end as reason - from - aws_elastic_beanstalk_environment as e - left join beanstalk_environment_logs_enabled as l on e.arn = l.arn; - PrimaryTable: aws_elastic_beanstalk_environment ListOfTables: - aws_elastic_beanstalk_environment Parameters: [] + PrimaryTable: aws_elastic_beanstalk_environment + QueryToExecute: | + WITH beanstalk_environment_logs_enabled AS ( + SELECT + DISTINCT e.arn + FROM + aws_elastic_beanstalk_environment AS e, + JSONB_ARRAY_ELEMENTS(e.configuration_settings) AS c, + JSONB_ARRAY_ELEMENTS(c -> 'OptionSettings') AS s + WHERE + s ->> 'OptionName' = 'StreamLogs' + AND s ->> 'Value' = 'true' + GROUP BY + arn + ) + SELECT + e.arn AS resource, + e.og_account_id AS og_account_id, + e.og_resource_id AS og_resource_id, + CASE + WHEN l.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN l.arn IS NOT NULL THEN title || ' send logs to AWS CloudWatch.' + ELSE title || ' does not send logs to AWS CloudWatch.' + END AS reason + FROM + aws_elastic_beanstalk_environment AS e + LEFT JOIN beanstalk_environment_logs_enabled AS l ON e.arn = l.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6.2 Ensure Persistent logs is setup and configured to S3 \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_6_3.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_6_3.yaml old mode 100755 new mode 100644 index 3c3e741ea..9f52d89cd --- a/compliance/controls/aws/aws_cis_compute_service_v100_6_3.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_6_3.yaml @@ -1,14 +1,22 @@ +Description: When you enable load balancing, your AWS Elastic Beanstalk environment is equipped with an Elastic Load Balancing load balancer to distribute traffic among the instances in your environment. ID: aws_cis_compute_service_v100_6_3 -Title: "6.3 Ensure access logs are enabled" -Description: "When you enable load balancing, your AWS Elastic Beanstalk environment is equipped with an Elastic Load Balancing load balancer to distribute traffic among the instances in your environment." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6.3 Ensure access logs are enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_compute_service_v100_6_4.yaml b/compliance/controls/aws/aws_cis_compute_service_v100_6_4.yaml old mode 100755 new mode 100644 index 1ab6d3ea1..88d4919ba --- a/compliance/controls/aws/aws_cis_compute_service_v100_6_4.yaml +++ b/compliance/controls/aws/aws_cis_compute_service_v100_6_4.yaml @@ -1,14 +1,22 @@ +Description: The simplest way to use HTTPS with an Elastic Beanstalk environment is to assign a server certificate to your environment's load balancer. ID: aws_cis_compute_service_v100_6_4 -Title: "6.4 Ensure that HTTPS is enabled on load balancer" -Description: "The simplest way to use HTTPS with an Elastic Beanstalk environment is to assign a server certificate to your environment's load balancer." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6.4 Ensure that HTTPS is enabled on load balancer \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_1.yaml b/compliance/controls/aws/aws_cis_v120_1_1.yaml old mode 100755 new mode 100644 index 441061de2..bb367ce2f --- a/compliance/controls/aws/aws_cis_v120_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_1.yaml @@ -1,14 +1,22 @@ +Description: The "root" account has unrestricted access to all resources in the AWS account. It is highly recommended that the use of this account be avoided. ID: aws_cis_v120_1_1 -Title: "1.1 Avoid the use of the \\\"root\\\" account" -Description: "The \\\"root\\\" account has unrestricted access to all resources in the AWS account. It is highly recommended that the use of this account be avoided." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.1 Avoid the use of the "root" account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_11.yaml b/compliance/controls/aws/aws_cis_v120_1_11.yaml old mode 100755 new mode 100644 index b0671e52e..a5b501621 --- a/compliance/controls/aws/aws_cis_v120_1_11.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_11.yaml @@ -1,15 +1,31 @@ +Description: IAM password policies can require passwords to be rotated or expired after a given number of days. It is recommended that the password policy expire passwords after 90 days or less. ID: aws_cis_v120_1_11 -Title: "1.11 Ensure IAM password policy expires passwords within 90 days or less" -Description: "IAM password policies can require passwords to be rotated or expired after a given number of days. It is recommended that the password policy expire passwords after 90 days or less." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when max_password_age <= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when max_password_age is null then 'Password expiration not set.'\n else 'Password expiration set to ' || max_password_age || ' days.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN max_password_age <= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN max_password_age IS NULL THEN 'Password expiration not set.' + ELSE 'Password expiration set to ' || max_password_age || ' days.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.11 Ensure IAM password policy expires passwords within 90 days or less \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_12.yaml b/compliance/controls/aws/aws_cis_v120_1_12.yaml old mode 100755 new mode 100644 index 9761a6f0a..f60396c61 --- a/compliance/controls/aws/aws_cis_v120_1_12.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_12.yaml @@ -1,28 +1,28 @@ +Description: The root account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the root account be removed. ID: aws_cis_v120_1_12 -Title: "1.12 Ensure no root account access key exists" -Description: "The root account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the root account be removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || partition || ':::' || account_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when account_access_keys_present > 0 then 'alarm' - else 'ok' - end status, - case - when account_access_keys_present > 0 then 'Root user access keys exist.' - else 'No root user access keys exist.' - end reason - from - aws_iam_account_summary; - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_access_keys_present > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN account_access_keys_present > 0 THEN 'Root user access keys exist.' + ELSE 'No root user access keys exist.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.12 Ensure no root account access key exists \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_13.yaml b/compliance/controls/aws/aws_cis_v120_1_13.yaml old mode 100755 new mode 100644 index a4d74c94f..404c1b261 --- a/compliance/controls/aws/aws_cis_v120_1_13.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_13.yaml @@ -1,14 +1,28 @@ +Description: The root account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. ID: aws_cis_v120_1_13 -Title: "1.13 Ensure MFA is enabled for the \\\"root\\\" account" -Description: "The root account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_mfa_enabled then 'ok'\n else 'alarm'\n end status,\n case\n when account_mfa_enabled then 'MFA enabled for root account.'\n else 'MFA not enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_mfa_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN account_mfa_enabled THEN 'MFA enabled for root account.' + ELSE 'MFA not enabled for root account.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.13 Ensure MFA is enabled for the "root" account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_15.yaml b/compliance/controls/aws/aws_cis_v120_1_15.yaml old mode 100755 new mode 100644 index d362511bb..d1ac35525 --- a/compliance/controls/aws/aws_cis_v120_1_15.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_15.yaml @@ -1,13 +1,22 @@ +Description: The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established. ID: aws_cis_v120_1_15 -Title: "1.15 Ensure security questions are registered in the AWS account" -Description: "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: category: @@ -28,5 +37,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: 1.15 Ensure security questions are registered in the AWS account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_16.yaml b/compliance/controls/aws/aws_cis_v120_1_16.yaml old mode 100755 new mode 100644 index 6ce909d3c..245155005 --- a/compliance/controls/aws/aws_cis_v120_1_16.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_16.yaml @@ -1,26 +1,25 @@ +Description: By default, IAM users, groups, and roles have no access to AWS resources. IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended that IAM policies be applied directly to groups and roles but not users. ID: aws_cis_v120_1_16 -Title: "1.16 Ensure IAM policies are attached only to groups or roles" -Description: "By default, IAM users, groups, and roles have no access to AWS resources. IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended that IAM policies be applied directly to groups and roles but not users." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when attached_policy_arns is null then 'ok' - else 'alarm' - end status, - name || ' has ' || coalesce(jsonb_array_length(attached_policy_arns),0) || ' attached policies.' as reason - - from - aws_iam_user; - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN attached_policy_arns IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' has ' || COALESCE(jsonb_array_length(attached_policy_arns), 0) || ' attached policies.' AS reason + FROM + aws_iam_user; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.16 Ensure IAM policies are attached only to groups or roles \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_17.yaml b/compliance/controls/aws/aws_cis_v120_1_17.yaml old mode 100755 new mode 100644 index a0df79d6e..af8b1d346 --- a/compliance/controls/aws/aws_cis_v120_1_17.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_17.yaml @@ -1,14 +1,22 @@ +Description: Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. ID: aws_cis_v120_1_17 -Title: "1.17 Maintain current contact details" -Description: "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.17 Maintain current contact details \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_18.yaml b/compliance/controls/aws/aws_cis_v120_1_18.yaml old mode 100755 new mode 100644 index 400eec0b8..cb94979d1 --- a/compliance/controls/aws/aws_cis_v120_1_18.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_18.yaml @@ -1,54 +1,53 @@ +Description: AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided. ID: aws_cis_v120_1_18 -Title: "1.18 Ensure security contact information is registered" -Description: "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alternate_security_contact as ( - select + ListOfTables: + - aws_account_alternate_contact + - aws_account + Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH alternate_security_contact AS ( + SELECT name, account_id - from + FROM aws_account_alternate_contact - where + WHERE contact_type = 'SECURITY' ), - account as ( - select + account AS ( + SELECT arn, partition, title, account_id, _ctx - from + FROM aws_account ) - select - arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.partition = 'aws-us-gov' then 'info' - -- Name is a required field if setting a security contact - when c.name is not null then 'ok' - else 'alarm' - end as status, - case - when a.partition = 'aws-us-gov' then a.title || ' in GovCloud, manual verification required.' - when c.name is not null then a.title || ' has security contact ' || c.name || ' registered.' - else a.title || ' security contact not registered.' - end as reason - from - account as a, - alternate_security_contact as c - where + SELECT + arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.partition = 'aws-us-gov' THEN 'info' + WHEN c.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.partition = 'aws-us-gov' THEN a.title || ' in GovCloud, manual verification required.' + WHEN c.name IS NOT NULL THEN a.title || ' has security contact ' || c.name || ' registered.' + ELSE a.title || ' security contact not registered.' + END AS reason + FROM + account AS a, + alternate_security_contact AS c + WHERE c.account_id = a.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_account_alternate_contact - - aws_account - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.18 Ensure security contact information is registered \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_19.yaml b/compliance/controls/aws/aws_cis_v120_1_19.yaml old mode 100755 new mode 100644 index fd078d9dd..44fe08b29 --- a/compliance/controls/aws/aws_cis_v120_1_19.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_19.yaml @@ -1,14 +1,22 @@ +Description: AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. "AWS Access" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources. ID: aws_cis_v120_1_19 -Title: "1.19 Ensure IAM instance roles are used for AWS resource access from instances" -Description: "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \\\"AWS Access\\\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.19 Ensure IAM instance roles are used for AWS resource access from instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_2.yaml b/compliance/controls/aws/aws_cis_v120_1_2.yaml old mode 100755 new mode 100644 index 7cc0025b4..871017566 --- a/compliance/controls/aws/aws_cis_v120_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_2.yaml @@ -1,14 +1,29 @@ +Description: Multi-Factor Authentication (MFA) adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. It is recommended that MFA be enabled for all accounts that have a console password. ID: aws_cis_v120_1_2 -Title: "1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password" -Description: "Multi-Factor Authentication (MFA) adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. It is recommended that MFA be enabled for all accounts that have a console password." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when password_enabled and not mfa_active then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then user_name || ' password login disabled.'\n when password_enabled and not mfa_active then user_name || ' password login enabled but no MFA device configured.'\n else user_name || ' password login enabled and MFA device configured.'\n end as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND NOT mfa_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN password_enabled AND NOT mfa_active THEN user_name || ' password login enabled but no MFA device configured.' + ELSE user_name || ' password login enabled and MFA device configured.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_20.yaml b/compliance/controls/aws/aws_cis_v120_1_20.yaml old mode 100755 new mode 100644 index 2c77beab1..0b1147877 --- a/compliance/controls/aws/aws_cis_v120_1_20.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_20.yaml @@ -1,50 +1,50 @@ +Description: AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support. ID: aws_cis_v120_1_20 -Title: "1.20 Ensure a support role has been created to manage incidents with AWS Support" -Description: "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - -- pgFormatter-ignore - with support_role_count as - ( - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - count(policy_arn), + ListOfTables: + - aws_account + - aws_iam_role + Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH support_role_count AS ( + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + COUNT(policy_arn), a.account_id, a._ctx - from - aws_account as a - left join aws_iam_role as r on r.account_id = a.account_id - left join jsonb_array_elements_text(attached_policy_arns) as policy_arn on true - where - split_part(policy_arn, '/', 2) = 'AWSSupportAccess' - or policy_arn is null - group by + FROM + aws_account AS a + LEFT JOIN aws_iam_role AS r + ON r.account_id = a.account_id + LEFT JOIN jsonb_array_elements_text(attached_policy_arns) AS policy_arn + ON TRUE + WHERE + SPLIT_PART(policy_arn, '/', 2) = 'AWSSupportAccess' + OR policy_arn IS NULL + GROUP BY a.account_id, a.partition, a._ctx ) - select + SELECT resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when count > 0 then 'ok' - else 'alarm' - end as status, - case - when count = 1 then 'AWSSupportAccess policy attached to 1 role.' - when count > 1 then 'AWSSupportAccess policy attached to ' || count || ' roles.' - else 'AWSSupportAccess policy not attached to any role.' - end as reason - from + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN COUNT > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT = 1 THEN 'AWSSupportAccess policy attached to 1 role.' + WHEN COUNT > 1 THEN 'AWSSupportAccess policy attached to ' || COUNT || ' roles.' + ELSE 'AWSSupportAccess policy not attached to any role.' + END AS reason + FROM support_role_count; - PrimaryTable: aws_iam_role - ListOfTables: - - aws_account - - aws_iam_role - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.20 Ensure a support role has been created to manage incidents with AWS Support \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_21.yaml b/compliance/controls/aws/aws_cis_v120_1_21.yaml old mode 100755 new mode 100644 index f958cd016..fbdb1f152 --- a/compliance/controls/aws/aws_cis_v120_1_21.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_21.yaml @@ -1,14 +1,34 @@ +Description: AWS console defaults the checkbox for creating access keys to enabled. This results in many access keys being generated unnecessarily. In addition to unnecessary credentials, it also generates unnecessary management work in auditing and rotating these keys. ID: aws_cis_v120_1_21 -Title: "1.21 Do not setup access keys during initial user setup for all IAM users that have a console password" -Description: "AWS console defaults the checkbox for creating access keys to enabled. This results in many access keys being generated unnecessarily. In addition to unnecessary credentials, it also generates unnecessary management work in auditing and rotating these keys." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n -- alarm when password is enabled and the key was created within 10 seconds of the user\n when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then user_name || ' password login disabled.'\n when access_key_1_last_rotated is null then user_name || ' has no access keys.'\n when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10)\n then user_name || ' has access key created during user creation and password login enabled.'\n else user_name || ' has access key not created during user creation.'\n end as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled + AND extract(epoch FROM (access_key_1_last_rotated - user_creation_time)) < 10 + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN access_key_1_last_rotated IS NULL THEN user_name || ' has no access keys.' + WHEN password_enabled + AND extract(epoch FROM (access_key_1_last_rotated - user_creation_time)) < 10 + THEN user_name || ' has access key created during user creation and password login enabled.' + ELSE user_name || ' has access key not created during user creation.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.21 Do not setup access keys during initial user setup for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_22.yaml b/compliance/controls/aws/aws_cis_v120_1_22.yaml old mode 100755 new mode 100644 index 921290390..444bdd44a --- a/compliance/controls/aws/aws_cis_v120_1_22.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_22.yaml @@ -1,55 +1,54 @@ +Description: IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege—that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges. ID: aws_cis_v120_1_22 -Title: "1.22 Ensure IAM policies that allow full \\\"*:*\\\" administrative privileges are not created" -Description: "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege—that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with star_access_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH star_access_policies AS ( + SELECT arn, is_aws_managed, - count(*) as num_bad_statements - from + COUNT(*) AS num_bad_statements + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - (action = '*' - or action = '*:*' - ) + AND resource = '*' + AND ( + action = '*' + OR action = '*:*' ) - and is_attached - group by + AND is_attached + GROUP BY arn, is_aws_managed ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when s.arn is not null and s.is_aws_managed then 'info' - when s.arn is null then 'ok' - else 'alarm' - end status, - case - when s.arn is not null and s.is_aws_managed then p.name || ' is an AWS managed policy with ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - else p.name || ' contains ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - end as reason - from - aws_iam_policy as p - left join star_access_policies as s on p.arn = s.arn - where + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN 'info' + WHEN s.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN p.name || ' is an AWS managed policy with ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + ELSE p.name || ' contains ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + END AS reason + FROM + aws_iam_policy AS p + LEFT JOIN star_access_policies AS s ON p.arn = s.arn + WHERE p.is_attached; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.22 Ensure IAM policies that allow full "*:*" administrative privileges are not created \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_3.yaml b/compliance/controls/aws/aws_cis_v120_1_3.yaml old mode 100755 new mode 100644 index a54b3c584..fdb55c6e7 --- a/compliance/controls/aws/aws_cis_v120_1_3.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_3.yaml @@ -1,14 +1,75 @@ +Description: AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 90 or greater days be removed or deactivated. ID: aws_cis_v120_1_3 -Title: "1.3 Ensure credentials unused for 90 days or greater are disabled" -Description: "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 90 or greater days be removed or deactivated." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when user_name = ''\n then 'info'\n when password_enabled and password_last_used is null and password_last_changed < (current_date - interval '90' day)\n then 'alarm'\n when password_enabled and password_last_used < (current_date - interval '90' day)\n then 'alarm'\n when access_key_1_active and access_key_1_last_used_date is null and access_key_1_last_rotated < (current_date - interval '90' day)\n then 'alarm'\n when access_key_1_active and access_key_1_last_used_date < (current_date - interval '90' day)\n then 'alarm'\n when access_key_2_active and access_key_2_last_used_date is null and access_key_2_last_rotated < (current_date - interval '90' day)\n then 'alarm'\n when access_key_2_active and access_key_2_last_used_date < (current_date - interval '90' day)\n then 'alarm'\n else 'ok'\n end status,\n user_name ||\n case\n when not password_enabled\n then ' password not enabled,'\n when password_enabled and password_last_used is null\n then ' password created ' || to_char(password_last_changed, 'DD-Mon-YYYY') || ' never used,'\n else\n ' password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_1_active\n then ' key 1 not enabled,'\n when access_key_1_active and access_key_1_last_used_date is null\n then ' key 1 created ' || to_char(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,'\n else\n ' key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_2_active\n then ' key 2 not enabled.'\n when access_key_2_active and access_key_2_last_used_date is null\n then ' key 2 created ' || to_char(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.'\n else\n ' key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.'\n end\n as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_name = '' + THEN 'info' + WHEN password_enabled + AND password_last_used IS NULL + AND password_last_changed < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN password_enabled + AND password_last_used < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_1_active + AND access_key_1_last_used_date IS NULL + AND access_key_1_last_rotated < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_1_active + AND access_key_1_last_used_date < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_2_active + AND access_key_2_last_used_date IS NULL + AND access_key_2_last_rotated < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_2_active + AND access_key_2_last_used_date < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + ELSE 'ok' + END status, + user_name || + CASE + WHEN NOT password_enabled + THEN ' password not enabled,' + WHEN password_enabled + AND password_last_used IS NULL + THEN ' password created ' || TO_CHAR(password_last_changed, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_1_active + THEN ' key 1 not enabled,' + WHEN access_key_1_active + AND access_key_1_last_used_date IS NULL + THEN ' key 1 created ' || TO_CHAR(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_2_active + THEN ' key 2 not enabled.' + WHEN access_key_2_active + AND access_key_2_last_used_date IS NULL + THEN ' key 2 created ' || TO_CHAR(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' + ELSE + ' key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' + END + AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.3 Ensure credentials unused for 90 days or greater are disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_4.yaml b/compliance/controls/aws/aws_cis_v120_1_4.yaml old mode 100755 new mode 100644 index ef5792684..092f64403 --- a/compliance/controls/aws/aws_cis_v120_1_4.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_4.yaml @@ -1,14 +1,26 @@ +Description: Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated. ID: aws_cis_v120_1_4 -Title: "1.4 Ensure access keys are rotated every 90 days or less" -Description: "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when create_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end status,\n user_name || ' ' || access_key_id || ' created ' || to_char(create_date , 'DD-Mon-YYYY') ||\n ' (' || extract(day from current_timestamp - create_date) || ' days).'\n as reason\n \nfrom\n aws_iam_access_key;" - PrimaryTable: aws_iam_access_key ListOfTables: - aws_iam_access_key Parameters: [] + PrimaryTable: aws_iam_access_key + QueryToExecute: | + SELECT + 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_date <= (current_date - interval '90' DAY) THEN 'alarm' + ELSE 'ok' + END status, + user_name || ' ' || access_key_id || ' created ' || TO_CHAR(create_date, 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM current_timestamp - create_date) || ' days).' AS reason + FROM + aws_iam_access_key; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.4 Ensure access keys are rotated every 90 days or less \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_1_8.yaml b/compliance/controls/aws/aws_cis_v120_1_8.yaml old mode 100755 new mode 100644 index 19b125b96..df4df2839 --- a/compliance/controls/aws/aws_cis_v120_1_8.yaml +++ b/compliance/controls/aws/aws_cis_v120_1_8.yaml @@ -1,31 +1,32 @@ +Description: Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one number. ID: aws_cis_v120_1_8 -Title: "1.8 Ensure IAM password policy require at least one number" -Description: "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one number." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when require_numbers then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - when require_numbers then 'Number required.' - else 'Number not required.' - end as reason - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN require_numbers THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN require_numbers THEN 'Number required.' + ELSE 'Number not required.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.8 Ensure IAM password policy require at least one number \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_2_2.yaml b/compliance/controls/aws/aws_cis_v120_2_2.yaml old mode 100755 new mode 100644 index d9ae0ede8..a8307a252 --- a/compliance/controls/aws/aws_cis_v120_2_2.yaml +++ b/compliance/controls/aws/aws_cis_v120_2_2.yaml @@ -1,14 +1,30 @@ +Description: CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails. ID: aws_cis_v120_2_2 -Title: "2.2 Ensure CloudTrail log file validation is enabled." -Description: "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_file_validation_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when log_file_validation_enabled then title || ' log file validation enabled.'\n else title || ' log file validation disabled.'\n end as reason\n \n \nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_file_validation_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_file_validation_enabled THEN title || ' log file validation enabled.' + ELSE title || ' log file validation disabled.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.2 Ensure CloudTrail log file validation is enabled. \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_2_3.yaml b/compliance/controls/aws/aws_cis_v120_2_3.yaml old mode 100755 new mode 100644 index fe22a0be1..b49b2a932 --- a/compliance/controls/aws/aws_cis_v120_2_3.yaml +++ b/compliance/controls/aws/aws_cis_v120_2_3.yaml @@ -1,15 +1,63 @@ +Description: CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy, or access control list (ACL), applied to the S3 bucket that CloudTrail logs to prevents public access to the CloudTrail logs. ID: aws_cis_v120_2_3 -Title: "2.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible" -Description: "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy, or access control list (ACL), applied to the S3 bucket that CloudTrail logs to prevents public access to the CloudTrail logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with public_bucket_data as (\n-- note the counts are not exactly CORRECT because of the jsonb_array_elements joins,\n-- but will be non-zero if any matches are found\nselect\n t.s3_bucket_name as name,\n b.arn,\n t.region,\n t.account_id,\n t.tags,\n t._ctx,\n count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AllUsers') as all_user_grants,\n count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AuthenticatedUsers') as auth_user_grants,\n count(s) filter (where s ->> 'Effect' = 'Allow' and p = '*' ) as anon_statements\nfrom\n aws_cloudtrail_trail as t\nleft join aws_s3_bucket as b on t.s3_bucket_name = b.name\nleft join jsonb_array_elements(acl -> 'Grants') as acl_grant on true\nleft join jsonb_array_elements(policy_std -> 'Statement') as s on true\nleft join jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p on true\ngroup by\n t.s3_bucket_name,\n b.arn,\n t.region,\n t.account_id,\n t.tags,\n t._ctx\n)\nselect\n case\n when arn is null then 'arn:aws:s3::' || name\n else arn\n end as resource,\n t.og_account_id as og_account_id,\n t.og_resource_id as og_resource_id,\n case\n when arn is null then 'skip'\n when all_user_grants > 0 then 'alarm'\n when auth_user_grants > 0 then 'alarm'\n when anon_statements > 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when arn is null then name || ' not found in account ' || account_id || '.'\n when all_user_grants > 0 then name || ' grants access to AllUsers in ACL.'\n when auth_user_grants > 0 then name || ' grants access to AuthenticatedUsers in ACL.'\n when anon_statements > 0 then name || ' grants access to AWS:*\" in bucket policy.'\n else name || ' does not grant anonymous access in ACL or bucket policy.'\n end as reason\n \n \nfrom\n public_bucket_data;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH public_bucket_data AS ( + SELECT + t.s3_bucket_name AS name, + b.arn, + t.region, + t.account_id, + t.tags, + t._ctx, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AllUsers') AS all_user_grants, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AuthenticatedUsers') AS auth_user_grants, + COUNT(s) FILTER (WHERE s ->> 'Effect' = 'Allow' AND p = '*') AS anon_statements + FROM + aws_cloudtrail_trail AS t + LEFT JOIN aws_s3_bucket AS b ON t.s3_bucket_name = b.name + LEFT JOIN jsonb_array_elements(acl -> 'Grants') AS acl_grant ON TRUE + LEFT JOIN jsonb_array_elements(policy_std -> 'Statement') AS s ON TRUE + LEFT JOIN jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p ON TRUE + GROUP BY + t.s3_bucket_name, + b.arn, + t.region, + t.account_id, + t.tags, + t._ctx + ) + SELECT + CASE + WHEN arn IS NULL THEN 'arn:aws:s3::' || name + ELSE arn + END AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN arn IS NULL THEN 'skip' + WHEN all_user_grants > 0 THEN 'alarm' + WHEN auth_user_grants > 0 THEN 'alarm' + WHEN anon_statements > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN arn IS NULL THEN name || ' not found in account ' || account_id || '.' + WHEN all_user_grants > 0 THEN name || ' grants access to AllUsers in ACL.' + WHEN auth_user_grants > 0 THEN name || ' grants access to AuthenticatedUsers in ACL.' + WHEN anon_statements > 0 THEN name || ' grants access to AWS:*" in bucket policy.' + ELSE name || ' does not grant anonymous access in ACL or bucket policy.' + END AS reason + FROM + public_bucket_data; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_2_4.yaml b/compliance/controls/aws/aws_cis_v120_2_4.yaml old mode 100755 new mode 100644 index 264797b79..4911ecff9 --- a/compliance/controls/aws/aws_cis_v120_2_4.yaml +++ b/compliance/controls/aws/aws_cis_v120_2_4.yaml @@ -1,30 +1,30 @@ +Description: AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs. ID: aws_cis_v120_2_4 -Title: "2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs" -Description: "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then 'ok' - else 'alarm' - end as status, - case - when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then title || ' integrated with CloudWatch logs.' - else title || ' not integrated with CloudWatch logs.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > current_date - 1) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > current_date - 1) THEN title || ' integrated with CloudWatch logs.' + ELSE title || ' not integrated with CloudWatch logs.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_2_5.yaml b/compliance/controls/aws/aws_cis_v120_2_5.yaml old mode 100755 new mode 100644 index 244ca8af5..1612069d7 --- a/compliance/controls/aws/aws_cis_v120_2_5.yaml +++ b/compliance/controls/aws/aws_cis_v120_2_5.yaml @@ -1,15 +1,67 @@ +Description: AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended to enable AWS Config be enabled in all regions. ID: aws_cis_v120_2_5 -Title: "2.5 Ensure AWS Config is enabled in all regions" -Description: "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended to enable AWS Config be enabled in all regions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "-- pgFormatter-ignore\n-- Get count for any region with all matching criteria\nwith global_recorders as (\n select\n count(*) as global_config_recorders\n from\n aws_config_configuration_recorder\n where\n recording_group -> 'IncludeGlobalResourceTypes' = 'true'\n and recording_group -> 'AllSupported' = 'true'\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n)\nselect\n 'arn:aws::' || a.region || ':' || a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n -- When any of the region satisfies with above CTE\n -- In left join of table, regions now having\n -- 'Recording' and 'LastStatus' matching criteria can be considered as OK\n when\n g.global_config_recorders >= 1\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n then 'ok'\n -- Skip any regions that are disabled in the account.\n when a.opt_in_status = 'not-opted-in' then 'skip'\n else 'alarm'\n end as status,\n -- Below cases are for citing respective reasons for control state\n case\n when a.opt_in_status = 'not-opted-in' then a.region || ' region is disabled.'\n else\n case\n when recording_group -> 'IncludeGlobalResourceTypes' = 'true' then a.region || ' IncludeGlobalResourceTypes enabled,'\n else a.region || ' IncludeGlobalResourceTypes disabled,'\n end ||\n case\n when recording_group -> 'AllSupported' = 'true' then ' AllSupported enabled,'\n else ' AllSupported disabled,'\n end ||\n case\n when status ->> 'Recording' = 'true' then ' Recording enabled'\n else ' Recording disabled'\n end ||\n case\n when status ->> 'LastStatus' = 'SUCCESS' then ' and LastStatus is SUCCESS.'\n else ' and LastStatus is not SUCCESS.'\n end\n end as reason\n \nfrom\n global_recorders as g,\n aws_region as a\n left join aws_config_configuration_recorder as r on r.account_id = a.account_id and r.region = a.name;" - PrimaryTable: aws_config_configuration_recorder ListOfTables: - aws_config_configuration_recorder - aws_region Parameters: [] + PrimaryTable: aws_config_configuration_recorder + QueryToExecute: | + WITH global_recorders AS ( + SELECT + COUNT(*) AS global_config_recorders + FROM + aws_config_configuration_recorder + WHERE + recording_group -> 'IncludeGlobalResourceTypes' = 'true' + AND recording_group -> 'AllSupported' = 'true' + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + ) + SELECT + 'arn:aws::' || a.region || ':' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN g.global_config_recorders >= 1 + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + THEN 'ok' + WHEN a.opt_in_status = 'not-opted-in' THEN 'skip' + ELSE 'alarm' + END AS status, + CASE + WHEN a.opt_in_status = 'not-opted-in' THEN a.region || ' region is disabled.' + ELSE + CASE + WHEN recording_group -> 'IncludeGlobalResourceTypes' = 'true' + THEN a.region || ' IncludeGlobalResourceTypes enabled,' + ELSE a.region || ' IncludeGlobalResourceTypes disabled,' + END || + CASE + WHEN recording_group -> 'AllSupported' = 'true' + THEN ' AllSupported enabled,' + ELSE ' AllSupported disabled,' + END || + CASE + WHEN status ->> 'Recording' = 'true' + THEN ' Recording enabled' + ELSE ' Recording disabled' + END || + CASE + WHEN status ->> 'LastStatus' = 'SUCCESS' + THEN ' and LastStatus is SUCCESS.' + ELSE ' and LastStatus is not SUCCESS.' + END + END AS reason + FROM + global_recorders AS g, + aws_region AS a + LEFT JOIN aws_config_configuration_recorder AS r + ON r.account_id = a.account_id AND r.region = a.name Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.5 Ensure AWS Config is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_2_6.yaml b/compliance/controls/aws/aws_cis_v120_2_6.yaml old mode 100755 new mode 100644 index 2c861abfe..57d8f4aa8 --- a/compliance/controls/aws/aws_cis_v120_2_6.yaml +++ b/compliance/controls/aws/aws_cis_v120_2_6.yaml @@ -1,32 +1,33 @@ +Description: S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket. ID: aws_cis_v120_2_6 -Title: "2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket" -Description: "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - t.arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when b.logging is not null then 'ok' - else 'alarm' - end as status, - case - when b.logging is not null then t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' - else t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' - end as reason - from - aws_cloudtrail_trail t - inner join aws_s3_bucket b on t.s3_bucket_name = b.name - where - t.region = t.home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN b.logging IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.logging IS NOT NULL THEN t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' + ELSE t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' + END AS reason + FROM + aws_cloudtrail_trail t + INNER JOIN + aws_s3_bucket b ON t.s3_bucket_name = b.name + WHERE + t.region = t.home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_2_7.yaml b/compliance/controls/aws/aws_cis_v120_2_7.yaml old mode 100755 new mode 100644 index 718bcf8ce..f2aea79b2 --- a/compliance/controls/aws/aws_cis_v120_2_7.yaml +++ b/compliance/controls/aws/aws_cis_v120_2_7.yaml @@ -1,30 +1,30 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS. ID: aws_cis_v120_2_7 -Title: "2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs" -Description: "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when kms_key_id is null then 'alarm' - else 'ok' - end as status, - case - when kms_key_id is null then title || ' logs are not encrypted at rest.' - else title || ' logs are encrypted at rest.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' logs are not encrypted at rest.' + ELSE title || ' logs are encrypted at rest.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_2_8.yaml b/compliance/controls/aws/aws_cis_v120_2_8.yaml old mode 100755 new mode 100644 index a258ef266..f2e8f033d --- a/compliance/controls/aws/aws_cis_v120_2_8.yaml +++ b/compliance/controls/aws/aws_cis_v120_2_8.yaml @@ -1,36 +1,36 @@ +Description: AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled. ID: aws_cis_v120_2_8 -Title: "2.8 Ensure rotation for customer created CMKs is enabled" -Description: "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when origin = 'EXTERNAL' then 'skip' - when key_state = 'PendingDeletion' then 'skip' - when key_state = 'Disabled' then 'skip' - when not key_rotation_enabled then 'alarm' - else 'ok' - end as status, - case - when origin = 'EXTERNAL' then title || ' has imported key material.' - when key_state = 'PendingDeletion' then title || ' is pending deletion.' - when key_state = 'Disabled' then title || ' is disabled.' - when not key_rotation_enabled then title || ' key rotation disabled.' - else title || ' key rotation enabled.' - end as reason - from - aws_kms_key - where - key_manager = 'CUSTOMER'; - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN origin = 'EXTERNAL' THEN 'skip' + WHEN key_state = 'PendingDeletion' THEN 'skip' + WHEN key_state = 'Disabled' THEN 'skip' + WHEN NOT key_rotation_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN origin = 'EXTERNAL' THEN title || ' has imported key material.' + WHEN key_state = 'PendingDeletion' THEN title || ' is pending deletion.' + WHEN key_state = 'Disabled' THEN title || ' is disabled.' + WHEN NOT key_rotation_enabled THEN title || ' key rotation disabled.' + ELSE title || ' key rotation enabled.' + END AS reason + FROM + aws_kms_key + WHERE + key_manager = 'CUSTOMER'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.8 Ensure rotation for customer created CMKs is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_2_9.yaml b/compliance/controls/aws/aws_cis_v120_2_9.yaml old mode 100755 new mode 100644 index 1fe3c314d..56364f984 --- a/compliance/controls/aws/aws_cis_v120_2_9.yaml +++ b/compliance/controls/aws/aws_cis_v120_2_9.yaml @@ -1,15 +1,56 @@ +Description: VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet "Rejects" for VPCs. ID: aws_cis_v120_2_9 -Title: "2.9 Ensure VPC flow logging is enabled in all VPCs" -Description: "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \\\"Rejects\\\" for VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vpcs as (\n select\n arn,\n account_id,\n region,\n owner_id,\n vpc_id,\n tags,\n _ctx\n from\n aws_vpc\n order by\n vpc_id\n),\nflowlogs as (\n select\n resource_id,\n account_id,\n region\n from\n aws_vpc_flow_log\n order by\n resource_id\n)\nselect\n v.arn as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when v.account_id <> v.owner_id then 'skip'\n when f.resource_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when v.account_id <> v.owner_id then v.vpc_id || ' is a shared VPC.'\n when f.resource_id is not null then v.vpc_id || ' flow logging enabled.'\n else v.vpc_id || ' flow logging disabled.'\n end as reason\n \nfrom\n vpcs as v\n left join flowlogs as f on v.vpc_id = f.resource_id;" - PrimaryTable: aws_vpc ListOfTables: - aws_vpc - aws_vpc_flow_log Parameters: [] + PrimaryTable: aws_vpc + QueryToExecute: | + WITH vpcs AS ( + SELECT + arn, + account_id, + region, + owner_id, + vpc_id, + tags, + _ctx + FROM + aws_vpc + ORDER BY + vpc_id + ), + flowlogs AS ( + SELECT + resource_id, + account_id, + region + FROM + aws_vpc_flow_log + ORDER BY + resource_id + ) + SELECT + v.arn AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.account_id <> v.owner_id THEN 'skip' + WHEN f.resource_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.account_id <> v.owner_id THEN v.vpc_id || ' is a shared VPC.' + WHEN f.resource_id IS NOT NULL THEN v.vpc_id || ' flow logging enabled.' + ELSE v.vpc_id || ' flow logging disabled.' + END AS reason + FROM + vpcs AS v + LEFT JOIN flowlogs AS f ON v.vpc_id = f.resource_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.9 Ensure VPC flow logging is enabled in all VPCs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_3_11.yaml b/compliance/controls/aws/aws_cis_v120_3_11.yaml old mode 100755 new mode 100644 index 35b0ba1f9..1df08f795 --- a/compliance/controls/aws/aws_cis_v120_3_11.yaml +++ b/compliance/controls/aws/aws_cis_v120_3_11.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs. ID: aws_cis_v120_3_11 -Title: "3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL)" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateNetworkAcl.+\$\.eventName\s*=\s*CreateNetworkAclEntry.+\$\.eventName\s*=\s*DeleteNetworkAcl.+\$\.eventName\s*=\s*DeleteNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclAssociation' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - f.og_account_id as og_account_id, - f.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for changes to NACLs.' - else filter_name || ' forwards events for changes to NACLs.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to NACLs.' + ELSE filter_name || ' forwards events for changes to NACLs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_3_12.yaml b/compliance/controls/aws/aws_cis_v120_3_12.yaml old mode 100755 new mode 100644 index 3fa83d7b3..55381b540 --- a/compliance/controls/aws/aws_cis_v120_3_12.yaml +++ b/compliance/controls/aws/aws_cis_v120_3_12.yaml @@ -1,10 +1,9 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways. ID: aws_cis_v120_3_12 -Title: "3.12 Ensure a log metric filter and alarm exist for changes to network gateways" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateCustomerGateway.+\\$\\.eventName\\s*=\\s*DeleteCustomerGateway.+\\$\\.eventName\\s*=\\s*AttachInternetGateway.+\\$\\.eventName\\s*=\\s*CreateInternetGateway.+\\$\\.eventName\\s*=\\s*DeleteInternetGateway.+\\$\\.eventName\\s*=\\s*DetachInternetGateway'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n f.og_account_id as og_account_id,\n f.og_resource_id as og_resource_id,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for changes to network gateways.'\n else filter_name || ' forwards events for changes to network gateways.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_cloudwatch_alarm @@ -12,7 +11,86 @@ Query: - aws_cloudwatch_log_metric_filter - aws_account Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateCustomerGateway.+\$\.eventName\s*=\s*DeleteCustomerGateway.+\$\.eventName\s*=\s*AttachInternetGateway.+\$\.eventName\s*=\s*CreateInternetGateway.+\$\.eventName\s*=\s*DeleteInternetGateway.+\$\.eventName\s*=\s*DetachInternetGateway' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to network gateways.' + ELSE filter_name || ' forwards events for changes to network gateways.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.12 Ensure a log metric filter and alarm exist for changes to network gateways \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_3_13.yaml b/compliance/controls/aws/aws_cis_v120_3_13.yaml old mode 100755 new mode 100644 index 263343e82..820669c57 --- a/compliance/controls/aws/aws_cis_v120_3_13.yaml +++ b/compliance/controls/aws/aws_cis_v120_3_13.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables. ID: aws_cis_v120_3_13 -Title: "3.13 Ensure a log metric filter and alarm exist for route table changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*ReplaceRoute.+\$\.eventName\s*=\s*ReplaceRouteTableAssociation.+\$\.eventName\s*=\s*DeleteRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for route table changes.' - else filter_name || ' forwards events for route table changes.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for route table changes.' + ELSE filter_name || ' forwards events for route table changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.13 Ensure a log metric filter and alarm exist for route table changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_3_14.yaml b/compliance/controls/aws/aws_cis_v120_3_14.yaml old mode 100755 new mode 100644 index a6e537527..18e90224b --- a/compliance/controls/aws/aws_cis_v120_3_14.yaml +++ b/compliance/controls/aws/aws_cis_v120_3_14.yaml @@ -1,10 +1,9 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs. ID: aws_cis_v120_3_14 -Title: "3.14 Ensure a log metric filter and alarm exist for VPC changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateVpc.+\\$\\.eventName\\s*=\\s*DeleteVpc.+\\$\\.eventName\\s*=\\s*ModifyVpcAttribute.+\\$\\.eventName\\s*=\\s*AcceptVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*CreateVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*DeleteVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*RejectVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*AttachClassicLinkVpc.+\\$\\.eventName\\s*=\\s*DetachClassicLinkVpc.+\\$\\.eventName\\s*=\\s*DisableVpcClassicLink.+\\$\\.eventName\\s*=\\s*EnableVpcClassicLink'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\nt.og_account_id as og_account_id,\nt.og_resource_id as og_resource_id,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for VPC changes.'\n else filter_name || ' forwards events for VPC changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_cloudwatch_alarm @@ -12,7 +11,86 @@ Query: - aws_cloudwatch_log_metric_filter - aws_account Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateVpc.+\$.eventName\s*=\s*DeleteVpc.+\$.eventName\s*=\s*ModifyVpcAttribute.+\$.eventName\s*=\s*AcceptVpcPeeringConnection.+\$.eventName\s*=\s*CreateVpcPeeringConnection.+\$.eventName\s*=\s*DeleteVpcPeeringConnection.+\$.eventName\s*=\s*RejectVpcPeeringConnection.+\$.eventName\s*=\s*AttachClassicLinkVpc.+\$.eventName\s*=\s*DetachClassicLinkVpc.+\$.eventName\s*=\s*DisableVpcClassicLink.+\$.eventName\s*=\s*EnableVpcClassicLink' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for VPC changes.' + ELSE filter_name || ' forwards events for VPC changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.14 Ensure a log metric filter and alarm exist for VPC changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_3_5.yaml b/compliance/controls/aws/aws_cis_v120_3_5.yaml old mode 100755 new mode 100644 index fa9323f3f..9902e7b7a --- a/compliance/controls/aws/aws_cis_v120_3_5.yaml +++ b/compliance/controls/aws/aws_cis_v120_3_5.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations. ID: aws_cis_v120_3_5 -Title: "3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateTrail.+\$\.eventName\s*=\s*UpdateTrail.+\$\.eventName\s*=\s*DeleteTrail.+\$\.eventName\s*=\s*StartLogging.+\$\.eventName\s*=\s*StopLogging' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for CloudTrail configuration changes.' - else filter_name || ' forwards events for CloudTrail configuration changes.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for CloudTrail configuration changes.' + ELSE filter_name || ' forwards events for CloudTrail configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_4_1.yaml b/compliance/controls/aws/aws_cis_v120_4_1.yaml old mode 100755 new mode 100644 index 543081e94..268666beb --- a/compliance/controls/aws/aws_cis_v120_4_1.yaml +++ b/compliance/controls/aws/aws_cis_v120_4_1.yaml @@ -1,51 +1,48 @@ +Description: Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to port 22. ID: aws_cis_v120_4_1 -Title: "4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22" -Description: "Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to port 22." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ingress_ssh_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_ssh_rules AS ( + SELECT group_id, - count(*) as num_ssh_rules - from + COUNT(*) AS num_ssh_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and cidr_ipv4 = '0.0.0.0/0' - and ( - ( ip_protocol = '-1' - and from_port is null - ) - or ( - from_port >= 22 - and to_port <= 22 - ) + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR ( + from_port >= 22 AND to_port <= 22 + ) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when ingress_ssh_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when ingress_ssh_rules.group_id is null then sg.group_id || ' ingress restricted for SSH from 0.0.0.0/0.' - else sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing SSH from 0.0.0.0/0.' - end as reason - from - aws_vpc_security_group as sg - left join ingress_ssh_rules on ingress_ssh_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN sg.group_id || ' ingress restricted for SSH from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing SSH from 0.0.0.0/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_ssh_rules ON ingress_ssh_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_4_2.yaml b/compliance/controls/aws/aws_cis_v120_4_2.yaml old mode 100755 new mode 100644 index 311c39308..d20fd03bf --- a/compliance/controls/aws/aws_cis_v120_4_2.yaml +++ b/compliance/controls/aws/aws_cis_v120_4_2.yaml @@ -1,51 +1,46 @@ +Description: Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to port 3389. ID: aws_cis_v120_4_2 -Title: "4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389" -Description: "Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ingress_rdp_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_rdp_rules AS ( + SELECT group_id, - count(*) as num_rdp_rules - from + COUNT(*) AS num_rdp_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and cidr_ipv4 = '0.0.0.0/0' - and ( - ( ip_protocol = '-1' - and from_port is null - ) - or ( - from_port >= 3389 - and to_port <= 3389 - ) + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR (from_port >= 3389 AND to_port <= 3389) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when ingress_rdp_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when ingress_rdp_rules.group_id is null then sg.group_id || ' ingress restricted for RDP from 0.0.0.0/0.' - else sg.group_id || ' contains ' || ingress_rdp_rules.num_rdp_rules || ' ingress rule(s) allowing RDP from 0.0.0.0/0.' - end as reason - from - aws_vpc_security_group as sg - left join ingress_rdp_rules on ingress_rdp_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN ingress_rdp_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_rdp_rules.group_id IS NULL THEN sg.group_id || ' ingress restricted for RDP from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || ingress_rdp_rules.num_rdp_rules || ' ingress rule(s) allowing RDP from 0.0.0.0/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_rdp_rules ON ingress_rdp_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v120_4_4.yaml b/compliance/controls/aws/aws_cis_v120_4_4.yaml old mode 100755 new mode 100644 index 23ddd8907..ea99c783e --- a/compliance/controls/aws/aws_cis_v120_4_4.yaml +++ b/compliance/controls/aws/aws_cis_v120_4_4.yaml @@ -1,14 +1,22 @@ +Description: Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection. ID: aws_cis_v120_4_4 -Title: "4.4 Ensure routing tables for VPC peering are \\\"least access\\\"" -Description: "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.4 Ensure routing tables for VPC peering are "least access" \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_1.yaml b/compliance/controls/aws/aws_cis_v130_1_1.yaml old mode 100755 new mode 100644 index 31e9a589b..72c99843a --- a/compliance/controls/aws/aws_cis_v130_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_1.yaml @@ -1,14 +1,22 @@ +Description: Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. ID: aws_cis_v130_1_1 -Title: "1.1 Maintain current contact details" -Description: "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.1 Maintain current contact details \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_10.yaml b/compliance/controls/aws/aws_cis_v130_1_10.yaml old mode 100755 new mode 100644 index f9c4c7610..fcb2fc356 --- a/compliance/controls/aws/aws_cis_v130_1_10.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_10.yaml @@ -1,14 +1,29 @@ +Description: Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password. ID: aws_cis_v130_1_10 -Title: "1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password" -Description: "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when password_enabled and not mfa_active then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then user_name || ' password login disabled.'\n when password_enabled and not mfa_active then user_name || ' password login enabled but no MFA device configured.'\n else user_name || ' password login enabled and MFA device configured.'\n end as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND NOT mfa_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN password_enabled AND NOT mfa_active THEN user_name || ' password login enabled but no MFA device configured.' + ELSE user_name || ' password login enabled and MFA device configured.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_11.yaml b/compliance/controls/aws/aws_cis_v130_1_11.yaml old mode 100755 new mode 100644 index 8ebabf3f5..e6d53015f --- a/compliance/controls/aws/aws_cis_v130_1_11.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_11.yaml @@ -1,14 +1,31 @@ +Description: AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require. ID: aws_cis_v130_1_11 -Title: "1.11 Do not setup access keys during initial user setup for all IAM users that have a console password" -Description: "AWS console defaults to no check boxes selected when creating a new IAM user. When cerating the IAM User credentials you have to determine what type of access they require." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n -- alarm when password is enabled and the key was created within 10 seconds of the user\n when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then user_name || ' password login disabled.'\n when access_key_1_last_rotated is null then user_name || ' has no access keys.'\n when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10)\n then user_name || ' has access key created during user creation and password login enabled.'\n else user_name || ' has access key not created during user creation.'\n end as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND (EXTRACT(EPOCH FROM (access_key_1_last_rotated - user_creation_time)) < 10) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN access_key_1_last_rotated IS NULL THEN user_name || ' has no access keys.' + WHEN password_enabled AND (EXTRACT(EPOCH FROM (access_key_1_last_rotated - user_creation_time)) < 10) + THEN user_name || ' has access key created during user creation and password login enabled.' + ELSE user_name || ' has access key not created during user creation.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.11 Do not setup access keys during initial user setup for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_12.yaml b/compliance/controls/aws/aws_cis_v130_1_12.yaml old mode 100755 new mode 100644 index f1e617830..f97c51e97 --- a/compliance/controls/aws/aws_cis_v130_1_12.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_12.yaml @@ -1,63 +1,63 @@ +Description: AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. + It is recommended that all credentials that have been unused in 90 or greater days be deactivated or removed. ID: aws_cis_v130_1_12 -Title: "1.12 Ensure credentials unused for 90 days or greater are disabled" -Description: "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 90 or greater days be deactivated or removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when user_name = '' - then 'info' - when password_enabled and password_last_used is null and password_last_changed < (current_date - interval '90' day) - then 'alarm' - when password_enabled and password_last_used < (current_date - interval '90' day) - then 'alarm' - when access_key_1_active and access_key_1_last_used_date is null and access_key_1_last_rotated < (current_date - interval '90' day) - then 'alarm' - when access_key_1_active and access_key_1_last_used_date < (current_date - interval '90' day) - then 'alarm' - when access_key_2_active and access_key_2_last_used_date is null and access_key_2_last_rotated < (current_date - interval '90' day) - then 'alarm' - when access_key_2_active and access_key_2_last_used_date < (current_date - interval '90' day) - then 'alarm' - else 'ok' - end status, - user_name || - case - when not password_enabled - then ' password not enabled,' - when password_enabled and password_last_used is null - then ' password created ' || to_char(password_last_changed, 'DD-Mon-YYYY') || ' never used,' - else - ' password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || ',' - end || - case - when not access_key_1_active - then ' key 1 not enabled,' - when access_key_1_active and access_key_1_last_used_date is null - then ' key 1 created ' || to_char(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' - else - ' key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' - end || - case - when not access_key_2_active - then ' key 2 not enabled.' - when access_key_2_active and access_key_2_last_used_date is null - then ' key 2 created ' || to_char(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' - else - ' key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' - end - as reason - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_name = '' + THEN 'info' + WHEN password_enabled AND password_last_used IS NULL AND password_last_changed < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN password_enabled AND password_last_used < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL AND access_key_1_last_rotated < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL AND access_key_2_last_rotated < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + ELSE 'ok' + END status, + user_name || + CASE + WHEN NOT password_enabled + THEN ' password not enabled,' + WHEN password_enabled AND password_last_used IS NULL + THEN ' password created ' || TO_CHAR(password_last_changed, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_1_active + THEN ' key 1 not enabled,' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL + THEN ' key 1 created ' || TO_CHAR(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_2_active + THEN ' key 2 not enabled.' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL + THEN ' key 2 created ' || TO_CHAR(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' + ELSE + ' key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.12 Ensure credentials unused for 90 days or greater are disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_13.yaml b/compliance/controls/aws/aws_cis_v130_1_13.yaml old mode 100755 new mode 100644 index 7b3a6ee71..1ec0c392b --- a/compliance/controls/aws/aws_cis_v130_1_13.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_13.yaml @@ -1,35 +1,38 @@ +Description: Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API. One of the best ways to protect your account is to not allow users to have multiple access keys. ID: aws_cis_v130_1_13 -Title: "1.13 Ensure there is only one active access key available for any single IAM user" -Description: "Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API. One of the best ways to protect your account is to not allow users to have multiple access keys." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - u.arn as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when count(k.*) > 1 then 'alarm' - else 'ok' - end as status, - u.name || ' has ' || count(k.*) || ' active access key(s).' as reason - from - aws_iam_user as u - left join aws_iam_access_key as k on u.name = k.user_name and u.account_id = k.account_id - where - k.status = 'Active' or k.status is null - group by + ListOfTables: + - aws_iam_user + - aws_iam_access_key + Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + u.arn AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(k.*) > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + u.name || ' has ' || COUNT(k.*) || ' active access key(s).' AS reason + FROM + aws_iam_user AS u + LEFT JOIN + aws_iam_access_key AS k + ON + u.name = k.user_name AND u.account_id = k.account_id + WHERE + k.status = 'Active' OR k.status IS NULL + GROUP BY u.arn, u.name, u.account_id, u.tags, u._ctx; - PrimaryTable: aws_iam_user - ListOfTables: - - aws_iam_user - - aws_iam_access_key - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.13 Ensure there is only one active access key available for any single IAM user \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_14.yaml b/compliance/controls/aws/aws_cis_v130_1_14.yaml old mode 100755 new mode 100644 index fff644786..b0b24dba9 --- a/compliance/controls/aws/aws_cis_v130_1_14.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_14.yaml @@ -1,14 +1,26 @@ +Description: Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated. ID: aws_cis_v130_1_14 -Title: "1.14 Ensure access keys are rotated every 90 days or less" -Description: "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when create_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end status,\n user_name || ' ' || access_key_id || ' created ' || to_char(create_date , 'DD-Mon-YYYY') ||\n ' (' || extract(day from current_timestamp - create_date) || ' days).'\n as reason\n \nfrom\n aws_iam_access_key;" - PrimaryTable: aws_iam_access_key ListOfTables: - aws_iam_access_key Parameters: [] + PrimaryTable: aws_iam_access_key + QueryToExecute: | + SELECT + 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || ' ' || access_key_id || ' created ' || TO_CHAR(create_date , 'DD-Mon-YYYY') || + ' (' || EXTRACT(day FROM CURRENT_TIMESTAMP - create_date) || ' days).' AS reason + FROM + aws_iam_access_key; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.14 Ensure access keys are rotated every 90 days or less \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_15.yaml b/compliance/controls/aws/aws_cis_v130_1_15.yaml old mode 100755 new mode 100644 index e244976af..564f9778c --- a/compliance/controls/aws/aws_cis_v130_1_15.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_15.yaml @@ -1,14 +1,26 @@ +Description: 'IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended.' ID: aws_cis_v130_1_15 -Title: "1.15 Ensure IAM Users Receive Permissions Only Through Groups" -Description: "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when inline_policies is null and attached_policy_arns is null then 'ok'\n else 'alarm'\n end status,\n name || ' has ' || coalesce(jsonb_array_length(inline_policies),0) || ' inline and ' ||\n coalesce(jsonb_array_length(attached_policy_arns),0) || ' directly attached policies.' as reason\n \n \nfrom\n aws_iam_user;" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN inline_policies IS NULL AND attached_policy_arns IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' has ' || COALESCE(jsonb_array_length(inline_policies), 0) || ' inline and ' || + COALESCE(jsonb_array_length(attached_policy_arns), 0) || ' directly attached policies.' AS reason + FROM + aws_iam_user; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.15 Ensure IAM Users Receive Permissions Only Through Groups \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_16.yaml b/compliance/controls/aws/aws_cis_v130_1_16.yaml old mode 100755 new mode 100644 index aab4e5c2d..7bf69ab34 --- a/compliance/controls/aws/aws_cis_v130_1_16.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_16.yaml @@ -1,55 +1,54 @@ +Description: IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege - that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges. ID: aws_cis_v130_1_16 -Title: "1.16 Ensure IAM policies that allow full \\\"*:*\\\" administrative privileges are not attached" -Description: "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with star_access_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH star_access_policies AS ( + SELECT arn, is_aws_managed, - count(*) as num_bad_statements - from + COUNT(*) AS num_bad_statements + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - (action = '*' - or action = '*:*' - ) + AND resource = '*' + AND ( + action = '*' + OR action = '*:*' ) - and is_attached - group by + AND is_attached + GROUP BY arn, is_aws_managed ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when s.arn is not null and s.is_aws_managed then 'info' - when s.arn is null then 'ok' - else 'alarm' - end status, - case - when s.arn is not null and s.is_aws_managed then p.name || ' is an AWS managed policy with ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - else p.name || ' contains ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - end as reason - from - aws_iam_policy as p - left join star_access_policies as s on p.arn = s.arn - where + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN 'info' + WHEN s.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN p.name || ' is an AWS managed policy with ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + ELSE p.name || ' contains ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + END AS reason + FROM + aws_iam_policy AS p + LEFT JOIN star_access_policies AS s ON p.arn = s.arn + WHERE p.is_attached; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.16 Ensure IAM policies that allow full "*:*" administrative privileges are not attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_17.yaml b/compliance/controls/aws/aws_cis_v130_1_17.yaml old mode 100755 new mode 100644 index 5295cb428..22f0938f4 --- a/compliance/controls/aws/aws_cis_v130_1_17.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_17.yaml @@ -1,50 +1,48 @@ +Description: AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support. ID: aws_cis_v130_1_17 -Title: "1.17 Ensure a support role has been created to manage incidents with AWS Support" -Description: "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - -- pgFormatter-ignore - with support_role_count as - ( - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - count(policy_arn), + ListOfTables: + - aws_account + - aws_iam_role + Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH support_role_count AS ( + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + COUNT(policy_arn), a.account_id, a._ctx - from - aws_account as a - left join aws_iam_role as r on r.account_id = a.account_id - left join jsonb_array_elements_text(attached_policy_arns) as policy_arn on true - where - split_part(policy_arn, '/', 2) = 'AWSSupportAccess' - or policy_arn is null - group by + FROM + aws_account AS a + LEFT JOIN aws_iam_role AS r ON r.account_id = a.account_id + LEFT JOIN jsonb_array_elements_text(attached_policy_arns) AS policy_arn ON TRUE + WHERE + SPLIT_PART(policy_arn, '/', 2) = 'AWSSupportAccess' + OR policy_arn IS NULL + GROUP BY a.account_id, a.partition, a._ctx ) - select + SELECT resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when count > 0 then 'ok' - else 'alarm' - end as status, - case - when count = 1 then 'AWSSupportAccess policy attached to 1 role.' - when count > 1 then 'AWSSupportAccess policy attached to ' || count || ' roles.' - else 'AWSSupportAccess policy not attached to any role.' - end as reason - from + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN COUNT > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT = 1 THEN 'AWSSupportAccess policy attached to 1 role.' + WHEN COUNT > 1 THEN 'AWSSupportAccess policy attached to ' || COUNT || ' roles.' + ELSE 'AWSSupportAccess policy not attached to any role.' + END AS reason + FROM support_role_count; - PrimaryTable: aws_account - ListOfTables: - - aws_account - - aws_iam_role - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.17 Ensure a support role has been created to manage incidents with AWS Support \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_18.yaml b/compliance/controls/aws/aws_cis_v130_1_18.yaml old mode 100755 new mode 100644 index cf66d7971..3666e8db5 --- a/compliance/controls/aws/aws_cis_v130_1_18.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_18.yaml @@ -1,14 +1,22 @@ +Description: AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. "AWS Access" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources. ID: aws_cis_v130_1_18 -Title: "1.18 Ensure IAM instance roles are used for AWS resource access from instances" -Description: "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \\\"AWS Access\\\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.18 Ensure IAM instance roles are used for AWS resource access from instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_19.yaml b/compliance/controls/aws/aws_cis_v130_1_19.yaml old mode 100755 new mode 100644 index b460626db..699d5e6d9 --- a/compliance/controls/aws/aws_cis_v130_1_19.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_19.yaml @@ -1,14 +1,30 @@ +Description: To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console. ID: aws_cis_v130_1_19 -Title: "1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed" -Description: "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case when expiration < (current_date - interval '1' second) then 'alarm'\n else 'ok'\n end as status,\n case when expiration < (current_date - interval '1' second) then\n name || ' expired ' || to_char(expiration, 'DD-Mon-YYYY') || '.'\n else\n name || ' valid until ' || to_char(expiration, 'DD-Mon-YYYY') || '.'\n end as reason\n \n \nfrom\n aws_iam_server_certificate;" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: [] + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN expiration < (CURRENT_DATE - INTERVAL '1' SECOND) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expiration < (CURRENT_DATE - INTERVAL '1' SECOND) THEN + name || ' expired ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + ELSE + name || ' valid until ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_iam_server_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_2.yaml b/compliance/controls/aws/aws_cis_v130_1_2.yaml old mode 100755 new mode 100644 index eee4e31e3..ce075eb6d --- a/compliance/controls/aws/aws_cis_v130_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_2.yaml @@ -1,15 +1,53 @@ +Description: AWS provides customers with the option of specifying the contact information for accounts security team. It is recommended that this information be provided. ID: aws_cis_v130_1_2 -Title: "1.2 Ensure security contact information is registered" -Description: "AWS provides customers with the option of specifying the contact information for accounts security team. It is recommended that this information be provided." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alternate_security_contact as (\n select\n name,\n account_id\n from\n aws_account_alternate_contact\n where\n contact_type = 'SECURITY'\n),\naccount as (\n select\n arn,\n partition,\n title,\n account_id,\n _ctx\n from\n aws_account\n)\nselect\n arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.partition = 'aws-us-gov' then 'info'\n -- Name is a required field if setting a security contact\n when c.name is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.partition = 'aws-us-gov' then a.title || ' in GovCloud, manual verification required.'\n when c.name is not null then a.title || ' has security contact ' || c.name || ' registered.'\n else a.title || ' security contact not registered.'\n end as reason\n \nfrom\n account as a,\n alternate_security_contact as c\nwhere\n c.account_id = a.account_id;" - PrimaryTable: aws_account ListOfTables: - aws_account_alternate_contact - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH alternate_security_contact AS ( + SELECT + name, + account_id + FROM + aws_account_alternate_contact + WHERE + contact_type = 'SECURITY' + ), + account AS ( + SELECT + arn, + partition, + title, + account_id, + _ctx + FROM + aws_account + ) + SELECT + arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.partition = 'aws-us-gov' THEN 'info' + WHEN c.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.partition = 'aws-us-gov' THEN a.title || ' in GovCloud, manual verification required.' + WHEN c.name IS NOT NULL THEN a.title || ' has security contact ' || c.name || ' registered.' + ELSE a.title || ' security contact not registered.' + END AS reason + FROM + account AS a, + alternate_security_contact AS c + WHERE + c.account_id = a.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.2 Ensure security contact information is registered \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_20.yaml b/compliance/controls/aws/aws_cis_v130_1_20.yaml old mode 100755 new mode 100644 index 1ebd804a3..6b8d2154c --- a/compliance/controls/aws/aws_cis_v130_1_20.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_20.yaml @@ -1,46 +1,52 @@ +Description: Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) + to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects + are created with public access disabled. However, an IAM principle with sufficient S3 permissions + can enable public access at the bucket and/or object level. While enabled, Block public access + (bucket settings) prevents an individual bucket, and its contained objects, from becoming + publicly accessible. Similarly, Block public access (account settings) prevents all buckets, + and contained objects, from becoming publicly accessible across the entire account. ID: aws_cis_v130_1_20 -Title: "1.20 Ensure that S3 Buckets are configured with 'Block public access (bucket settings)'" -Description: "Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principle with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, Block public access (bucket settings) prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, Block public access (account settings) prevents all buckets, and contained objects, from becoming publicly accessible across the entire account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - bucket.og_account_id as og_account_id, - bucket.og_resource_id as og_resource_id, - case - when (bucket.block_public_acls or s3account.block_public_acls) - and (bucket.block_public_policy or s3account.block_public_policy) - and (bucket.ignore_public_acls or s3account.ignore_public_acls) - and (bucket.restrict_public_buckets or s3account.restrict_public_buckets) - then 'ok' - else 'alarm' - end as status, - case - when (bucket.block_public_acls or s3account.block_public_acls) - and (bucket.block_public_policy or s3account.block_public_policy) - and (bucket.ignore_public_acls or s3account.ignore_public_acls) - and (bucket.restrict_public_buckets or s3account.restrict_public_buckets) - then name || ' all public access blocks enabled.' - else name || ' not enabled for: ' || - concat_ws(', ', - case when not (bucket.block_public_acls or s3account.block_public_acls) then 'block_public_acls' end, - case when not (bucket.block_public_policy or s3account.block_public_policy) then 'block_public_policy' end, - case when not (bucket.ignore_public_acls or s3account.ignore_public_acls) then 'ignore_public_acls' end, - case when not (bucket.restrict_public_buckets or s3account.restrict_public_buckets) then 'restrict_public_buckets' end - ) || '.' - end as reason - from - aws_s3_bucket as bucket, - aws_s3_account_settings as s3account - where - s3account.account_id = bucket.account_id; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket - aws_s3_account_settings Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + bucket.og_account_id AS og_account_id, + bucket.og_resource_id AS og_resource_id, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN name || ' all public access blocks enabled.' + ELSE name || ' not enabled for: ' || + concat_ws(', ', + CASE WHEN NOT (bucket.block_public_acls OR s3account.block_public_acls) THEN 'block_public_acls' END, + CASE WHEN NOT (bucket.block_public_policy OR s3account.block_public_policy) THEN 'block_public_policy' END, + CASE WHEN NOT (bucket.ignore_public_acls OR s3account.ignore_public_acls) THEN 'ignore_public_acls' END, + CASE WHEN NOT (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) THEN 'restrict_public_buckets' END + ) || '.' + END AS reason + FROM + aws_s3_bucket AS bucket, + aws_s3_account_settings AS s3account + WHERE + s3account.account_id = bucket.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.20 Ensure that S3 Buckets are configured with 'Block public access (bucket settings)' \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_21.yaml b/compliance/controls/aws/aws_cis_v130_1_21.yaml old mode 100755 new mode 100644 index f356be6a6..3b7dcf104 --- a/compliance/controls/aws/aws_cis_v130_1_21.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_21.yaml @@ -1,33 +1,34 @@ +Description: Enable IAM Access analyzer for IAM policies about all resources. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. ID: aws_cis_v130_1_21 -Title: "1.21 Ensure that IAM Access analyzer is enabled" -Description: "Enable IAM Access analyzer for IAM policies about all resources. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - -- Skip any regions that are disabled in the account. - when r.opt_in_status = 'not-opted-in' then 'skip' - when aa.arn is not null then 'ok' - else 'alarm' - end as status, - case - when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.' - when aa.arn is not null then aa.name || ' enabled in ' || r.region || '.' - else 'Access Analyzer not enabled in ' || r.region || '.' - end as reason - from - aws_region as r - left join aws_accessanalyzer_analyzer as aa on r.account_id = aa.account_id and r.region = aa.region; - PrimaryTable: aws_accessanalyzer_analyzer ListOfTables: - aws_region - aws_accessanalyzer_analyzer Parameters: [] + PrimaryTable: aws_accessanalyzer_analyzer + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN aa.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN aa.arn IS NOT NULL THEN aa.name || ' enabled in ' || r.region || '.' + ELSE 'Access Analyzer not enabled in ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN aws_accessanalyzer_analyzer AS aa + ON r.account_id = aa.account_id + AND r.region = aa.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.21 Ensure that IAM Access analyzer is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_22.yaml b/compliance/controls/aws/aws_cis_v130_1_22.yaml old mode 100755 new mode 100644 index 0ee1778b9..2c00e8469 --- a/compliance/controls/aws/aws_cis_v130_1_22.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_22.yaml @@ -1,14 +1,22 @@ +Description: In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provide via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations. ID: aws_cis_v130_1_22 -Title: "1.22 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments" -Description: "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provide via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.22 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_3.yaml b/compliance/controls/aws/aws_cis_v130_1_3.yaml old mode 100755 new mode 100644 index b3002d538..a114cd0ec --- a/compliance/controls/aws/aws_cis_v130_1_3.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_3.yaml @@ -1,14 +1,22 @@ +Description: The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established. ID: aws_cis_v130_1_3 -Title: "1.3 Ensure security questions are registered in the AWS account" -Description: "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.3 Ensure security questions are registered in the AWS account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_4.yaml b/compliance/controls/aws/aws_cis_v130_1_4.yaml old mode 100755 new mode 100644 index b06a77f51..f5e26496f --- a/compliance/controls/aws/aws_cis_v130_1_4.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_4.yaml @@ -1,14 +1,28 @@ +Description: The root user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the root user account be removed. ID: aws_cis_v130_1_4 -Title: "1.4 Ensure no root user account access key exists" -Description: "The root user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the root user account be removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_access_keys_present > 0 then 'alarm'\n else 'ok'\n end status,\n case\n when account_access_keys_present > 0 then 'Root user access keys exist.'\n else 'No root user access keys exist.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_access_keys_present > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN account_access_keys_present > 0 THEN 'Root user access keys exist.' + ELSE 'No root user access keys exist.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.4 Ensure no root user account access key exists \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_5.yaml b/compliance/controls/aws/aws_cis_v130_1_5.yaml old mode 100755 new mode 100644 index f1c39bf1b..39650f5de --- a/compliance/controls/aws/aws_cis_v130_1_5.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_5.yaml @@ -1,28 +1,28 @@ +Description: The root user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. ID: aws_cis_v130_1_5 -Title: "1.5 Ensure MFA is enabled for the \\\"root user\\\" account" -Description: "The root user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || partition || ':::' || account_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when account_mfa_enabled then 'ok' - else 'alarm' - end status, - case - when account_mfa_enabled then 'MFA enabled for root account.' - else 'MFA not enabled for root account.' - end reason - from - aws_iam_account_summary; - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_mfa_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN account_mfa_enabled THEN 'MFA enabled for root account.' + ELSE 'MFA not enabled for root account.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.5 Ensure MFA is enabled for the "root user" account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_7.yaml b/compliance/controls/aws/aws_cis_v130_1_7.yaml old mode 100755 new mode 100644 index 75d64ae50..111f47abe --- a/compliance/controls/aws/aws_cis_v130_1_7.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_7.yaml @@ -1,14 +1,40 @@ +Description: With the creation of an AWS account, a root user is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks. ID: aws_cis_v130_1_7 -Title: "1.7 Eliminate use of the root user for administrative and daily tasks" -Description: "With the creation of an AWS account, a root user is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when password_last_used >= (current_date - interval '90' day) then 'alarm'\n when access_key_1_last_used_date <= (current_date - interval '90' day) then 'alarm'\n when access_key_2_last_used_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end as status,\n case\n when password_last_used is null then 'Root never logged in with password.'\n else 'Root password used ' || to_char(password_last_used , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - password_last_used) || ' days).'\n end ||\n case\n when access_key_1_last_used_date is null then ' Access Key 1 never used.'\n else ' Access Key 1 used ' || to_char(access_key_1_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_1_last_used_date) || ' days).'\n end ||\n case\n when access_key_2_last_used_date is null then ' Access Key 2 never used.'\n else ' Access Key 2 used ' || to_char(access_key_2_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_2_last_used_date) || ' days).'\n end as reason\n \nfrom\n aws_iam_credential_report\nwhere\n user_name = '';" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_last_used >= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + WHEN access_key_1_last_used_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + WHEN access_key_2_last_used_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN password_last_used IS NULL THEN 'Root never logged in with password.' + ELSE 'Root password used ' || TO_CHAR(password_last_used , 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - password_last_used) || ' days).' + END || + CASE + WHEN access_key_1_last_used_date IS NULL THEN ' Access Key 1 never used.' + ELSE ' Access Key 1 used ' || TO_CHAR(access_key_1_last_used_date , 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - access_key_1_last_used_date) || ' days).' + END || + CASE + WHEN access_key_2_last_used_date IS NULL THEN ' Access Key 2 never used.' + ELSE ' Access Key 2 used ' || TO_CHAR(access_key_2_last_used_date , 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - access_key_2_last_used_date) || ' days).' + END AS reason + FROM + aws_iam_credential_report + WHERE + user_name = ''; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.7 Eliminate use of the root user for administrative and daily tasks \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_1_8.yaml b/compliance/controls/aws/aws_cis_v130_1_8.yaml old mode 100755 new mode 100644 index 4e8988116..0bccc07a1 --- a/compliance/controls/aws/aws_cis_v130_1_8.yaml +++ b/compliance/controls/aws/aws_cis_v130_1_8.yaml @@ -1,30 +1,35 @@ +Description: Password policies are, in part, used to enforce password complexity requirements. + IAM password policies can be used to ensure passwords are at least a given length. + It is recommended that the password policy require a minimum password length of 14. ID: aws_cis_v130_1_8 -Title: "1.8 Ensure IAM password policy requires minimum length of 14 or greater" -Description: "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when minimum_password_length >= 14 then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - else 'Minimum password length set to ' || minimum_password_length || '.' - end as reason - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN minimum_password_length >= 14 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + ELSE 'Minimum password length set to ' || minimum_password_length || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON + a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.8 Ensure IAM password policy requires minimum length of 14 or greater \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_2_1_1.yaml b/compliance/controls/aws/aws_cis_v130_2_1_1.yaml old mode 100755 new mode 100644 index 4efe6c2b1..9ddd36be8 --- a/compliance/controls/aws/aws_cis_v130_2_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v130_2_1_1.yaml @@ -1,28 +1,28 @@ +Description: Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest. ID: aws_cis_v130_2_1_1 -Title: "2.1.1 Ensure all S3 buckets employ encryption-at-rest" -Description: "Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when server_side_encryption_configuration is not null then 'ok' - else 'alarm' - end status, - case - when server_side_encryption_configuration is not null then name || ' default encryption enabled.' - else name || ' default encryption disabled.' - end reason - from - aws_s3_bucket; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN server_side_encryption_configuration IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN server_side_encryption_configuration IS NOT NULL THEN name || ' default encryption enabled.' + ELSE name || ' default encryption disabled.' + END AS reason + FROM + aws_s3_bucket; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.1 Ensure all S3 buckets employ encryption-at-rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_2_1_2.yaml b/compliance/controls/aws/aws_cis_v130_2_1_2.yaml old mode 100755 new mode 100644 index 632925c20..239210851 --- a/compliance/controls/aws/aws_cis_v130_2_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v130_2_1_2.yaml @@ -1,48 +1,48 @@ +Description: At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS. ID: aws_cis_v130_2_1_2 -Title: "2.1.2 Ensure S3 Bucket Policy allows HTTPS requests" -Description: "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ssl_ok as ( - select - distinct name, + ListOfTables: + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH ssl_ok AS ( + SELECT + DISTINCT name, arn, - 'ok' as status - from + 'ok' AS status + FROM aws_s3_bucket, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p, - jsonb_array_elements_text(s -> 'Action') as a, - jsonb_array_elements_text(s -> 'Resource') as r, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + jsonb_array_elements_text(s -> 'Action') AS a, + jsonb_array_elements_text(s -> 'Resource') AS r, jsonb_array_elements_text( s -> 'Condition' -> 'Bool' -> 'aws:securetransport' - ) as ssl - where + ) AS ssl + WHERE p = '*' - and s ->> 'Effect' = 'Deny' - and ssl :: bool = false + AND s ->> 'Effect' = 'Deny' + AND ssl::bool = false ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when ok.status = 'ok' then 'ok' - else 'alarm' - end status, - case - when ok.status = 'ok' then b.name || ' bucket policy enforces HTTPS.' - else b.name || ' bucket policy does not enforce HTTPS.' - end reason - from - aws_s3_bucket as b - left join ssl_ok as ok on ok.name = b.name; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_s3_bucket - Parameters: [] + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN ok.status = 'ok' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ok.status = 'ok' THEN b.name || ' bucket policy enforces HTTPS.' + ELSE b.name || ' bucket policy does not enforce HTTPS.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN ssl_ok AS ok ON ok.name = b.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.2 Ensure S3 Bucket Policy allows HTTPS requests \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_2_2_1.yaml b/compliance/controls/aws/aws_cis_v130_2_2_1.yaml old mode 100755 new mode 100644 index 0765120ee..c4c5cd67d --- a/compliance/controls/aws/aws_cis_v130_2_2_1.yaml +++ b/compliance/controls/aws/aws_cis_v130_2_2_1.yaml @@ -1,14 +1,28 @@ +Description: Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported. ID: aws_cis_v130_2_2_1 -Title: "2.2.1 Ensure EBS volume encryption is enabled" -Description: "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then volume_id || ' encrypted.'\n else volume_id || ' not encrypted.'\n end as reason\n \n \nfrom\n aws_ebs_volume;" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN volume_id || ' encrypted.' + ELSE volume_id || ' not encrypted.' + END AS reason + FROM + aws_ebs_volume; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.2.1 Ensure EBS volume encryption is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_3_10.yaml b/compliance/controls/aws/aws_cis_v130_3_10.yaml old mode 100755 new mode 100644 index ec3adb55b..1af2d60b9 --- a/compliance/controls/aws/aws_cis_v130_3_10.yaml +++ b/compliance/controls/aws/aws_cis_v130_3_10.yaml @@ -1,55 +1,50 @@ +Description: S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets. ID: aws_cis_v130_3_10 -Title: "3.10 Ensure that Object-level logging for write events is enabled for S3 bucket" -Description: "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with s3_selectors as - ( - select - name as trail_name, + ListOfTables: + - aws_cloudtrail_trail + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( + SELECT + name AS trail_name, is_multi_region_trail, bucket_selector - from + FROM aws_cloudtrail_trail, - jsonb_array_elements(event_selectors) as event_selector, - jsonb_array_elements(event_selector -> 'DataResources') as data_resource, - jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector - where + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE is_multi_region_trail - and data_resource ->> 'Type' = 'AWS::S3::Object' - and event_selector ->> 'ReadWriteType' in - ( - 'WriteOnly', - 'All' - ) + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ('WriteOnly', 'All') ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when count(bucket_selector) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(bucket_selector) > 0 then b.name || ' object-level write events logging enabled.' - else b.name || ' object-level write events logging disabled.' - end as reason - from - aws_s3_bucket as b - left join - s3_selectors - on bucket_selector like (b.arn || '%') - or bucket_selector = 'arn:aws:s3' - group by + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level write events logging enabled.' + ELSE b.name || ' object-level write events logging disabled.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN + s3_selectors + ON bucket_selector LIKE (b.arn || '%') + OR bucket_selector = 'arn:aws:s3' + GROUP BY b.account_id, b.region, b.arn, b.name, b.tags, b._ctx; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_cloudtrail_trail - - aws_s3_bucket - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.10 Ensure that Object-level logging for write events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_3_11.yaml b/compliance/controls/aws/aws_cis_v130_3_11.yaml old mode 100755 new mode 100644 index 5f2499d19..eff8176a4 --- a/compliance/controls/aws/aws_cis_v130_3_11.yaml +++ b/compliance/controls/aws/aws_cis_v130_3_11.yaml @@ -1,55 +1,49 @@ +Description: S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets. ID: aws_cis_v130_3_11 -Title: "3.11 Ensure that Object-level logging for read events is enabled for S3 bucket" -Description: "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with s3_selectors as - ( - select - name as trail_name, + ListOfTables: + - aws_cloudtrail_trail + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( + SELECT + name AS trail_name, is_multi_region_trail, bucket_selector - from + FROM aws_cloudtrail_trail, - jsonb_array_elements(event_selectors) as event_selector, - jsonb_array_elements(event_selector -> 'DataResources') as data_resource, - jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector - where + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE is_multi_region_trail - and data_resource ->> 'Type' = 'AWS::S3::Object' - and event_selector ->> 'ReadWriteType' in - ( - 'ReadOnly', - 'All' - ) + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ('ReadOnly', 'All') ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when count(bucket_selector) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(bucket_selector) > 0 then b.name || ' object-level read events logging enabled.' - else b.name || ' object-level read events logging disabled.' - end as reason - from - aws_s3_bucket as b - left join - s3_selectors - on bucket_selector like (b.arn || '%') - or bucket_selector = 'arn:aws:s3' - group by + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level read events logging enabled.' + ELSE b.name || ' object-level read events logging disabled.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN + s3_selectors ON bucket_selector LIKE (b.arn || '%') + OR bucket_selector = 'arn:aws:s3' + GROUP BY b.account_id, b.region, b.arn, b.name, b.tags, b._ctx; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_cloudtrail_trail - - aws_s3_bucket - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.11 Ensure that Object-level logging for read events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_3_2.yaml b/compliance/controls/aws/aws_cis_v130_3_2.yaml old mode 100755 new mode 100644 index 1b9cc6ab6..386f1e8cf --- a/compliance/controls/aws/aws_cis_v130_3_2.yaml +++ b/compliance/controls/aws/aws_cis_v130_3_2.yaml @@ -1,30 +1,30 @@ +Description: CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails. ID: aws_cis_v130_3_2 -Title: "3.2 Ensure CloudTrail log file validation is enabled." -Description: "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_file_validation_enabled then 'ok' - else 'alarm' - end as status, - case - when log_file_validation_enabled then title || ' log file validation enabled.' - else title || ' log file validation disabled.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_file_validation_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_file_validation_enabled THEN title || ' log file validation enabled.' + ELSE title || ' log file validation disabled.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.2 Ensure CloudTrail log file validation is enabled. \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_3_3.yaml b/compliance/controls/aws/aws_cis_v130_3_3.yaml old mode 100755 new mode 100644 index 80844d4bd..fb8bb424d --- a/compliance/controls/aws/aws_cis_v130_3_3.yaml +++ b/compliance/controls/aws/aws_cis_v130_3_3.yaml @@ -1,15 +1,67 @@ +Description: CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs. ID: aws_cis_v130_3_3 -Title: "3.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible" -Description: "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with public_bucket_data as (\n-- note the counts are not exactly CORRECT because of the jsonb_array_elements joins,\n-- but will be non-zero if any matches are found\nselect\n t.s3_bucket_name as name,\n b.arn,\n t.region,\n t.account_id,\n t.tags,\n t._ctx,\n count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AllUsers') as all_user_grants,\n count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AuthenticatedUsers') as auth_user_grants,\n count(s) filter (where s ->> 'Effect' = 'Allow' and p = '*' ) as anon_statements\nfrom\n aws_cloudtrail_trail as t\nleft join aws_s3_bucket as b on t.s3_bucket_name = b.name\nleft join jsonb_array_elements(acl -> 'Grants') as acl_grant on true\nleft join jsonb_array_elements(policy_std -> 'Statement') as s on true\nleft join jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p on true\ngroup by\n t.s3_bucket_name,\n b.arn,\n t.region,\n t.account_id,\n t.tags,\n t._ctx\n)\nselect\n case\n when arn is null then 'arn:aws:s3::' || name\n else arn\n end as resource,\n t.og_account_id as og_account_id,\n t.og_resource_id as og_resource_id,\n case\n when arn is null then 'skip'\n when all_user_grants > 0 then 'alarm'\n when auth_user_grants > 0 then 'alarm'\n when anon_statements > 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when arn is null then name || ' not found in account ' || account_id || '.'\n when all_user_grants > 0 then name || ' grants access to AllUsers in ACL.'\n when auth_user_grants > 0 then name || ' grants access to AuthenticatedUsers in ACL.'\n when anon_statements > 0 then name || ' grants access to AWS:*\" in bucket policy.'\n else name || ' does not grant anonymous access in ACL or bucket policy.'\n end as reason\n \n \nfrom\n public_bucket_data;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH public_bucket_data AS ( + SELECT + t.s3_bucket_name AS name, + b.arn, + t.region, + t.account_id, + t.tags, + t._ctx, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AllUsers') AS all_user_grants, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AuthenticatedUsers') AS auth_user_grants, + COUNT(s) FILTER (WHERE s ->> 'Effect' = 'Allow' AND p = '*') AS anon_statements + FROM + aws_cloudtrail_trail AS t + LEFT JOIN aws_s3_bucket AS b + ON t.s3_bucket_name = b.name + LEFT JOIN jsonb_array_elements(acl -> 'Grants') AS acl_grant + ON TRUE + LEFT JOIN jsonb_array_elements(policy_std -> 'Statement') AS s + ON TRUE + LEFT JOIN jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p + ON TRUE + GROUP BY + t.s3_bucket_name, + b.arn, + t.region, + t.account_id, + t.tags, + t._ctx + ) + SELECT + CASE + WHEN arn IS NULL THEN 'arn:aws:s3::' || name + ELSE arn + END AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN arn IS NULL THEN 'skip' + WHEN all_user_grants > 0 THEN 'alarm' + WHEN auth_user_grants > 0 THEN 'alarm' + WHEN anon_statements > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN arn IS NULL THEN name || ' not found in account ' || account_id || '.' + WHEN all_user_grants > 0 THEN name || ' grants access to AllUsers in ACL.' + WHEN auth_user_grants > 0 THEN name || ' grants access to AuthenticatedUsers in ACL.' + WHEN anon_statements > 0 THEN name || ' grants access to AWS:*" in bucket policy.' + ELSE name || ' does not grant anonymous access in ACL or bucket policy.' + END AS reason + FROM + public_bucket_data; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_3_4.yaml b/compliance/controls/aws/aws_cis_v130_3_4.yaml old mode 100755 new mode 100644 index a98f6974e..db5b503fc --- a/compliance/controls/aws/aws_cis_v130_3_4.yaml +++ b/compliance/controls/aws/aws_cis_v130_3_4.yaml @@ -1,30 +1,30 @@ +Description: AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs. ID: aws_cis_v130_3_4 -Title: "3.4 Ensure CloudTrail trails are integrated with CloudWatch Logs" -Description: "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then 'ok' - else 'alarm' - end as status, - case - when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then title || ' integrated with CloudWatch logs.' - else title || ' not integrated with CloudWatch logs.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > CURRENT_DATE - 1) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > CURRENT_DATE - 1) THEN title || ' integrated with CloudWatch logs.' + ELSE title || ' not integrated with CloudWatch logs.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.4 Ensure CloudTrail trails are integrated with CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_3_5.yaml b/compliance/controls/aws/aws_cis_v130_3_5.yaml old mode 100755 new mode 100644 index 968699ca8..31b6d58a9 --- a/compliance/controls/aws/aws_cis_v130_3_5.yaml +++ b/compliance/controls/aws/aws_cis_v130_3_5.yaml @@ -1,15 +1,70 @@ +Description: AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended to enable AWS Config in all regions. ID: aws_cis_v130_3_5 -Title: "3.5 Ensure AWS Config is enabled in all regions" -Description: "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended to enable AWS Config be enabled in all regions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "-- pgFormatter-ignore\n-- Get count for any region with all matching criteria\nwith global_recorders as (\n select\n count(*) as global_config_recorders\n from\n aws_config_configuration_recorder\n where\n recording_group -> 'IncludeGlobalResourceTypes' = 'true'\n and recording_group -> 'AllSupported' = 'true'\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n)\nselect\n 'arn:aws::' || a.region || ':' || a.account_id as resource,\na.og_account_id as og_account_id,\na.og_resource_id as og_resource_id,\n case\n -- When any of the region satisfies with above CTE\n -- In left join of table, regions now having\n -- 'Recording' and 'LastStatus' matching criteria can be considered as OK\n when\n g.global_config_recorders >= 1\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n then 'ok'\n -- Skip any regions that are disabled in the account.\n when a.opt_in_status = 'not-opted-in' then 'skip'\n else 'alarm'\n end as status,\n -- Below cases are for citing respective reasons for control state\n case\n when a.opt_in_status = 'not-opted-in' then a.region || ' region is disabled.'\n else\n case\n when recording_group -> 'IncludeGlobalResourceTypes' = 'true' then a.region || ' IncludeGlobalResourceTypes enabled,'\n else a.region || ' IncludeGlobalResourceTypes disabled,'\n end ||\n case\n when recording_group -> 'AllSupported' = 'true' then ' AllSupported enabled,'\n else ' AllSupported disabled,'\n end ||\n case\n when status ->> 'Recording' = 'true' then ' Recording enabled'\n else ' Recording disabled'\n end ||\n case\n when status ->> 'LastStatus' = 'SUCCESS' then ' and LastStatus is SUCCESS.'\n else ' and LastStatus is not SUCCESS.'\n end\n end as reason\n \nfrom\n global_recorders as g,\n aws_region as a\n left join aws_config_configuration_recorder as r on r.account_id = a.account_id and r.region = a.name;" - PrimaryTable: aws_config_configuration_recorder ListOfTables: - aws_config_configuration_recorder - aws_region Parameters: [] + PrimaryTable: aws_config_configuration_recorder + QueryToExecute: | + WITH global_recorders AS ( + SELECT + COUNT(*) AS global_config_recorders + FROM + aws_config_configuration_recorder + WHERE + recording_group -> 'IncludeGlobalResourceTypes' = 'true' + AND recording_group -> 'AllSupported' = 'true' + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + ) + SELECT + 'arn:aws::' || a.region || ':' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN g.global_config_recorders >= 1 + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + THEN 'ok' + WHEN a.opt_in_status = 'not-opted-in' + THEN 'skip' + ELSE 'alarm' + END AS status, + CASE + WHEN a.opt_in_status = 'not-opted-in' + THEN a.region || ' region is disabled.' + ELSE + CASE + WHEN recording_group -> 'IncludeGlobalResourceTypes' = 'true' + THEN a.region || ' IncludeGlobalResourceTypes enabled,' + ELSE a.region || ' IncludeGlobalResourceTypes disabled,' + END || + CASE + WHEN recording_group -> 'AllSupported' = 'true' + THEN ' AllSupported enabled,' + ELSE ' AllSupported disabled,' + END || + CASE + WHEN status ->> 'Recording' = 'true' + THEN ' Recording enabled' + ELSE ' Recording disabled' + END || + CASE + WHEN status ->> 'LastStatus' = 'SUCCESS' + THEN ' and LastStatus is SUCCESS.' + ELSE ' and LastStatus is not SUCCESS.' + END + END AS reason + FROM + global_recorders AS g, + aws_region AS a + LEFT JOIN aws_config_configuration_recorder AS r + ON r.account_id = a.account_id + AND r.region = a.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.5 Ensure AWS Config is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_3_6.yaml b/compliance/controls/aws/aws_cis_v130_3_6.yaml old mode 100755 new mode 100644 index 1960198ae..65d2b4416 --- a/compliance/controls/aws/aws_cis_v130_3_6.yaml +++ b/compliance/controls/aws/aws_cis_v130_3_6.yaml @@ -1,32 +1,32 @@ +Description: S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket. ID: aws_cis_v130_3_6 -Title: "3.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket" -Description: "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - t.arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when b.logging is not null then 'ok' - else 'alarm' - end as status, - case - when b.logging is not null then t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' - else t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' - end as reason - from - aws_cloudtrail_trail t - inner join aws_s3_bucket b on t.s3_bucket_name = b.name - where - t.region = t.home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN b.logging IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.logging IS NOT NULL THEN t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' + ELSE t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' + END AS reason + FROM + aws_cloudtrail_trail t + INNER JOIN aws_s3_bucket b ON t.s3_bucket_name = b.name + WHERE + t.region = t.home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_3_7.yaml b/compliance/controls/aws/aws_cis_v130_3_7.yaml old mode 100755 new mode 100644 index 070235895..73957e87b --- a/compliance/controls/aws/aws_cis_v130_3_7.yaml +++ b/compliance/controls/aws/aws_cis_v130_3_7.yaml @@ -1,30 +1,30 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS. ID: aws_cis_v130_3_7 -Title: "3.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs" -Description: "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when kms_key_id is null then 'alarm' - else 'ok' - end as status, - case - when kms_key_id is null then title || ' logs are not encrypted at rest.' - else title || ' logs are encrypted at rest.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' logs are not encrypted at rest.' + ELSE title || ' logs are encrypted at rest.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_3_8.yaml b/compliance/controls/aws/aws_cis_v130_3_8.yaml old mode 100755 new mode 100644 index c256f8400..a476ddcb6 --- a/compliance/controls/aws/aws_cis_v130_3_8.yaml +++ b/compliance/controls/aws/aws_cis_v130_3_8.yaml @@ -1,36 +1,36 @@ +Description: AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled. ID: aws_cis_v130_3_8 -Title: "3.8 Ensure rotation for customer created CMKs is enabled" -Description: "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when origin = 'EXTERNAL' then 'skip' - when key_state = 'PendingDeletion' then 'skip' - when key_state = 'Disabled' then 'skip' - when not key_rotation_enabled then 'alarm' - else 'ok' - end as status, - case - when origin = 'EXTERNAL' then title || ' has imported key material.' - when key_state = 'PendingDeletion' then title || ' is pending deletion.' - when key_state = 'Disabled' then title || ' is disabled.' - when not key_rotation_enabled then title || ' key rotation disabled.' - else title || ' key rotation enabled.' - end as reason - from - aws_kms_key - where - key_manager = 'CUSTOMER'; - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN origin = 'EXTERNAL' THEN 'skip' + WHEN key_state = 'PendingDeletion' THEN 'skip' + WHEN key_state = 'Disabled' THEN 'skip' + WHEN NOT key_rotation_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN origin = 'EXTERNAL' THEN title || ' has imported key material.' + WHEN key_state = 'PendingDeletion' THEN title || ' is pending deletion.' + WHEN key_state = 'Disabled' THEN title || ' is disabled.' + WHEN NOT key_rotation_enabled THEN title || ' key rotation disabled.' + ELSE title || ' key rotation enabled.' + END AS reason + FROM + aws_kms_key + WHERE + key_manager = 'CUSTOMER'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.8 Ensure rotation for customer created CMKs is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_4_13.yaml b/compliance/controls/aws/aws_cis_v130_4_13.yaml old mode 100755 new mode 100644 index 81194dd38..26b7ffed0 --- a/compliance/controls/aws/aws_cis_v130_4_13.yaml +++ b/compliance/controls/aws/aws_cis_v130_4_13.yaml @@ -1,96 +1,102 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables. ID: aws_cis_v130_4_13 -Title: "4.13 Ensure a log metric filter and alarm exist for route table changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where - filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*ReplaceRoute.+\$\.eventName\s*=\s*ReplaceRouteTableAssociation.+\$\.eventName\s*=\s*DeleteRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable' - order by + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateRoute\s+' + || '\$\.eventName\s*=\s*CreateRouteTable\s+' + || '\$\.eventName\s*=\s*ReplaceRoute\s+' + || '\$\.eventName\s*=\s*ReplaceRouteTableAssociation\s+' + || '\$\.eventName\s*=\s*DeleteRouteTable\s+' + || '\$\.eventName\s*=\s*DeleteRoute\s+' + || '\$\.eventName\s*=\s*DisassociateRouteTable' + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for route table changes.' - else filter_name || ' forwards events for route table changes.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for route table changes.' + ELSE filter_name || ' forwards events for route table changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.13 Ensure a log metric filter and alarm exist for route table changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_4_3.yaml b/compliance/controls/aws/aws_cis_v130_4_3.yaml old mode 100755 new mode 100644 index e9e0f0072..9c98ce57a --- a/compliance/controls/aws/aws_cis_v130_4_3.yaml +++ b/compliance/controls/aws/aws_cis_v130_4_3.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for root login attempts. ID: aws_cis_v130_4_3 -Title: "4.3 Ensure a log metric filter and alarm exist for usage of \\\"root\\\" account" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for root login attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.userIdentity\.type\s*=\s*"Root".+\$\.userIdentity\.invokedBy NOT EXISTS.+\$\.eventType\s*!=\s*"AwsServiceEvent"' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - f.og_account_id as og_account_id, - f.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for usage of "root" account.' - else filter_name || ' forwards events for usage of "root" account.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for usage of "root" account.' + ELSE filter_name || ' forwards events for usage of "root" account.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.3 Ensure a log metric filter and alarm exist for usage of "root" account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_4_8.yaml b/compliance/controls/aws/aws_cis_v130_4_8.yaml old mode 100755 new mode 100644 index 19053ad7f..8b09aabe0 --- a/compliance/controls/aws/aws_cis_v130_4_8.yaml +++ b/compliance/controls/aws/aws_cis_v130_4_8.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies. ID: aws_cis_v130_4_8 -Title: "4.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*s3.amazonaws.com.+\$\.eventName\s*=\s*PutBucketAcl.+\$\.eventName\s*=\s*PutBucketPolicy.+\$\.eventName\s*=\s*PutBucketCors.+\$\.eventName\s*=\s*PutBucketLifecycle.+\$\.eventName\s*=\s*PutBucketReplication.+\$\.eventName\s*=\s*DeleteBucketPolicy.+\$\.eventName\s*=\s*DeleteBucketCors.+\$\.eventName\s*=\s*DeleteBucketLifecycle.+\$\.eventName\s*=\s*DeleteBucketReplication' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - f.og_account_id as og_account_id, - f.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for S3 bucket policy changes.' - else filter_name || ' forwards events for S3 bucket policy changes.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for S3 bucket policy changes.' + ELSE filter_name || ' forwards events for S3 bucket policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_5_2.yaml b/compliance/controls/aws/aws_cis_v130_5_2.yaml old mode 100755 new mode 100644 index 66d34b499..3216ba90a --- a/compliance/controls/aws/aws_cis_v130_5_2.yaml +++ b/compliance/controls/aws/aws_cis_v130_5_2.yaml @@ -1,58 +1,57 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_cis_v130_5_2 -Title: "5.2 Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT group_id, - count(*) as num_bad_rules - from + COUNT(*) AS num_bad_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and ( + AND ( cidr_ipv4 = '0.0.0.0/0' - or cidr_ipv6 = '::/0' + OR cidr_ipv6 = '::/0' ) - and ( - ( ip_protocol = '-1' -- all traffic - and from_port is null - ) - or ( - from_port >= 22 - and to_port <= 22 - ) - or ( - from_port >= 3389 - and to_port <= 3389 - ) + AND ( + (ip_protocol = '-1' + AND from_port IS NULL) + OR ( + from_port >= 22 + AND to_port <= 22 + ) + OR ( + from_port >= 3389 + AND to_port <= 3389 + ) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when bad_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - end as reason - from - aws_vpc_security_group as sg - left join bad_rules on bad_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.2 Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v130_5_4.yaml b/compliance/controls/aws/aws_cis_v130_5_4.yaml old mode 100755 new mode 100644 index ace127c6e..4fd833a8d --- a/compliance/controls/aws/aws_cis_v130_5_4.yaml +++ b/compliance/controls/aws/aws_cis_v130_5_4.yaml @@ -1,14 +1,22 @@ +Description: A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. ID: aws_cis_v130_5_4 -Title: "5.4 Ensure routing tables for VPC peering are 'least access'" -Description: "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.4 Ensure routing tables for VPC peering are 'least access' \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_1.yaml b/compliance/controls/aws/aws_cis_v140_1_1.yaml old mode 100755 new mode 100644 index b7befb806..763ba7c02 --- a/compliance/controls/aws/aws_cis_v140_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_1.yaml @@ -1,14 +1,22 @@ +Description: Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. ID: aws_cis_v140_1_1 -Title: "1.1 Maintain current contact details" -Description: "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.1 Maintain current contact details \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_10.yaml b/compliance/controls/aws/aws_cis_v140_1_10.yaml old mode 100755 new mode 100644 index ea2410143..d69ca81bf --- a/compliance/controls/aws/aws_cis_v140_1_10.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_10.yaml @@ -1,14 +1,29 @@ +Description: Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password. ID: aws_cis_v140_1_10 -Title: "1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password" -Description: "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when password_enabled and not mfa_active then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then user_name || ' password login disabled.'\n when password_enabled and not mfa_active then user_name || ' password login enabled but no MFA device configured.'\n else user_name || ' password login enabled and MFA device configured.'\n end as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND NOT mfa_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN password_enabled AND NOT mfa_active THEN user_name || ' password login enabled but no MFA device configured.' + ELSE user_name || ' password login enabled and MFA device configured.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_11.yaml b/compliance/controls/aws/aws_cis_v140_1_11.yaml old mode 100755 new mode 100644 index 360911e55..1c933dd14 --- a/compliance/controls/aws/aws_cis_v140_1_11.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_11.yaml @@ -1,14 +1,36 @@ +Description: AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require. ID: aws_cis_v140_1_11 -Title: "1.11 Do not setup access keys during initial user setup for all IAM users that have a console password" -Description: "AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n -- alarm when password is enabled and the key was created within 10 seconds of the user\n when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then user_name || ' password login disabled.'\n when access_key_1_last_rotated is null then user_name || ' has no access keys.'\n when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10)\n then user_name || ' has access key created during user creation and password login enabled.'\n else user_name || ' has access key not created during user creation.'\n end as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled + AND (EXTRACT(EPOCH FROM (access_key_1_last_rotated - user_creation_time)) < 10) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled + THEN user_name || ' password login disabled.' + WHEN access_key_1_last_rotated IS NULL + THEN user_name || ' has no access keys.' + WHEN password_enabled + AND (EXTRACT(EPOCH FROM (access_key_1_last_rotated - user_creation_time)) < 10) + THEN user_name || ' has access key created during user creation and password login enabled.' + ELSE user_name || ' has access key not created during user creation.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.11 Do not setup access keys during initial user setup for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_12.yaml b/compliance/controls/aws/aws_cis_v140_1_12.yaml old mode 100755 new mode 100644 index e18d5ec97..bcdb7312b --- a/compliance/controls/aws/aws_cis_v140_1_12.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_12.yaml @@ -1,14 +1,46 @@ +Description: AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed. ID: aws_cis_v140_1_12 -Title: "1.12 Ensure credentials unused for 45 days or greater are disabled" -Description: "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n --root_account will have always password associated even though AWS credential report returns 'not_supported' for password_enabled\n when user_name = ''\n then 'info'\n when password_enabled and password_last_used is null and password_last_changed < (current_date - interval '45' day)\n then 'alarm'\n when password_enabled and password_last_used < (current_date - interval '45' day)\n then 'alarm'\n when access_key_1_active and access_key_1_last_used_date is null and access_key_1_last_rotated < (current_date - interval '45' day)\n then 'alarm'\n when access_key_1_active and access_key_1_last_used_date < (current_date - interval '45' day)\n then 'alarm'\n when access_key_2_active and access_key_2_last_used_date is null and access_key_2_last_rotated < (current_date - interval '45' day)\n then 'alarm'\n when access_key_2_active and access_key_2_last_used_date < (current_date - interval '45' day)\n then 'alarm'\n else 'ok'\n end status,\n user_name ||\n case\n when not password_enabled\n then ' password not enabled,'\n when password_enabled and password_last_used is null\n then ' password created ' || to_char(password_last_changed, 'DD-Mon-YYYY') || ' never used,'\n else\n ' password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_1_active\n then ' key 1 not enabled,'\n when access_key_1_active and access_key_1_last_used_date is null\n then ' key 1 created ' || to_char(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,'\n else\n ' key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_2_active\n then ' key 2 not enabled.'\n when access_key_2_active and access_key_2_last_used_date is null\n then ' key 2 created ' || to_char(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.'\n else\n ' key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.'\n end\n as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_name = '' THEN 'info' + WHEN password_enabled AND password_last_used IS NULL AND password_last_changed < (CURRENT_DATE - INTERVAL '45' DAY) THEN 'alarm' + WHEN password_enabled AND password_last_used < (CURRENT_DATE - INTERVAL '45' DAY) THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL AND access_key_1_last_rotated < (CURRENT_DATE - INTERVAL '45' DAY) THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date < (CURRENT_DATE - INTERVAL '45' DAY) THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL AND access_key_2_last_rotated < (CURRENT_DATE - INTERVAL '45' DAY) THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date < (CURRENT_DATE - INTERVAL '45' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || + CASE + WHEN NOT password_enabled THEN ' password not enabled,' + WHEN password_enabled AND password_last_used IS NULL THEN ' password created ' || TO_CHAR(password_last_changed, 'DD-Mon-YYYY') || ' never used,' + ELSE ' password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_1_active THEN ' key 1 not enabled,' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL THEN ' key 1 created ' || TO_CHAR(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' + ELSE ' key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_2_active THEN ' key 2 not enabled.' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL THEN ' key 2 created ' || TO_CHAR(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' + ELSE ' key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.12 Ensure credentials unused for 45 days or greater are disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_13.yaml b/compliance/controls/aws/aws_cis_v140_1_13.yaml old mode 100755 new mode 100644 index fe3684caa..9b2c2f025 --- a/compliance/controls/aws/aws_cis_v140_1_13.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_13.yaml @@ -1,24 +1,33 @@ +Description: Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK). ID: aws_cis_v140_1_13 -Title: "1.13 Ensure there is only one active access key available for any single IAM user" -Description: "Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - u.arn as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when count(k.*) > 1 then 'alarm' - else 'ok' - end as status, - u.name || ' has ' || count(k.*) || ' active access key(s).' as reason - from - aws_iam_user as u - left join aws_iam_access_key as k on u.name = k.user_name and u.account_id = k.account_id - where - k.status = 'Active' or k.status is null - group by + ListOfTables: + - aws_iam_user + - aws_iam_access_key + Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + u.arn AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(k.*) > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + u.name || ' has ' || COUNT(k.*) || ' active access key(s).' AS reason + FROM + aws_iam_user AS u + LEFT JOIN + aws_iam_access_key AS k + ON u.name = k.user_name + AND u.account_id = k.account_id + WHERE + k.status = 'Active' OR k.status IS NULL + GROUP BY u.arn, u.name, u.account_id, @@ -26,12 +35,6 @@ Query: u._ctx, u.og_account_id, u.og_resource_id; - PrimaryTable: aws_iam_user - ListOfTables: - - aws_iam_user - - aws_iam_access_key - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.13 Ensure there is only one active access key available for any single IAM user \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_14.yaml b/compliance/controls/aws/aws_cis_v140_1_14.yaml old mode 100755 new mode 100644 index e1ac4a6fd..71f52ddb7 --- a/compliance/controls/aws/aws_cis_v140_1_14.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_14.yaml @@ -1,14 +1,26 @@ +Description: Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated. ID: aws_cis_v140_1_14 -Title: "1.14 Ensure access keys are rotated every 90 days or less" -Description: "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when create_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end status,\n user_name || ' ' || access_key_id || ' created ' || to_char(create_date , 'DD-Mon-YYYY') ||\n ' (' || extract(day from current_timestamp - create_date) || ' days).'\n as reason\n \nfrom\n aws_iam_access_key;" - PrimaryTable: aws_iam_access_key ListOfTables: - aws_iam_access_key Parameters: [] + PrimaryTable: aws_iam_access_key + QueryToExecute: | + SELECT + 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || ' ' || access_key_id || ' created ' || TO_CHAR(create_date , 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM current_timestamp - create_date) || ' days).' AS reason + FROM + aws_iam_access_key; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.14 Ensure access keys are rotated every 90 days or less \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_15.yaml b/compliance/controls/aws/aws_cis_v140_1_15.yaml old mode 100755 new mode 100644 index f3bec7236..20ada386f --- a/compliance/controls/aws/aws_cis_v140_1_15.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_15.yaml @@ -1,14 +1,26 @@ +Description: 'IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended.' ID: aws_cis_v140_1_15 -Title: "1.15 Ensure IAM Users Receive Permissions Only Through Groups" -Description: "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when inline_policies is null and attached_policy_arns is null then 'ok'\n else 'alarm'\n end status,\n name || ' has ' || coalesce(jsonb_array_length(inline_policies),0) || ' inline and ' ||\n coalesce(jsonb_array_length(attached_policy_arns),0) || ' directly attached policies.' as reason\n \n \nfrom\n aws_iam_user;" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN inline_policies IS NULL AND attached_policy_arns IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' has ' || COALESCE(jsonb_array_length(inline_policies), 0) || ' inline and ' || + COALESCE(jsonb_array_length(attached_policy_arns), 0) || ' directly attached policies.' AS reason + FROM + aws_iam_user; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.15 Ensure IAM Users Receive Permissions Only Through Groups \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_16.yaml b/compliance/controls/aws/aws_cis_v140_1_16.yaml old mode 100755 new mode 100644 index 82b499d16..e0140ba06 --- a/compliance/controls/aws/aws_cis_v140_1_16.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_16.yaml @@ -1,55 +1,54 @@ +Description: IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges. ID: aws_cis_v140_1_16 -Title: "1.16 Ensure IAM policies that allow full \\\"*:*\\\" administrative privileges are not attached" -Description: "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with star_access_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH star_access_policies AS ( + SELECT arn, is_aws_managed, - count(*) as num_bad_statements - from + COUNT(*) AS num_bad_statements + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - (action = '*' - or action = '*:*' - ) + AND resource = '*' + AND ( + action = '*' + OR action = '*:*' ) - and is_attached - group by + AND is_attached + GROUP BY arn, is_aws_managed ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when s.arn is not null and s.is_aws_managed then 'info' - when s.arn is null then 'ok' - else 'alarm' - end status, - case - when s.arn is not null and s.is_aws_managed then p.name || ' is an AWS managed policy with ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - else p.name || ' contains ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - end as reason - from - aws_iam_policy as p - left join star_access_policies as s on p.arn = s.arn - where + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN 'info' + WHEN s.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN p.name || ' is an AWS managed policy with ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + ELSE p.name || ' contains ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + END AS reason + FROM + aws_iam_policy AS p + LEFT JOIN star_access_policies AS s ON p.arn = s.arn + WHERE p.is_attached; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.16 Ensure IAM policies that allow full "*:*" administrative privileges are not attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_17.yaml b/compliance/controls/aws/aws_cis_v140_1_17.yaml old mode 100755 new mode 100644 index b259270f8..1a9911738 --- a/compliance/controls/aws/aws_cis_v140_1_17.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_17.yaml @@ -1,54 +1,52 @@ +Description: AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support. ID: aws_cis_v140_1_17 -Title: "1.17 Ensure a support role has been created to manage incidents with AWS Support" -Description: "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - -- pgFormatter-ignore - with support_role_count as - ( - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - count(policy_arn), + ListOfTables: + - aws_account + - aws_iam_role + Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH support_role_count AS ( + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + COUNT(policy_arn), a.account_id, a._ctx, a.og_account_id, a.og_resource_id - from - aws_account as a - left join aws_iam_role as r on r.account_id = a.account_id - left join jsonb_array_elements_text(attached_policy_arns) as policy_arn on true - where - split_part(policy_arn, '/', 2) = 'AWSSupportAccess' - or policy_arn is null - group by + FROM + aws_account AS a + LEFT JOIN aws_iam_role AS r ON r.account_id = a.account_id + LEFT JOIN jsonb_array_elements_text(attached_policy_arns) AS policy_arn ON TRUE + WHERE + SPLIT_PART(policy_arn, '/', 2) = 'AWSSupportAccess' + OR policy_arn IS NULL + GROUP BY a.account_id, a.partition, a._ctx, a.og_account_id, a.og_resource_id ) - select + SELECT resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when count > 0 then 'ok' - else 'alarm' - end as status, - case - when count = 1 then 'AWSSupportAccess policy attached to 1 role.' - when count > 1 then 'AWSSupportAccess policy attached to ' || count || ' roles.' - else 'AWSSupportAccess policy not attached to any role.' - end as reason - from + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN COUNT > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT = 1 THEN 'AWSSupportAccess policy attached to 1 role.' + WHEN COUNT > 1 THEN 'AWSSupportAccess policy attached to ' || COUNT || ' roles.' + ELSE 'AWSSupportAccess policy not attached to any role.' + END AS reason + FROM support_role_count; - PrimaryTable: aws_iam_role - ListOfTables: - - aws_account - - aws_iam_role - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.17 Ensure a support role has been created to manage incidents with AWS Support \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_18.yaml b/compliance/controls/aws/aws_cis_v140_1_18.yaml old mode 100755 new mode 100644 index 790e410d0..74e1325e9 --- a/compliance/controls/aws/aws_cis_v140_1_18.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_18.yaml @@ -1,14 +1,22 @@ +Description: AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. "AWS Access" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources. ID: aws_cis_v140_1_18 -Title: "1.18 Ensure IAM instance roles are used for AWS resource access from instances" -Description: "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \\\"AWS Access\\\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.18 Ensure IAM instance roles are used for AWS resource access from instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_19.yaml b/compliance/controls/aws/aws_cis_v140_1_19.yaml old mode 100755 new mode 100644 index 95b99924a..a1b966020 --- a/compliance/controls/aws/aws_cis_v140_1_19.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_19.yaml @@ -1,14 +1,30 @@ +Description: To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console. ID: aws_cis_v140_1_19 -Title: "1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed" -Description: "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case when expiration < (current_date - interval '1' second) then 'alarm'\n else 'ok'\n end as status,\n case when expiration < (current_date - interval '1' second) then\n name || ' expired ' || to_char(expiration, 'DD-Mon-YYYY') || '.'\n else\n name || ' valid until ' || to_char(expiration, 'DD-Mon-YYYY') || '.'\n end as reason\n \n \nfrom\n aws_iam_server_certificate;" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: [] + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN expiration < (current_date - INTERVAL '1' SECOND) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expiration < (current_date - INTERVAL '1' SECOND) THEN + name || ' expired ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + ELSE + name || ' valid until ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_iam_server_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_2.yaml b/compliance/controls/aws/aws_cis_v140_1_2.yaml old mode 100755 new mode 100644 index 7f8d7ae3b..1c4b6a67a --- a/compliance/controls/aws/aws_cis_v140_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_2.yaml @@ -1,15 +1,56 @@ +Description: AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided. ID: aws_cis_v140_1_2 -Title: "1.2 Ensure security contact information is registered" -Description: "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alternate_security_contact as (\n select\n name,\n account_id\n from\n aws_account_alternate_contact\n where\n contact_type = 'SECURITY'\n),\naccount as (\n select\n arn,\n partition,\n title,\n account_id,\n _ctx,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id\n from\n aws_account\n)\nselect\n arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.partition = 'aws-us-gov' then 'info'\n -- Name is a required field if setting a security contact\n when c.name is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.partition = 'aws-us-gov' then a.title || ' in GovCloud, manual verification required.'\n when c.name is not null then a.title || ' has security contact ' || c.name || ' registered.'\n else a.title || ' security contact not registered.'\n end as reason\n \nfrom\n account as a,\n alternate_security_contact as c\nwhere\n c.account_id = a.account_id;" - PrimaryTable: aws_account ListOfTables: - aws_account_alternate_contact - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH alternate_security_contact AS ( + SELECT + name, + account_id + FROM + aws_account_alternate_contact + WHERE + contact_type = 'SECURITY' + ), + account AS ( + SELECT + arn, + partition, + title, + account_id, + _ctx, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id + FROM + aws_account + ) + SELECT + arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.partition = 'aws-us-gov' THEN 'info' + -- Name is a required field if setting a security contact + WHEN c.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.partition = 'aws-us-gov' THEN a.title || ' in GovCloud, manual verification required.' + WHEN c.name IS NOT NULL THEN a.title || ' has security contact ' || c.name || ' registered.' + ELSE a.title || ' security contact not registered.' + END AS reason + FROM + account AS a, + alternate_security_contact AS c + WHERE + c.account_id = a.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.2 Ensure security contact information is registered \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_20.yaml b/compliance/controls/aws/aws_cis_v140_1_20.yaml old mode 100755 new mode 100644 index 22a0b5948..f7446dc10 --- a/compliance/controls/aws/aws_cis_v140_1_20.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_20.yaml @@ -1,33 +1,33 @@ +Description: Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region. ID: aws_cis_v140_1_20 -Title: "1.20 Ensure that IAM Access analyzer is enabled for all regions" -Description: "Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - -- Skip any regions that are disabled in the account. - when r.opt_in_status = 'not-opted-in' then 'skip' - when aa.arn is not null then 'ok' - else 'alarm' - end as status, - case - when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.' - when aa.arn is not null then aa.name || ' enabled in ' || r.region || '.' - else 'Access Analyzer not enabled in ' || r.region || '.' - end as reason - from - aws_region as r - left join aws_accessanalyzer_analyzer as aa on r.account_id = aa.account_id and r.region = aa.region; - PrimaryTable: aws_region ListOfTables: - aws_region - aws_accessanalyzer_analyzer Parameters: [] + PrimaryTable: aws_region + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN aa.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN aa.arn IS NOT NULL THEN aa.name || ' enabled in ' || r.region || '.' + ELSE 'Access Analyzer not enabled in ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN + aws_accessanalyzer_analyzer AS aa ON r.account_id = aa.account_id AND r.region = aa.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.20 Ensure that IAM Access analyzer is enabled for all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_21.yaml b/compliance/controls/aws/aws_cis_v140_1_21.yaml old mode 100755 new mode 100644 index 2161fcf68..7c2f997d5 --- a/compliance/controls/aws/aws_cis_v140_1_21.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_21.yaml @@ -1,14 +1,22 @@ +Description: In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provide via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations. ID: aws_cis_v140_1_21 -Title: "1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments" -Description: "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provide via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_3.yaml b/compliance/controls/aws/aws_cis_v140_1_3.yaml old mode 100755 new mode 100644 index 978209247..81d0e7548 --- a/compliance/controls/aws/aws_cis_v140_1_3.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_3.yaml @@ -1,14 +1,22 @@ +Description: The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established. ID: aws_cis_v140_1_3 -Title: "1.3 Ensure security questions are registered in the AWS account" -Description: "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.3 Ensure security questions are registered in the AWS account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_4.yaml b/compliance/controls/aws/aws_cis_v140_1_4.yaml old mode 100755 new mode 100644 index b3f5c7822..6186f4553 --- a/compliance/controls/aws/aws_cis_v140_1_4.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_4.yaml @@ -1,14 +1,28 @@ +Description: The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed. ID: aws_cis_v140_1_4 -Title: "1.4 Ensure no 'root' user account access key exists" -Description: "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_access_keys_present > 0 then 'alarm'\n else 'ok'\n end status,\n case\n when account_access_keys_present > 0 then 'Root user access keys exist.'\n else 'No root user access keys exist.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_access_keys_present > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN account_access_keys_present > 0 THEN 'Root user access keys exist.' + ELSE 'No root user access keys exist.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.4 Ensure no 'root' user account access key exists \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_5.yaml b/compliance/controls/aws/aws_cis_v140_1_5.yaml old mode 100755 new mode 100644 index 8b2d4e9b5..8dd8c33d4 --- a/compliance/controls/aws/aws_cis_v140_1_5.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_5.yaml @@ -1,14 +1,28 @@ +Description: The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. ID: aws_cis_v140_1_5 -Title: "1.5 Ensure MFA is enabled for the 'root' user account" -Description: "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_mfa_enabled then 'ok'\n else 'alarm'\n end status,\n case\n when account_mfa_enabled then 'MFA enabled for root account.'\n else 'MFA not enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_mfa_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN account_mfa_enabled THEN 'MFA enabled for root account.' + ELSE 'MFA not enabled for root account.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.5 Ensure MFA is enabled for the 'root' user account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_1_7.yaml b/compliance/controls/aws/aws_cis_v140_1_7.yaml old mode 100755 new mode 100644 index 08cb3a3ea..dddfbaf85 --- a/compliance/controls/aws/aws_cis_v140_1_7.yaml +++ b/compliance/controls/aws/aws_cis_v140_1_7.yaml @@ -1,14 +1,40 @@ +Description: With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks. ID: aws_cis_v140_1_7 -Title: "1.7 Eliminate use of the 'root' user for administrative and daily tasks" -Description: "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when password_last_used >= (current_date - interval '90' day) then 'alarm'\n when access_key_1_last_used_date <= (current_date - interval '90' day) then 'alarm'\n when access_key_2_last_used_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end as status,\n case\n when password_last_used is null then 'Root never logged in with password.'\n else 'Root password used ' || to_char(password_last_used , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - password_last_used) || ' days).'\n end ||\n case\n when access_key_1_last_used_date is null then ' Access Key 1 never used.'\n else ' Access Key 1 used ' || to_char(access_key_1_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_1_last_used_date) || ' days).'\n end ||\n case\n when access_key_2_last_used_date is null then ' Access Key 2 never used.'\n else ' Access Key 2 used ' || to_char(access_key_2_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_2_last_used_date) || ' days).'\n end as reason\n \nfrom\n aws_iam_credential_report\nwhere\n user_name = '';" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_last_used >= (current_date - INTERVAL '90' day) THEN 'alarm' + WHEN access_key_1_last_used_date <= (current_date - INTERVAL '90' day) THEN 'alarm' + WHEN access_key_2_last_used_date <= (current_date - INTERVAL '90' day) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN password_last_used IS NULL THEN 'Root never logged in with password.' + ELSE 'Root password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || ' (' || extract(day FROM current_timestamp - password_last_used) || ' days).' + END || + CASE + WHEN access_key_1_last_used_date IS NULL THEN ' Access Key 1 never used.' + ELSE ' Access Key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ' (' || extract(day FROM current_timestamp - access_key_1_last_used_date) || ' days).' + END || + CASE + WHEN access_key_2_last_used_date IS NULL THEN ' Access Key 2 never used.' + ELSE ' Access Key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || ' (' || extract(day FROM current_timestamp - access_key_2_last_used_date) || ' days).' + END AS reason + FROM + aws_iam_credential_report + WHERE + user_name = ''; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.7 Eliminate use of the 'root' user for administrative and daily tasks \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_2_1_1.yaml b/compliance/controls/aws/aws_cis_v140_2_1_1.yaml old mode 100755 new mode 100644 index ebf648859..f1861bf21 --- a/compliance/controls/aws/aws_cis_v140_2_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v140_2_1_1.yaml @@ -1,14 +1,28 @@ +Description: Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest. ID: aws_cis_v140_2_1_1 -Title: "2.1.1 Ensure all S3 buckets employ encryption-at-rest" -Description: "Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when server_side_encryption_configuration is not null then 'ok'\n else 'alarm'\n end status,\n case\n when server_side_encryption_configuration is not null then name || ' default encryption enabled.'\n else name || ' default encryption disabled.'\n end reason\n \n \nfrom\n aws_s3_bucket;" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN server_side_encryption_configuration IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN server_side_encryption_configuration IS NOT NULL THEN name || ' default encryption enabled.' + ELSE name || ' default encryption disabled.' + END AS reason + FROM + aws_s3_bucket; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.1 Ensure all S3 buckets employ encryption-at-rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_2_1_2.yaml b/compliance/controls/aws/aws_cis_v140_2_1_2.yaml old mode 100755 new mode 100644 index 6bdc41fe3..171c7999c --- a/compliance/controls/aws/aws_cis_v140_2_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v140_2_1_2.yaml @@ -1,49 +1,49 @@ +Description: At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS. ID: aws_cis_v140_2_1_2 -Title: "2.1.2 Ensure S3 Bucket Policy is set to deny HTTP requests" -Description: "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ssl_ok as ( - select - distinct name, + ListOfTables: + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH ssl_ok AS ( + SELECT + DISTINCT name, arn, - 'ok' as status - from + 'ok' AS status + FROM aws_s3_bucket, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p, - jsonb_array_elements_text(s -> 'Action') as a, - jsonb_array_elements_text(s -> 'Resource') as r, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + jsonb_array_elements_text(s -> 'Action') AS a, + jsonb_array_elements_text(s -> 'Resource') AS r, jsonb_array_elements_text( s -> 'Condition' -> 'Bool' -> 'aws:securetransport' - ) as ssl - where + ) AS ssl + WHERE p = '*' - and s ->> 'Effect' = 'Deny' - and ssl :: bool = false + AND s ->> 'Effect' = 'Deny' + AND ssl::bool = FALSE ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when ok.status = 'ok' then 'ok' - else 'alarm' - end status, - case - when ok.status = 'ok' then b.name || ' bucket policy enforces HTTPS.' - else b.name || ' bucket policy does not enforce HTTPS.' - end reason - from - aws_s3_bucket as b - left join ssl_ok as ok on ok.name = b.name; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_s3_bucket - Parameters: [] + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN ok.status = 'ok' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ok.status = 'ok' THEN b.name || ' bucket policy enforces HTTPS.' + ELSE b.name || ' bucket policy does not enforce HTTPS.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN ssl_ok AS ok ON ok.name = b.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.2 Ensure S3 Bucket Policy is set to deny HTTP requests \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_2_1_3.yaml b/compliance/controls/aws/aws_cis_v140_2_1_3.yaml old mode 100755 new mode 100644 index dde7f9cb4..89dbb21b3 --- a/compliance/controls/aws/aws_cis_v140_2_1_3.yaml +++ b/compliance/controls/aws/aws_cis_v140_2_1_3.yaml @@ -1,14 +1,28 @@ +Description: Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication. ID: aws_cis_v140_2_1_3 -Title: "2.1.3 Ensure MFA Delete is enabled on S3 buckets" -Description: "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when versioning_mfa_delete then 'ok'\n else 'alarm'\n end as status,\n case\n when versioning_mfa_delete then name || ' MFA delete enabled.'\n else name || ' MFA delete disabled.'\n end as reason\n \n \nfrom\n aws_s3_bucket;" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN versioning_mfa_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN versioning_mfa_delete THEN name || ' MFA delete enabled.' + ELSE name || ' MFA delete disabled.' + END AS reason + FROM + aws_s3_bucket; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.3 Ensure MFA Delete is enabled on S3 buckets \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_2_1_4.yaml b/compliance/controls/aws/aws_cis_v140_2_1_4.yaml old mode 100755 new mode 100644 index f3b71db10..bea45f848 --- a/compliance/controls/aws/aws_cis_v140_2_1_4.yaml +++ b/compliance/controls/aws/aws_cis_v140_2_1_4.yaml @@ -1,40 +1,43 @@ +Description: Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets. ID: aws_cis_v140_2_1_4 -Title: "2.1.4 Ensure all data in Amazon S3 has been discovered, classified and secured when required" -Description: "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bucket_list as ( - select - trim(b::text, '"' ) as bucket_name - from - aws_macie2_classification_job, - jsonb_array_elements(s3_job_definition -> 'BucketDefinitions') as d, - jsonb_array_elements(d -> 'Buckets') as b - ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when b.region = any(array['us-gov-east-1', 'us-gov-west-1']) then 'skip' - when l.bucket_name is not null then 'ok' - else 'alarm' - end as status, - case - when b.region = any(array['us-gov-east-1', 'us-gov-west-1']) then b.title || ' not protected by Macie as Macie is not supported in ' || b.region || '.' - when l.bucket_name is not null then b.title || ' protected by Macie.' - else b.title || ' not protected by Macie.' - end as reason - from - aws_s3_bucket as b - left join bucket_list as l on b.name = l.bucket_name; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_macie2_classification_job - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH bucket_list AS ( + SELECT + TRIM(b::TEXT, '"' ) AS bucket_name + FROM + aws_macie2_classification_job, + JSONB_ARRAY_ELEMENTS(s3_job_definition -> 'BucketDefinitions') AS d, + JSONB_ARRAY_ELEMENTS(d -> 'Buckets') AS b + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN b.region = ANY(ARRAY['us-gov-east-1', 'us-gov-west-1']) THEN 'skip' + WHEN l.bucket_name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.region = ANY(ARRAY['us-gov-east-1', 'us-gov-west-1']) THEN + b.title || ' not protected by Macie as Macie is not supported in ' || b.region || '.' + WHEN l.bucket_name IS NOT NULL THEN + b.title || ' protected by Macie.' + ELSE + b.title || ' not protected by Macie.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN bucket_list AS l ON b.name = l.bucket_name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.4 Ensure all data in Amazon S3 has been discovered, classified and secured when required \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_2_2_1.yaml b/compliance/controls/aws/aws_cis_v140_2_2_1.yaml old mode 100755 new mode 100644 index 3e18c5dce..9630679e7 --- a/compliance/controls/aws/aws_cis_v140_2_2_1.yaml +++ b/compliance/controls/aws/aws_cis_v140_2_2_1.yaml @@ -1,14 +1,28 @@ +Description: Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported. ID: aws_cis_v140_2_2_1 -Title: "2.2.1 Ensure EBS volume encryption is enabled" -Description: "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then volume_id || ' encrypted.'\n else volume_id || ' not encrypted.'\n end as reason\n \n \nfrom\n aws_ebs_volume;" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN volume_id || ' encrypted.' + ELSE volume_id || ' not encrypted.' + END AS reason + FROM + aws_ebs_volume; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.2.1 Ensure EBS volume encryption is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_2_3_1.yaml b/compliance/controls/aws/aws_cis_v140_2_3_1.yaml old mode 100755 new mode 100644 index dc7787211..d631f0127 --- a/compliance/controls/aws/aws_cis_v140_2_3_1.yaml +++ b/compliance/controls/aws/aws_cis_v140_2_3_1.yaml @@ -1,14 +1,28 @@ +Description: Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance. ID: aws_cis_v140_2_3_1 -Title: "2.3.1 Ensure that encryption is enabled for RDS Instances" -Description: "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_rds_db_instance;" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3.1 Ensure that encryption is enabled for RDS Instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_3_10.yaml b/compliance/controls/aws/aws_cis_v140_3_10.yaml old mode 100755 new mode 100644 index 5a43e9075..eb85f70ea --- a/compliance/controls/aws/aws_cis_v140_3_10.yaml +++ b/compliance/controls/aws/aws_cis_v140_3_10.yaml @@ -1,55 +1,51 @@ +Description: S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets. ID: aws_cis_v140_3_10 -Title: "3.10 Ensure that Object-level logging for write events is enabled for S3 bucket" -Description: "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with s3_selectors as - ( - select - name as trail_name, + ListOfTables: + - aws_cloudtrail_trail + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( + SELECT + name AS trail_name, is_multi_region_trail, bucket_selector - from + FROM aws_cloudtrail_trail, - jsonb_array_elements(event_selectors) as event_selector, - jsonb_array_elements(event_selector -> 'DataResources') as data_resource, - jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector - where + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE is_multi_region_trail - and data_resource ->> 'Type' = 'AWS::S3::Object' - and event_selector ->> 'ReadWriteType' in - ( - 'WriteOnly', - 'All' - ) + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ('WriteOnly', 'All') ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when count(bucket_selector) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(bucket_selector) > 0 then b.name || ' object-level write events logging enabled.' - else b.name || ' object-level write events logging disabled.' - end as reason - from - aws_s3_bucket as b - left join - s3_selectors - on bucket_selector like (b.arn || '%') - or bucket_selector = 'arn:aws:s3' - group by + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 + THEN b.name || ' object-level write events logging enabled.' + ELSE b.name || ' object-level write events logging disabled.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN + s3_selectors + ON bucket_selector LIKE (b.arn || '%') + OR bucket_selector = 'arn:aws:s3' + GROUP BY b.account_id, b.region, b.arn, b.name, b.tags, b._ctx; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_cloudtrail_trail - - aws_s3_bucket - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.10 Ensure that Object-level logging for write events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_3_11.yaml b/compliance/controls/aws/aws_cis_v140_3_11.yaml old mode 100755 new mode 100644 index a5c9758d3..4ec159816 --- a/compliance/controls/aws/aws_cis_v140_3_11.yaml +++ b/compliance/controls/aws/aws_cis_v140_3_11.yaml @@ -1,55 +1,50 @@ +Description: S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets. ID: aws_cis_v140_3_11 -Title: "3.11 Ensure that Object-level logging for read events is enabled for S3 bucket" -Description: "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with s3_selectors as - ( - select - name as trail_name, + ListOfTables: + - aws_cloudtrail_trail + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( + SELECT + name AS trail_name, is_multi_region_trail, bucket_selector - from + FROM aws_cloudtrail_trail, - jsonb_array_elements(event_selectors) as event_selector, - jsonb_array_elements(event_selector -> 'DataResources') as data_resource, - jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector - where + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE is_multi_region_trail - and data_resource ->> 'Type' = 'AWS::S3::Object' - and event_selector ->> 'ReadWriteType' in - ( - 'ReadOnly', - 'All' - ) + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ('ReadOnly', 'All') ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when count(bucket_selector) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(bucket_selector) > 0 then b.name || ' object-level read events logging enabled.' - else b.name || ' object-level read events logging disabled.' - end as reason - from - aws_s3_bucket as b - left join - s3_selectors - on bucket_selector like (b.arn || '%') - or bucket_selector = 'arn:aws:s3' - group by + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level read events logging enabled.' + ELSE b.name || ' object-level read events logging disabled.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN + s3_selectors + ON bucket_selector LIKE (b.arn || '%') + OR bucket_selector = 'arn:aws:s3' + GROUP BY b.account_id, b.region, b.arn, b.name, b.tags, b._ctx; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_cloudtrail_trail - - aws_s3_bucket - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.11 Ensure that Object-level logging for read events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_3_2.yaml b/compliance/controls/aws/aws_cis_v140_3_2.yaml old mode 100755 new mode 100644 index 9a42f17cd..a593aa288 --- a/compliance/controls/aws/aws_cis_v140_3_2.yaml +++ b/compliance/controls/aws/aws_cis_v140_3_2.yaml @@ -1,30 +1,30 @@ +Description: CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails. ID: aws_cis_v140_3_2 -Title: "3.2 Ensure CloudTrail log file validation is enabled" -Description: "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_file_validation_enabled then 'ok' - else 'alarm' - end as status, - case - when log_file_validation_enabled then title || ' log file validation enabled.' - else title || ' log file validation disabled.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_file_validation_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_file_validation_enabled THEN title || ' log file validation enabled.' + ELSE title || ' log file validation disabled.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.2 Ensure CloudTrail log file validation is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_3_3.yaml b/compliance/controls/aws/aws_cis_v140_3_3.yaml old mode 100755 new mode 100644 index 9d12ba21e..4b415aad8 --- a/compliance/controls/aws/aws_cis_v140_3_3.yaml +++ b/compliance/controls/aws/aws_cis_v140_3_3.yaml @@ -1,70 +1,67 @@ +Description: CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs. ID: aws_cis_v140_3_3 -Title: "3.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible" -Description: "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with public_bucket_data as ( - -- note the counts are not exactly CORRECT because of the jsonb_array_elements joins, - -- but will be non-zero if any matches are found - select - t.s3_bucket_name as name, - b.arn, - t.region, - t.account_id, - t.tags, - t._ctx, - t.og_account_id, - t.og_resource_id, - count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AllUsers') as all_user_grants, - count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AuthenticatedUsers') as auth_user_grants, - count(s) filter (where s ->> 'Effect' = 'Allow' and p = '*' ) as anon_statements - from - aws_cloudtrail_trail as t - left join aws_s3_bucket as b on t.s3_bucket_name = b.name - left join jsonb_array_elements(acl -> 'Grants') as acl_grant on true - left join jsonb_array_elements(policy_std -> 'Statement') as s on true - left join jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p on true - group by - t.s3_bucket_name, - b.arn, - t.region, - t.account_id, - t.tags, - t._ctx, - t.og_account_id, - t.og_resource_id - ) - select - case - when arn is null then 'arn:aws:s3::' || name - else arn - end as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when arn is null then 'skip' - when all_user_grants > 0 then 'alarm' - when auth_user_grants > 0 then 'alarm' - when anon_statements > 0 then 'alarm' - else 'ok' - end as status, - case - when arn is null then name || ' not found in account ' || account_id || '.' - when all_user_grants > 0 then name || ' grants access to AllUsers in ACL.' - when auth_user_grants > 0 then name || ' grants access to AuthenticatedUsers in ACL.' - when anon_statements > 0 then name || ' grants access to AWS:*" in bucket policy.' - else name || ' does not grant anonymous access in ACL or bucket policy.' - end as reason - - from - public_bucket_data; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH public_bucket_data AS ( + SELECT + t.s3_bucket_name AS name, + b.arn, + t.region, + t.account_id, + t.tags, + t._ctx, + t.og_account_id, + t.og_resource_id, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AllUsers') AS all_user_grants, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AuthenticatedUsers') AS auth_user_grants, + COUNT(s) FILTER (WHERE s ->> 'Effect' = 'Allow' AND p = '*') AS anon_statements + FROM + aws_cloudtrail_trail AS t + LEFT JOIN aws_s3_bucket AS b ON t.s3_bucket_name = b.name + LEFT JOIN jsonb_array_elements(acl -> 'Grants') AS acl_grant ON true + LEFT JOIN jsonb_array_elements(policy_std -> 'Statement') AS s ON true + LEFT JOIN jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p ON true + GROUP BY + t.s3_bucket_name, + b.arn, + t.region, + t.account_id, + t.tags, + t._ctx, + t.og_account_id, + t.og_resource_id + ) + SELECT + CASE + WHEN arn IS NULL THEN 'arn:aws:s3::' || name + ELSE arn + END AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN arn IS NULL THEN 'skip' + WHEN all_user_grants > 0 THEN 'alarm' + WHEN auth_user_grants > 0 THEN 'alarm' + WHEN anon_statements > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN arn IS NULL THEN name || ' not found in account ' || account_id || '.' + WHEN all_user_grants > 0 THEN name || ' grants access to AllUsers in ACL.' + WHEN auth_user_grants > 0 THEN name || ' grants access to AuthenticatedUsers in ACL.' + WHEN anon_statements > 0 THEN name || ' grants access to AWS:* in bucket policy.' + ELSE name || ' does not grant anonymous access in ACL or bucket policy.' + END AS reason + FROM + public_bucket_data; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_3_4.yaml b/compliance/controls/aws/aws_cis_v140_3_4.yaml old mode 100755 new mode 100644 index 94133a84a..adb855309 --- a/compliance/controls/aws/aws_cis_v140_3_4.yaml +++ b/compliance/controls/aws/aws_cis_v140_3_4.yaml @@ -1,30 +1,30 @@ +Description: AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs. ID: aws_cis_v140_3_4 -Title: "3.4 Ensure CloudTrail trails are integrated with CloudWatch Logs" -Description: "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then 'ok' - else 'alarm' - end as status, - case - when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then title || ' integrated with CloudWatch logs.' - else title || ' not integrated with CloudWatch logs.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > CURRENT_DATE - 1) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > CURRENT_DATE - 1) THEN title || ' integrated with CloudWatch logs.' + ELSE title || ' not integrated with CloudWatch logs.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.4 Ensure CloudTrail trails are integrated with CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_3_5.yaml b/compliance/controls/aws/aws_cis_v140_3_5.yaml old mode 100755 new mode 100644 index 00c419353..7a849ac17 --- a/compliance/controls/aws/aws_cis_v140_3_5.yaml +++ b/compliance/controls/aws/aws_cis_v140_3_5.yaml @@ -1,15 +1,68 @@ +Description: AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions. ID: aws_cis_v140_3_5 -Title: "3.5 Ensure AWS Config is enabled in all regions" -Description: "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "-- pgFormatter-ignore\n-- Get count for any region with all matching criteria\nwith global_recorders as (\n select\n count(*) as global_config_recorders\n from\n aws_config_configuration_recorder\n where\n recording_group -> 'IncludeGlobalResourceTypes' = 'true'\n and recording_group -> 'AllSupported' = 'true'\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n)\nselect\n 'arn:aws::' || a.region || ':' || a.account_id as resource,\na.og_account_id as og_account_id,\na.og_resource_id as og_resource_id,\n case\n -- When any of the region satisfies with above CTE\n -- In left join of table, regions now having\n -- 'Recording' and 'LastStatus' matching criteria can be considered as OK\n when\n g.global_config_recorders >= 1\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n then 'ok'\n -- Skip any regions that are disabled in the account.\n when a.opt_in_status = 'not-opted-in' then 'skip'\n else 'alarm'\n end as status,\n -- Below cases are for citing respective reasons for control state\n case\n when a.opt_in_status = 'not-opted-in' then a.region || ' region is disabled.'\n else\n case\n when recording_group -> 'IncludeGlobalResourceTypes' = 'true' then a.region || ' IncludeGlobalResourceTypes enabled,'\n else a.region || ' IncludeGlobalResourceTypes disabled,'\n end ||\n case\n when recording_group -> 'AllSupported' = 'true' then ' AllSupported enabled,'\n else ' AllSupported disabled,'\n end ||\n case\n when status ->> 'Recording' = 'true' then ' Recording enabled'\n else ' Recording disabled'\n end ||\n case\n when status ->> 'LastStatus' = 'SUCCESS' then ' and LastStatus is SUCCESS.'\n else ' and LastStatus is not SUCCESS.'\n end\n end as reason\n \nfrom\n global_recorders as g,\n aws_region as a\n left join aws_config_configuration_recorder as r on r.account_id = a.account_id and r.region = a.name;" - PrimaryTable: aws_region ListOfTables: - aws_config_configuration_recorder - aws_region Parameters: [] + PrimaryTable: aws_region + QueryToExecute: | + WITH global_recorders AS ( + SELECT + COUNT(*) AS global_config_recorders + FROM + aws_config_configuration_recorder + WHERE + recording_group -> 'IncludeGlobalResourceTypes' = 'true' + AND recording_group -> 'AllSupported' = 'true' + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + ) + SELECT + 'arn:aws::' || a.region || ':' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN + g.global_config_recorders >= 1 + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + THEN 'ok' + WHEN a.opt_in_status = 'not-opted-in' THEN 'skip' + ELSE 'alarm' + END AS status, + CASE + WHEN a.opt_in_status = 'not-opted-in' THEN a.region || ' region is disabled.' + ELSE + CASE + WHEN recording_group -> 'IncludeGlobalResourceTypes' = 'true' + THEN a.region || ' IncludeGlobalResourceTypes enabled,' + ELSE a.region || ' IncludeGlobalResourceTypes disabled,' + END || + CASE + WHEN recording_group -> 'AllSupported' = 'true' + THEN ' AllSupported enabled,' + ELSE ' AllSupported disabled,' + END || + CASE + WHEN status ->> 'Recording' = 'true' + THEN ' Recording enabled' + ELSE ' Recording disabled' + END || + CASE + WHEN status ->> 'LastStatus' = 'SUCCESS' + THEN ' and LastStatus is SUCCESS.' + ELSE ' and LastStatus is not SUCCESS.' + END + END AS reason + FROM + global_recorders AS g, + aws_region AS a + LEFT JOIN aws_config_configuration_recorder AS r + ON r.account_id = a.account_id AND r.region = a.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.5 Ensure AWS Config is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_3_6.yaml b/compliance/controls/aws/aws_cis_v140_3_6.yaml old mode 100755 new mode 100644 index ad92e6663..0422e7c00 --- a/compliance/controls/aws/aws_cis_v140_3_6.yaml +++ b/compliance/controls/aws/aws_cis_v140_3_6.yaml @@ -1,32 +1,34 @@ +Description: S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket. ID: aws_cis_v140_3_6 -Title: "3.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket" -Description: "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - t.arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when b.logging is not null then 'ok' - else 'alarm' - end as status, - case - when b.logging is not null then t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' - else t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' - end as reason - from - aws_cloudtrail_trail t - inner join aws_s3_bucket b on t.s3_bucket_name = b.name - where - t.region = t.home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN b.logging IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.logging IS NOT NULL + THEN t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' + ELSE t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' + END AS reason + FROM + aws_cloudtrail_trail t + INNER JOIN + aws_s3_bucket b ON t.s3_bucket_name = b.name + WHERE + t.region = t.home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_3_7.yaml b/compliance/controls/aws/aws_cis_v140_3_7.yaml old mode 100755 new mode 100644 index abddf6f97..f6e07fd07 --- a/compliance/controls/aws/aws_cis_v140_3_7.yaml +++ b/compliance/controls/aws/aws_cis_v140_3_7.yaml @@ -1,14 +1,30 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS. ID: aws_cis_v140_3_7 -Title: "3.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs" -Description: "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kms_key_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_key_id is null then title || ' logs are not encrypted at rest.'\n else title || ' logs are encrypted at rest.'\n end as reason\n \n \nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' logs are not encrypted at rest.' + ELSE title || ' logs are encrypted at rest.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_3_8.yaml b/compliance/controls/aws/aws_cis_v140_3_8.yaml old mode 100755 new mode 100644 index e51866514..19e855820 --- a/compliance/controls/aws/aws_cis_v140_3_8.yaml +++ b/compliance/controls/aws/aws_cis_v140_3_8.yaml @@ -1,36 +1,36 @@ +Description: AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled. ID: aws_cis_v140_3_8 -Title: "3.8 Ensure rotation for customer created CMKs is enabled" -Description: "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when origin = 'EXTERNAL' then 'skip' - when key_state = 'PendingDeletion' then 'skip' - when key_state = 'Disabled' then 'skip' - when not key_rotation_enabled then 'alarm' - else 'ok' - end as status, - case - when origin = 'EXTERNAL' then title || ' has imported key material.' - when key_state = 'PendingDeletion' then title || ' is pending deletion.' - when key_state = 'Disabled' then title || ' is disabled.' - when not key_rotation_enabled then title || ' key rotation disabled.' - else title || ' key rotation enabled.' - end as reason - from - aws_kms_key - where - key_manager = 'CUSTOMER'; - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN origin = 'EXTERNAL' THEN 'skip' + WHEN key_state = 'PendingDeletion' THEN 'skip' + WHEN key_state = 'Disabled' THEN 'skip' + WHEN NOT key_rotation_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN origin = 'EXTERNAL' THEN title || ' has imported key material.' + WHEN key_state = 'PendingDeletion' THEN title || ' is pending deletion.' + WHEN key_state = 'Disabled' THEN title || ' is disabled.' + WHEN NOT key_rotation_enabled THEN title || ' key rotation disabled.' + ELSE title || ' key rotation enabled.' + END AS reason + FROM + aws_kms_key + WHERE + key_manager = 'CUSTOMER'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.8 Ensure rotation for customer created CMKs is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_3_9.yaml b/compliance/controls/aws/aws_cis_v140_3_9.yaml old mode 100755 new mode 100644 index dacde29ee..9e6a2ad9f --- a/compliance/controls/aws/aws_cis_v140_3_9.yaml +++ b/compliance/controls/aws/aws_cis_v140_3_9.yaml @@ -1,11 +1,17 @@ +Description: VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet "Rejects" for VPCs. ID: aws_cis_v140_3_9 -Title: "3.9 Ensure VPC flow logging is enabled in all VPCs" -Description: "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \\\"Rejects\\\" for VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with vpcs as ( - select + ListOfTables: + - aws_vpc + - aws_vpc_flow_log + Parameters: [] + PrimaryTable: aws_vpc + QueryToExecute: | + WITH vpcs AS ( + SELECT arn, account_id, region, @@ -15,44 +21,38 @@ Query: _ctx, og_account_id, og_resource_id - from + FROM aws_vpc - order by + ORDER BY vpc_id ), - flowlogs as ( - select + flowlogs AS ( + SELECT resource_id, account_id, region - from + FROM aws_vpc_flow_log - order by + ORDER BY resource_id ) - select - v.arn as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when v.account_id <> v.owner_id then 'skip' - when f.resource_id is not null then 'ok' - else 'alarm' - end as status, - case - when v.account_id <> v.owner_id then v.vpc_id || ' is a shared VPC.' - when f.resource_id is not null then v.vpc_id || ' flow logging enabled.' - else v.vpc_id || ' flow logging disabled.' - end as reason - from - vpcs as v - left join flowlogs as f on v.vpc_id = f.resource_id; - PrimaryTable: aws_vpc - ListOfTables: - - aws_vpc - - aws_vpc_flow_log - Parameters: [] + SELECT + v.arn AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.account_id <> v.owner_id THEN 'skip' + WHEN f.resource_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.account_id <> v.owner_id THEN v.vpc_id || ' is a shared VPC.' + WHEN f.resource_id IS NOT NULL THEN v.vpc_id || ' flow logging enabled.' + ELSE v.vpc_id || ' flow logging disabled.' + END AS reason + FROM + vpcs AS v + LEFT JOIN flowlogs AS f ON v.vpc_id = f.resource_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.9 Ensure VPC flow logging is enabled in all VPCs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_4_14.yaml b/compliance/controls/aws/aws_cis_v140_4_14.yaml old mode 100755 new mode 100644 index 8f5012a05..ee229645c --- a/compliance/controls/aws/aws_cis_v140_4_14.yaml +++ b/compliance/controls/aws/aws_cis_v140_4_14.yaml @@ -1,96 +1,97 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs. ID: aws_cis_v140_4_14 -Title: "4.14 Ensure a log metric filter and alarm exist for VPC changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateVpc.+\$\.eventName\s*=\s*DeleteVpc.+\$\.eventName\s*=\s*ModifyVpcAttribute.+\$\.eventName\s*=\s*AcceptVpcPeeringConnection.+\$\.eventName\s*=\s*CreateVpcPeeringConnection.+\$\.eventName\s*=\s*DeleteVpcPeeringConnection.+\$\.eventName\s*=\s*RejectVpcPeeringConnection.+\$\.eventName\s*=\s*AttachClassicLinkVpc.+\$\.eventName\s*=\s*DetachClassicLinkVpc.+\$\.eventName\s*=\s*DisableVpcClassicLink.+\$\.eventName\s*=\s*EnableVpcClassicLink' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for VPC changes.' - else filter_name || ' forwards events for VPC changes.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for VPC changes.' + ELSE f.filter_name || ' forwards events for VPC changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.14 Ensure a log metric filter and alarm exist for VPC changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_4_5.yaml b/compliance/controls/aws/aws_cis_v140_4_5.yaml old mode 100755 new mode 100644 index 8ca70be90..90008a661 --- a/compliance/controls/aws/aws_cis_v140_4_5.yaml +++ b/compliance/controls/aws/aws_cis_v140_4_5.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations. ID: aws_cis_v140_4_5 -Title: "4.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateTrail.+\$\.eventName\s*=\s*UpdateTrail.+\$\.eventName\s*=\s*DeleteTrail.+\$\.eventName\s*=\s*StartLogging.+\$\.eventName\s*=\s*StopLogging' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for CloudTrail configuration changes.' - else filter_name || ' forwards events for CloudTrail configuration changes.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for CloudTrail configuration changes.' + ELSE filter_name || ' forwards events for CloudTrail configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_4_7.yaml b/compliance/controls/aws/aws_cis_v140_4_7.yaml old mode 100755 new mode 100644 index 4e0ddbf89..f4df6397b --- a/compliance/controls/aws/aws_cis_v140_4_7.yaml +++ b/compliance/controls/aws/aws_cis_v140_4_7.yaml @@ -1,96 +1,97 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. + It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion. ID: aws_cis_v140_4_7 -Title: "4.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*kms.amazonaws.com.+\$\.eventName\s*=\s*DisableKey.+\$\.eventName\s*=\s*ScheduleKeyDeletion' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for disabling/deletion of CMKs.' - else filter_name || ' forwards events for disabling/deletion of CMKs.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for disabling/deletion of CMKs.' + ELSE filter_name || ' forwards events for disabling/deletion of CMKs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_4_8.yaml b/compliance/controls/aws/aws_cis_v140_4_8.yaml old mode 100755 new mode 100644 index c675c6818..2331705fb --- a/compliance/controls/aws/aws_cis_v140_4_8.yaml +++ b/compliance/controls/aws/aws_cis_v140_4_8.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies. ID: aws_cis_v140_4_8 -Title: "4.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*s3.amazonaws.com.+\$\.eventName\s*=\s*PutBucketAcl.+\$\.eventName\s*=\s*PutBucketPolicy.+\$\.eventName\s*=\s*PutBucketCors.+\$\.eventName\s*=\s*PutBucketLifecycle.+\$\.eventName\s*=\s*PutBucketReplication.+\$\.eventName\s*=\s*DeleteBucketPolicy.+\$\.eventName\s*=\s*DeleteBucketCors.+\$\.eventName\s*=\s*DeleteBucketLifecycle.+\$\.eventName\s*=\s*DeleteBucketReplication' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for S3 bucket policy changes.' - else filter_name || ' forwards events for S3 bucket policy changes.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for S3 bucket policy changes.' + ELSE filter_name || ' forwards events for S3 bucket policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_5_1.yaml b/compliance/controls/aws/aws_cis_v140_5_1.yaml old mode 100755 new mode 100644 index 84af604d9..6f137d28d --- a/compliance/controls/aws/aws_cis_v140_5_1.yaml +++ b/compliance/controls/aws/aws_cis_v140_5_1.yaml @@ -1,87 +1,87 @@ +Description: The Network Access Control List (NACL) function provides stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_cis_v140_5_1 -Title: "5.1 Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_rules as ( - select + ListOfTables: + - aws_vpc_network_acl + Parameters: [] + PrimaryTable: aws_vpc_network_acl + QueryToExecute: | + WITH bad_rules AS ( + SELECT network_acl_id, - count(*) as num_bad_rules, + COUNT(*) AS num_bad_rules, tags, region, account_id - from + FROM aws_vpc_network_acl, - jsonb_array_elements(entries) as att - where - att ->> 'Egress' = 'false' -- as per aws egress = false indicates the ingress - and ( + jsonb_array_elements(entries) AS att + WHERE + att ->> 'Egress' = 'false' + AND ( att ->> 'CidrBlock' = '0.0.0.0/0' - or att ->> 'Ipv6CidrBlock' = '::/0' + OR att ->> 'Ipv6CidrBlock' = '::/0' ) - and att ->> 'RuleAction' = 'allow' - and ( + AND att ->> 'RuleAction' = 'allow' + AND ( ( - att ->> 'Protocol' = '-1' -- all traffic - and att ->> 'PortRange' is null + att ->> 'Protocol' = '-1' + AND att ->> 'PortRange' IS NULL + ) + OR ( + (att -> 'PortRange' ->> 'From')::int <= 22 + AND (att -> 'PortRange' ->> 'To')::int >= 22 + AND att ->> 'Protocol' IN ('6', '17') ) - or ( - (att -> 'PortRange' ->> 'From') :: int <= 22 - and (att -> 'PortRange' ->> 'To') :: int >= 22 - and att ->> 'Protocol' in('6', '17') -- TCP or UDP + OR ( + (att -> 'PortRange' ->> 'From')::int <= 3389 + AND (att -> 'PortRange' ->> 'To')::int >= 3389 + AND att ->> 'Protocol' IN ('6', '17') ) - or ( - (att -> 'PortRange' ->> 'From') :: int <= 3389 - and (att -> 'PortRange' ->> 'To') :: int >= 3389 - and att ->> 'Protocol' in('6', '17') -- TCP or UDP ) - ) - group by + GROUP BY network_acl_id, region, account_id, tags - order by + ORDER BY network_acl_id, region, account_id, tags ), - aws_vpc_network_acls as ( - select + aws_vpc_network_acls AS ( + SELECT network_acl_id, tags, partition, region, account_id - from + FROM aws_vpc_network_acl - order by + ORDER BY network_acl_id, region, account_id ) - select - 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id as resource, - acl.og_account_id as og_account_id, - acl.og_resource_id as og_resource_id, - case - when bad_rules.network_acl_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.network_acl_id is null then acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - else acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - end as reason - from - aws_vpc_network_acls as acl - left join bad_rules on bad_rules.network_acl_id = acl.network_acl_id; - PrimaryTable: aws_vpc_network_acl - ListOfTables: - - aws_vpc_network_acl - Parameters: [] + SELECT + 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id AS resource, + acl.og_account_id AS og_account_id, + acl.og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + aws_vpc_network_acls AS acl + LEFT JOIN bad_rules ON bad_rules.network_acl_id = acl.network_acl_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.1 Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_5_2.yaml b/compliance/controls/aws/aws_cis_v140_5_2.yaml old mode 100755 new mode 100644 index 387211986..a2818b3b1 --- a/compliance/controls/aws/aws_cis_v140_5_2.yaml +++ b/compliance/controls/aws/aws_cis_v140_5_2.yaml @@ -1,58 +1,57 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_cis_v140_5_2 -Title: "5.2 Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT group_id, - count(*) as num_bad_rules - from + COUNT(*) AS num_bad_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and ( + AND ( cidr_ipv4 = '0.0.0.0/0' - or cidr_ipv6 = '::/0' + OR cidr_ipv6 = '::/0' ) - and ( - ( ip_protocol = '-1' -- all traffic - and from_port is null - ) - or ( - from_port >= 22 - and to_port <= 22 - ) - or ( - from_port >= 3389 - and to_port <= 3389 - ) + AND ( + (ip_protocol = '-1' -- all traffic + AND from_port IS NULL) + OR ( + from_port >= 22 + AND to_port <= 22 + ) + OR ( + from_port >= 3389 + AND to_port <= 3389 + ) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when bad_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - end as reason - from - aws_vpc_security_group as sg - left join bad_rules on bad_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.2 Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v140_5_4.yaml b/compliance/controls/aws/aws_cis_v140_5_4.yaml old mode 100755 new mode 100644 index 8e9eadbc7..8a25ecd30 --- a/compliance/controls/aws/aws_cis_v140_5_4.yaml +++ b/compliance/controls/aws/aws_cis_v140_5_4.yaml @@ -1,14 +1,22 @@ +Description: Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection. ID: aws_cis_v140_5_4 -Title: "5.4 Ensure routing tables for VPC peering are \\\"least access\\\"" -Description: "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.4 Ensure routing tables for VPC peering are "least access" \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_1.yaml b/compliance/controls/aws/aws_cis_v150_1_1.yaml old mode 100755 new mode 100644 index 421cbd03d..eb725566a --- a/compliance/controls/aws/aws_cis_v150_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_1.yaml @@ -1,14 +1,22 @@ +Description: Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. ID: aws_cis_v150_1_1 -Title: "1.1 Maintain current contact details" -Description: "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.1 Maintain current contact details \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_10.yaml b/compliance/controls/aws/aws_cis_v150_1_10.yaml old mode 100755 new mode 100644 index 1b7de91e5..ae2da1b77 --- a/compliance/controls/aws/aws_cis_v150_1_10.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_10.yaml @@ -1,29 +1,29 @@ +Description: Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password. ID: aws_cis_v150_1_10 -Title: "1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password" -Description: "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when password_enabled and not mfa_active then 'alarm' - else 'ok' - end as status, - case - when not password_enabled then user_name || ' password login disabled.' - when password_enabled and not mfa_active then user_name || ' password login enabled but no MFA device configured.' - else user_name || ' password login enabled and MFA device configured.' - end as reason - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND NOT mfa_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN password_enabled AND NOT mfa_active THEN user_name || ' password login enabled but no MFA device configured.' + ELSE user_name || ' password login enabled and MFA device configured.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_11.yaml b/compliance/controls/aws/aws_cis_v150_1_11.yaml old mode 100755 new mode 100644 index ee3a62c22..7faef747d --- a/compliance/controls/aws/aws_cis_v150_1_11.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_11.yaml @@ -1,32 +1,32 @@ +Description: AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require. ID: aws_cis_v150_1_11 -Title: "1.11 Do not setup access keys during initial user setup for all IAM users that have a console password" -Description: "AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - -- alarm when password is enabled and the key was created within 10 seconds of the user - when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) then 'alarm' - else 'ok' - end as status, - case - when not password_enabled then user_name || ' password login disabled.' - when access_key_1_last_rotated is null then user_name || ' has no access keys.' - when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) - then user_name || ' has access key created during user creation and password login enabled.' - else user_name || ' has access key not created during user creation.' - end as reason - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled + AND extract(epoch FROM (access_key_1_last_rotated - user_creation_time)) < 10 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN access_key_1_last_rotated IS NULL THEN user_name || ' has no access keys.' + WHEN password_enabled + AND extract(epoch FROM (access_key_1_last_rotated - user_creation_time)) < 10 THEN user_name || ' has access key created during user creation and password login enabled.' + ELSE user_name || ' has access key not created during user creation.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.11 Do not setup access keys during initial user setup for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_12.yaml b/compliance/controls/aws/aws_cis_v150_1_12.yaml old mode 100755 new mode 100644 index 4c30ed02b..6a9d02930 --- a/compliance/controls/aws/aws_cis_v150_1_12.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_12.yaml @@ -1,14 +1,63 @@ +Description: AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed. ID: aws_cis_v150_1_12 -Title: "1.12 Ensure credentials unused for 45 days or greater are disabled" -Description: "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n --root_account will have always password associated even though AWS credential report returns 'not_supported' for password_enabled\n when user_name = ''\n then 'info'\n when password_enabled and password_last_used is null and password_last_changed < (current_date - interval '45' day)\n then 'alarm'\n when password_enabled and password_last_used < (current_date - interval '45' day)\n then 'alarm'\n when access_key_1_active and access_key_1_last_used_date is null and access_key_1_last_rotated < (current_date - interval '45' day)\n then 'alarm'\n when access_key_1_active and access_key_1_last_used_date < (current_date - interval '45' day)\n then 'alarm'\n when access_key_2_active and access_key_2_last_used_date is null and access_key_2_last_rotated < (current_date - interval '45' day)\n then 'alarm'\n when access_key_2_active and access_key_2_last_used_date < (current_date - interval '45' day)\n then 'alarm'\n else 'ok'\n end status,\n user_name ||\n case\n when not password_enabled\n then ' password not enabled,'\n when password_enabled and password_last_used is null\n then ' password created ' || to_char(password_last_changed, 'DD-Mon-YYYY') || ' never used,'\n else\n ' password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_1_active\n then ' key 1 not enabled,'\n when access_key_1_active and access_key_1_last_used_date is null\n then ' key 1 created ' || to_char(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,'\n else\n ' key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_2_active\n then ' key 2 not enabled.'\n when access_key_2_active and access_key_2_last_used_date is null\n then ' key 2 created ' || to_char(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.'\n else\n ' key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.'\n end\n as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_name = '' + THEN 'info' + WHEN password_enabled AND password_last_used IS NULL AND password_last_changed < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN password_enabled AND password_last_used < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL AND access_key_1_last_rotated < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL AND access_key_2_last_rotated < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || + CASE + WHEN NOT password_enabled + THEN ' password not enabled,' + WHEN password_enabled AND password_last_used IS NULL + THEN ' password created ' || TO_CHAR(password_last_changed, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_1_active + THEN ' key 1 not enabled,' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL + THEN ' key 1 created ' || TO_CHAR(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_2_active + THEN ' key 2 not enabled.' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL + THEN ' key 2 created ' || TO_CHAR(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' + ELSE + ' key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' + END + AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.12 Ensure credentials unused for 45 days or greater are disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_13.yaml b/compliance/controls/aws/aws_cis_v150_1_13.yaml old mode 100755 new mode 100644 index a12c860f3..088a1b142 --- a/compliance/controls/aws/aws_cis_v150_1_13.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_13.yaml @@ -1,24 +1,33 @@ +Description: Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK). ID: aws_cis_v150_1_13 -Title: "1.13 Ensure there is only one active access key available for any single IAM user" -Description: "Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - u.arn as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when count(k.*) > 1 then 'alarm' - else 'ok' - end as status, - u.name || ' has ' || count(k.*) || ' active access key(s).' as reason - from - aws_iam_user as u - left join aws_iam_access_key as k on u.name = k.user_name and u.account_id = k.account_id - where - k.status = 'Active' or k.status is null - group by + ListOfTables: + - aws_iam_user + - aws_iam_access_key + Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + u.arn AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(k.*) > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + u.name || ' has ' || COUNT(k.*) || ' active access key(s).' AS reason + FROM + aws_iam_user AS u + LEFT JOIN aws_iam_access_key AS k + ON u.name = k.user_name + AND u.account_id = k.account_id + WHERE + k.status = 'Active' + OR k.status IS NULL + GROUP BY u.arn, u.name, u.account_id, @@ -26,12 +35,6 @@ Query: u._ctx, u.og_account_id, u.og_resource_id; - PrimaryTable: aws_iam_user - ListOfTables: - - aws_iam_user - - aws_iam_access_key - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.13 Ensure there is only one active access key available for any single IAM user \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_14.yaml b/compliance/controls/aws/aws_cis_v150_1_14.yaml old mode 100755 new mode 100644 index 9040ebb83..413d9c74f --- a/compliance/controls/aws/aws_cis_v150_1_14.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_14.yaml @@ -1,14 +1,25 @@ +Description: Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated. ID: aws_cis_v150_1_14 -Title: "1.14 Ensure access keys are rotated every 90 days or less" -Description: "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when create_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end status,\n user_name || ' ' || access_key_id || ' created ' || to_char(create_date , 'DD-Mon-YYYY') ||\n ' (' || extract(day from current_timestamp - create_date) || ' days).'\n as reason\n \nfrom\n aws_iam_access_key;" - PrimaryTable: aws_iam_access_key ListOfTables: - aws_iam_access_key Parameters: [] + PrimaryTable: aws_iam_access_key + QueryToExecute: | + SELECT + 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END status, + user_name || ' ' || access_key_id || ' created ' || TO_CHAR(create_date, 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - create_date) || ' days).' AS reason + FROM + aws_iam_access_key; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.14 Ensure access keys are rotated every 90 days or less \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_15.yaml b/compliance/controls/aws/aws_cis_v150_1_15.yaml old mode 100755 new mode 100644 index afce7d842..8284cf85d --- a/compliance/controls/aws/aws_cis_v150_1_15.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_15.yaml @@ -1,26 +1,26 @@ +Description: 'IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended.' ID: aws_cis_v150_1_15 -Title: "1.15 Ensure IAM Users Receive Permissions Only Through Groups" -Description: "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when inline_policies is null and attached_policy_arns is null then 'ok' - else 'alarm' - end status, - name || ' has ' || coalesce(jsonb_array_length(inline_policies),0) || ' inline and ' || - coalesce(jsonb_array_length(attached_policy_arns),0) || ' directly attached policies.' as reason - from - aws_iam_user; - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN inline_policies IS NULL AND attached_policy_arns IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' has ' || COALESCE(jsonb_array_length(inline_policies), 0) || ' inline and ' || + COALESCE(jsonb_array_length(attached_policy_arns), 0) || ' directly attached policies.' AS reason + FROM + aws_iam_user; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.15 Ensure IAM Users Receive Permissions Only Through Groups \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_16.yaml b/compliance/controls/aws/aws_cis_v150_1_16.yaml old mode 100755 new mode 100644 index a335067ef..a98c361f0 --- a/compliance/controls/aws/aws_cis_v150_1_16.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_16.yaml @@ -1,55 +1,54 @@ +Description: IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege - that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges. ID: aws_cis_v150_1_16 -Title: "1.16 Ensure IAM policies that allow full \\\"*:*\\\" administrative privileges are not attached" -Description: "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with star_access_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH star_access_policies AS ( + SELECT arn, is_aws_managed, - count(*) as num_bad_statements - from + COUNT(*) AS num_bad_statements + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where - s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - (action = '*' - or action = '*:*' - ) + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + s ->> 'Effect' = 'Allow' + AND resource = '*' + AND ( + action = '*' + OR action = '*:*' ) - and is_attached - group by + AND is_attached + GROUP BY arn, is_aws_managed ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when s.arn is not null and s.is_aws_managed then 'info' - when s.arn is null then 'ok' - else 'alarm' - end status, - case - when s.arn is not null and s.is_aws_managed then p.name || ' is an AWS managed policy with ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - else p.name || ' contains ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - end as reason - from - aws_iam_policy as p - left join star_access_policies as s on p.arn = s.arn - where + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN 'info' + WHEN s.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN p.name || ' is an AWS managed policy with ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + ELSE p.name || ' contains ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + END AS reason + FROM + aws_iam_policy AS p + LEFT JOIN star_access_policies AS s ON p.arn = s.arn + WHERE p.is_attached; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.16 Ensure IAM policies that allow full "*:*" administrative privileges are not attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_17.yaml b/compliance/controls/aws/aws_cis_v150_1_17.yaml old mode 100755 new mode 100644 index e54c0eb4d..db2933fe8 --- a/compliance/controls/aws/aws_cis_v150_1_17.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_17.yaml @@ -1,15 +1,54 @@ +Description: AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support. ID: aws_cis_v150_1_17 -Title: "1.17 Ensure a support role has been created to manage incidents with AWS Support" -Description: "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "-- pgFormatter-ignore\nwith support_role_count as\n(\n select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n count(policy_arn),\n a.account_id,\n a._ctx,\n a.og_account_id,\n a.og_resource_id\n from\n aws_account as a\n left join aws_iam_role as r on r.account_id = a.account_id\n left join jsonb_array_elements_text(attached_policy_arns) as policy_arn on true\n where\n split_part(policy_arn, '/', 2) = 'AWSSupportAccess'\n or policy_arn is null\n group by\n a.account_id,\n a.partition,\n a._ctx,\n a.og_account_id,\n a.og_resource_id\n)\nselect\n resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when count > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count = 1 then 'AWSSupportAccess policy attached to 1 role.'\n when count > 1 then 'AWSSupportAccess policy attached to ' || count || ' roles.'\n else 'AWSSupportAccess policy not attached to any role.'\n end as reason\n \nfrom\n support_role_count;" - PrimaryTable: aws_iam_role ListOfTables: - aws_account - aws_iam_role Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH support_role_count AS ( + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + COUNT(policy_arn), + a.account_id, + a._ctx, + a.og_account_id, + a.og_resource_id + FROM + aws_account AS a + LEFT JOIN + aws_iam_role AS r ON r.account_id = a.account_id + LEFT JOIN + jsonb_array_elements_text(attached_policy_arns) AS policy_arn ON true + WHERE + split_part(policy_arn, '/', 2) = 'AWSSupportAccess' + OR policy_arn IS NULL + GROUP BY + a.account_id, + a.partition, + a._ctx, + a.og_account_id, + a.og_resource_id + ) + SELECT + resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN COUNT > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT = 1 THEN 'AWSSupportAccess policy attached to 1 role.' + WHEN COUNT > 1 THEN 'AWSSupportAccess policy attached to ' || COUNT || ' roles.' + ELSE 'AWSSupportAccess policy not attached to any role.' + END AS reason + FROM + support_role_count; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.17 Ensure a support role has been created to manage incidents with AWS Support \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_18.yaml b/compliance/controls/aws/aws_cis_v150_1_18.yaml old mode 100755 new mode 100644 index 88b92a551..4ed32dcea --- a/compliance/controls/aws/aws_cis_v150_1_18.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_18.yaml @@ -1,14 +1,22 @@ +Description: AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. "AWS Access" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources. ID: aws_cis_v150_1_18 -Title: "1.18 Ensure IAM instance roles are used for AWS resource access from instances" -Description: "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \\\"AWS Access\\\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.18 Ensure IAM instance roles are used for AWS resource access from instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_19.yaml b/compliance/controls/aws/aws_cis_v150_1_19.yaml old mode 100755 new mode 100644 index af2d9f063..e048a11c1 --- a/compliance/controls/aws/aws_cis_v150_1_19.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_19.yaml @@ -1,14 +1,30 @@ +Description: To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console. ID: aws_cis_v150_1_19 -Title: "1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed" -Description: "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case when expiration < (current_date - interval '1' second) then 'alarm'\n else 'ok'\n end as status,\n case when expiration < (current_date - interval '1' second) then\n name || ' expired ' || to_char(expiration, 'DD-Mon-YYYY') || '.'\n else\n name || ' valid until ' || to_char(expiration, 'DD-Mon-YYYY') || '.'\n end as reason\n \n \nfrom\n aws_iam_server_certificate;" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: [] + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN expiration < (current_date - INTERVAL '1' SECOND) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expiration < (current_date - INTERVAL '1' SECOND) THEN + name || ' expired ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + ELSE + name || ' valid until ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_iam_server_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_2.yaml b/compliance/controls/aws/aws_cis_v150_1_2.yaml old mode 100755 new mode 100644 index a2f700e45..6c9556fe4 --- a/compliance/controls/aws/aws_cis_v150_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_2.yaml @@ -1,20 +1,26 @@ +Description: AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided. ID: aws_cis_v150_1_2 -Title: "1.2 Ensure security contact information is registered" -Description: "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alternate_security_contact as ( - select + ListOfTables: + - aws_account + - aws_account_alternate_contact + Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH alternate_security_contact AS ( + SELECT name, account_id - from + FROM aws_account_alternate_contact - where + WHERE contact_type = 'SECURITY' ), - account as ( - select + account AS ( + SELECT arn, partition, title, @@ -22,35 +28,29 @@ Query: _ctx, og_account_id, og_resource_id - from + FROM aws_account ) - select - arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.partition = 'aws-us-gov' then 'info' - -- Name is a required field if setting a security contact - when c.name is not null then 'ok' - else 'alarm' - end as status, - case - when a.partition = 'aws-us-gov' then a.title || ' in GovCloud, manual verification required.' - when c.name is not null then a.title || ' has security contact ' || c.name || ' registered.' - else a.title || ' security contact not registered.' - end as reason - from - account as a, - alternate_security_contact as c - where + SELECT + arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.partition = 'aws-us-gov' THEN 'info' + WHEN c.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.partition = 'aws-us-gov' THEN a.title || ' in GovCloud, manual verification required.' + WHEN c.name IS NOT NULL THEN a.title || ' has security contact ' || c.name || ' registered.' + ELSE a.title || ' security contact not registered.' + END AS reason + FROM + account AS a + JOIN + alternate_security_contact AS c + ON c.account_id = a.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_account - - aws_account_alternate_contact - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.2 Ensure security contact information is registered \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_21.yaml b/compliance/controls/aws/aws_cis_v150_1_21.yaml old mode 100755 new mode 100644 index 9e3d3d628..b231be686 --- a/compliance/controls/aws/aws_cis_v150_1_21.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_21.yaml @@ -1,14 +1,22 @@ +Description: In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations. ID: aws_cis_v150_1_21 -Title: "1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments" -Description: "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provide via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_3.yaml b/compliance/controls/aws/aws_cis_v150_1_3.yaml old mode 100755 new mode 100644 index a404abd5d..bbfe0cbc1 --- a/compliance/controls/aws/aws_cis_v150_1_3.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_3.yaml @@ -1,14 +1,22 @@ +Description: The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established. ID: aws_cis_v150_1_3 -Title: "1.3 Ensure security questions are registered in the AWS account" -Description: "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.3 Ensure security questions are registered in the AWS account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_4.yaml b/compliance/controls/aws/aws_cis_v150_1_4.yaml old mode 100755 new mode 100644 index 2aa7dfdc1..245b444d0 --- a/compliance/controls/aws/aws_cis_v150_1_4.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_4.yaml @@ -1,14 +1,28 @@ +Description: The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed. ID: aws_cis_v150_1_4 -Title: "1.4 Ensure no 'root' user account access key exists" -Description: "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_access_keys_present > 0 then 'alarm'\n else 'ok'\n end status,\n case\n when account_access_keys_present > 0 then 'Root user access keys exist.'\n else 'No root user access keys exist.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_access_keys_present > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN account_access_keys_present > 0 THEN 'Root user access keys exist.' + ELSE 'No root user access keys exist.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.4 Ensure no 'root' user account access key exists \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_5.yaml b/compliance/controls/aws/aws_cis_v150_1_5.yaml old mode 100755 new mode 100644 index 168d5922e..7a60f196c --- a/compliance/controls/aws/aws_cis_v150_1_5.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_5.yaml @@ -1,14 +1,28 @@ +Description: The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. ID: aws_cis_v150_1_5 -Title: "1.5 Ensure MFA is enabled for the 'root' user account" -Description: "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_mfa_enabled then 'ok'\n else 'alarm'\n end status,\n case\n when account_mfa_enabled then 'MFA enabled for root account.'\n else 'MFA not enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_mfa_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN account_mfa_enabled THEN 'MFA enabled for root account.' + ELSE 'MFA not enabled for root account.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.5 Ensure MFA is enabled for the 'root' user account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_7.yaml b/compliance/controls/aws/aws_cis_v150_1_7.yaml old mode 100755 new mode 100644 index 433d9f187..f529339d4 --- a/compliance/controls/aws/aws_cis_v150_1_7.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_7.yaml @@ -1,14 +1,40 @@ +Description: With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks. ID: aws_cis_v150_1_7 -Title: "1.7 Eliminate use of the 'root' user for administrative and daily tasks" -Description: "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when password_last_used >= (current_date - interval '90' day) then 'alarm'\n when access_key_1_last_used_date <= (current_date - interval '90' day) then 'alarm'\n when access_key_2_last_used_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end as status,\n case\n when password_last_used is null then 'Root never logged in with password.'\n else 'Root password used ' || to_char(password_last_used , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - password_last_used) || ' days).'\n end ||\n case\n when access_key_1_last_used_date is null then ' Access Key 1 never used.'\n else ' Access Key 1 used ' || to_char(access_key_1_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_1_last_used_date) || ' days).'\n end ||\n case\n when access_key_2_last_used_date is null then ' Access Key 2 never used.'\n else ' Access Key 2 used ' || to_char(access_key_2_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_2_last_used_date) || ' days).'\n end as reason\n \nfrom\n aws_iam_credential_report\nwhere\n user_name = '';" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_last_used >= (current_date - INTERVAL '90' day) THEN 'alarm' + WHEN access_key_1_last_used_date <= (current_date - INTERVAL '90' day) THEN 'alarm' + WHEN access_key_2_last_used_date <= (current_date - INTERVAL '90' day) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN password_last_used IS NULL THEN 'Root never logged in with password.' + ELSE 'Root password used ' || TO_CHAR(password_last_used , 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM current_timestamp - password_last_used) || ' days).' + END || + CASE + WHEN access_key_1_last_used_date IS NULL THEN ' Access Key 1 never used.' + ELSE ' Access Key 1 used ' || TO_CHAR(access_key_1_last_used_date , 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM current_timestamp - access_key_1_last_used_date) || ' days).' + END || + CASE + WHEN access_key_2_last_used_date IS NULL THEN ' Access Key 2 never used.' + ELSE ' Access Key 2 used ' || TO_CHAR(access_key_2_last_used_date , 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM current_timestamp - access_key_2_last_used_date) || ' days).' + END AS reason + FROM + aws_iam_credential_report + WHERE + user_name = ''; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.7 Eliminate use of the 'root' user for administrative and daily tasks \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_8.yaml b/compliance/controls/aws/aws_cis_v150_1_8.yaml old mode 100755 new mode 100644 index 0a2c53566..d7d5f5499 --- a/compliance/controls/aws/aws_cis_v150_1_8.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_8.yaml @@ -1,30 +1,33 @@ +Description: Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14. ID: aws_cis_v150_1_8 -Title: "1.8 Ensure IAM password policy requires minimum length of 14 or greater" -Description: "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when minimum_password_length >= 14 then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - else 'Minimum password length set to ' || minimum_password_length || '.' - end as reason - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_iam_account_password_policy ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_iam_account_password_policy + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN minimum_password_length >= 14 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + ELSE 'Minimum password length set to ' || minimum_password_length || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON + a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.8 Ensure IAM password policy requires minimum length of 14 or greater \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_1_9.yaml b/compliance/controls/aws/aws_cis_v150_1_9.yaml old mode 100755 new mode 100644 index 279f5a5e8..f11602e4d --- a/compliance/controls/aws/aws_cis_v150_1_9.yaml +++ b/compliance/controls/aws/aws_cis_v150_1_9.yaml @@ -1,31 +1,34 @@ +Description: IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords. ID: aws_cis_v150_1_9 -Title: "1.9 Ensure IAM password policy prevents password reuse" -Description: "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when password_reuse_prevention >= 24 then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - when password_reuse_prevention is null then 'Password reuse prevention not set.' - else 'Password reuse prevention set to ' || password_reuse_prevention || '.' - end as reason - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_iam_account_password_policy ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_iam_account_password_policy + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN password_reuse_prevention >= 24 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN password_reuse_prevention IS NULL THEN 'Password reuse prevention not set.' + ELSE 'Password reuse prevention set to ' || password_reuse_prevention || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON + a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.9 Ensure IAM password policy prevents password reuse \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_2_1_1.yaml b/compliance/controls/aws/aws_cis_v150_2_1_1.yaml old mode 100755 new mode 100644 index 865d6ee6a..bf7dd7240 --- a/compliance/controls/aws/aws_cis_v150_2_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v150_2_1_1.yaml @@ -1,28 +1,28 @@ +Description: Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest. ID: aws_cis_v150_2_1_1 -Title: "2.1.1 Ensure all S3 buckets employ encryption-at-rest" -Description: "Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when server_side_encryption_configuration is not null then 'ok' - else 'alarm' - end status, - case - when server_side_encryption_configuration is not null then name || ' default encryption enabled.' - else name || ' default encryption disabled.' - end reason - from - aws_s3_bucket; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN server_side_encryption_configuration IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN server_side_encryption_configuration IS NOT NULL THEN name || ' default encryption enabled.' + ELSE name || ' default encryption disabled.' + END AS reason + FROM + aws_s3_bucket; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.1 Ensure all S3 buckets employ encryption-at-rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_2_1_2.yaml b/compliance/controls/aws/aws_cis_v150_2_1_2.yaml old mode 100755 new mode 100644 index 5c0760ada..bcfa684b3 --- a/compliance/controls/aws/aws_cis_v150_2_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v150_2_1_2.yaml @@ -1,48 +1,48 @@ +Description: At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS. ID: aws_cis_v150_2_1_2 -Title: "2.1.2 Ensure S3 Bucket Policy is set to deny HTTP requests" -Description: "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ssl_ok as ( - select - distinct name, + ListOfTables: + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH ssl_ok AS ( + SELECT + DISTINCT name, arn, - 'ok' as status - from + 'ok' AS status + FROM aws_s3_bucket, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p, - jsonb_array_elements_text(s -> 'Action') as a, - jsonb_array_elements_text(s -> 'Resource') as r, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + jsonb_array_elements_text(s -> 'Action') AS a, + jsonb_array_elements_text(s -> 'Resource') AS r, jsonb_array_elements_text( s -> 'Condition' -> 'Bool' -> 'aws:securetransport' - ) as ssl - where + ) AS ssl + WHERE p = '*' - and s ->> 'Effect' = 'Deny' - and ssl :: bool = false + AND s ->> 'Effect' = 'Deny' + AND ssl::bool = FALSE ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when ok.status = 'ok' then 'ok' - else 'alarm' - end status, - case - when ok.status = 'ok' then b.name || ' bucket policy enforces HTTPS.' - else b.name || ' bucket policy does not enforce HTTPS.' - end reason - from - aws_s3_bucket as b - left join ssl_ok as ok on ok.name = b.name; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_s3_bucket - Parameters: [] + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN ok.status = 'ok' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ok.status = 'ok' THEN b.name || ' bucket policy enforces HTTPS.' + ELSE b.name || ' bucket policy does not enforce HTTPS.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN ssl_ok AS ok ON ok.name = b.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.2 Ensure S3 Bucket Policy is set to deny HTTP requests \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_2_1_3.yaml b/compliance/controls/aws/aws_cis_v150_2_1_3.yaml old mode 100755 new mode 100644 index 3c8083807..1e64b6c39 --- a/compliance/controls/aws/aws_cis_v150_2_1_3.yaml +++ b/compliance/controls/aws/aws_cis_v150_2_1_3.yaml @@ -1,28 +1,28 @@ +Description: Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication. ID: aws_cis_v150_2_1_3 -Title: "2.1.3 Ensure MFA Delete is enabled on S3 buckets" -Description: "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when versioning_mfa_delete then 'ok' - else 'alarm' - end as status, - case - when versioning_mfa_delete then name || ' MFA delete enabled.' - else name || ' MFA delete disabled.' - end as reason - from - aws_s3_bucket; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN versioning_mfa_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN versioning_mfa_delete THEN name || ' MFA delete enabled.' + ELSE name || ' MFA delete disabled.' + END AS reason + FROM + aws_s3_bucket; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.3 Ensure MFA Delete is enabled on S3 buckets \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_2_1_4.yaml b/compliance/controls/aws/aws_cis_v150_2_1_4.yaml old mode 100755 new mode 100644 index 3bd8e0d1e..aefb6b9f3 --- a/compliance/controls/aws/aws_cis_v150_2_1_4.yaml +++ b/compliance/controls/aws/aws_cis_v150_2_1_4.yaml @@ -1,40 +1,40 @@ +Description: Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets. ID: aws_cis_v150_2_1_4 -Title: "2.1.4 Ensure all data in Amazon S3 has been discovered, classified and secured when required" -Description: "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bucket_list as ( - select - trim(b::text, '"' ) as bucket_name - from - aws_macie2_classification_job, - jsonb_array_elements(s3_job_definition -> 'BucketDefinitions') as d, - jsonb_array_elements(d -> 'Buckets') as b - ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when b.region = any(array['us-gov-east-1', 'us-gov-west-1']) then 'skip' - when l.bucket_name is not null then 'ok' - else 'alarm' - end as status, - case - when b.region = any(array['us-gov-east-1', 'us-gov-west-1']) then b.title || ' not protected by Macie as Macie is not supported in ' || b.region || '.' - when l.bucket_name is not null then b.title || ' protected by Macie.' - else b.title || ' not protected by Macie.' - end as reason - from - aws_s3_bucket as b - left join bucket_list as l on b.name = l.bucket_name; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_macie2_classification_job - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH bucket_list AS ( + SELECT + TRIM(b::text, '"') AS bucket_name + FROM + aws_macie2_classification_job, + jsonb_array_elements(s3_job_definition -> 'BucketDefinitions') AS d, + jsonb_array_elements(d -> 'Buckets') AS b + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN b.region = ANY(ARRAY['us-gov-east-1', 'us-gov-west-1']) THEN 'skip' + WHEN l.bucket_name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.region = ANY(ARRAY['us-gov-east-1', 'us-gov-west-1']) THEN b.title || ' not protected by Macie as Macie is not supported in ' || b.region || '.' + WHEN l.bucket_name IS NOT NULL THEN b.title || ' protected by Macie.' + ELSE b.title || ' not protected by Macie.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN bucket_list AS l ON b.name = l.bucket_name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.4 Ensure all data in Amazon S3 has been discovered, classified and secured when required \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_2_2_1.yaml b/compliance/controls/aws/aws_cis_v150_2_2_1.yaml old mode 100755 new mode 100644 index 080ee2a77..69d0f0c89 --- a/compliance/controls/aws/aws_cis_v150_2_2_1.yaml +++ b/compliance/controls/aws/aws_cis_v150_2_2_1.yaml @@ -1,28 +1,28 @@ +Description: Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported. ID: aws_cis_v150_2_2_1 -Title: "2.2.1 Ensure EBS Volume Encryption is Enabled in all Regions" -Description: "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when encrypted then 'ok' - else 'alarm' - end as status, - case - when encrypted then volume_id || ' encrypted.' - else volume_id || ' not encrypted.' - end as reason - from - aws_ebs_volume; - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN volume_id || ' encrypted.' + ELSE volume_id || ' not encrypted.' + END AS reason + FROM + aws_ebs_volume; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.2.1 Ensure EBS Volume Encryption is Enabled in all Regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_2_3_1.yaml b/compliance/controls/aws/aws_cis_v150_2_3_1.yaml old mode 100755 new mode 100644 index a587aad6c..7e4fb112e --- a/compliance/controls/aws/aws_cis_v150_2_3_1.yaml +++ b/compliance/controls/aws/aws_cis_v150_2_3_1.yaml @@ -1,14 +1,28 @@ +Description: Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance. ID: aws_cis_v150_2_3_1 -Title: "2.3.1 Ensure that encryption is enabled for RDS Instances" -Description: "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_rds_db_instance;" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3.1 Ensure that encryption is enabled for RDS Instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_2_3_2.yaml b/compliance/controls/aws/aws_cis_v150_2_3_2.yaml old mode 100755 new mode 100644 index 35b053ecb..868bdbf0c --- a/compliance/controls/aws/aws_cis_v150_2_3_2.yaml +++ b/compliance/controls/aws/aws_cis_v150_2_3_2.yaml @@ -1,28 +1,28 @@ +Description: Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines. ID: aws_cis_v150_2_3_2 -Title: "2.3.2 Ensure Auto Minor Version Upgrade feature is Enabled for RDS Instances" -Description: "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when auto_minor_version_upgrade then 'ok' - else 'alarm' - end as status, - case - when auto_minor_version_upgrade then title || ' automatic minor version upgrades enabled.' - else title || ' automatic minor version upgrades not enabled.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrades enabled.' + ELSE title || ' automatic minor version upgrades not enabled.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3.2 Ensure Auto Minor Version Upgrade feature is Enabled for RDS Instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_2_3_3.yaml b/compliance/controls/aws/aws_cis_v150_2_3_3.yaml old mode 100755 new mode 100644 index e2092c769..a42fb691c --- a/compliance/controls/aws/aws_cis_v150_2_3_3.yaml +++ b/compliance/controls/aws/aws_cis_v150_2_3_3.yaml @@ -1,14 +1,28 @@ +Description: Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance. ID: aws_cis_v150_2_3_3 -Title: "2.3.3 Ensure that public access is not given to RDS Instance" -Description: "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when publicly_accessible then 'alarm'\n else 'ok'\n end status,\n case\n when publicly_accessible then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end reason\n \nfrom\n aws_rds_db_instance;" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3.3 Ensure that public access is not given to RDS Instance \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_2_4_1.yaml b/compliance/controls/aws/aws_cis_v150_2_4_1.yaml old mode 100755 new mode 100644 index b823a26e6..630022f16 --- a/compliance/controls/aws/aws_cis_v150_2_4_1.yaml +++ b/compliance/controls/aws/aws_cis_v150_2_4_1.yaml @@ -1,28 +1,28 @@ +Description: EFS data should be encrypted at rest using AWS KMS (Key Management Service). ID: aws_cis_v150_2_4_1 -Title: "2.4.1 Ensure that encryption is enabled for EFS file systems" -Description: "EFS data should be encrypted at rest using AWS KMS (Key Management Service)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when encrypted then 'ok' - else 'alarm' - end as status, - case - when encrypted then title || ' encrypted at rest.' - else title || ' not encrypted at rest.' - end as reason - from - aws_efs_file_system; - PrimaryTable: aws_efs_file_system ListOfTables: - aws_efs_file_system Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_efs_file_system; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.4.1 Ensure that encryption is enabled for EFS file systems \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_3_10.yaml b/compliance/controls/aws/aws_cis_v150_3_10.yaml old mode 100755 new mode 100644 index 291ce9156..8650e1cb8 --- a/compliance/controls/aws/aws_cis_v150_3_10.yaml +++ b/compliance/controls/aws/aws_cis_v150_3_10.yaml @@ -1,55 +1,55 @@ +Description: S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets. ID: aws_cis_v150_3_10 -Title: "3.10 Ensure that Object-level logging for write events is enabled for S3 bucket" -Description: "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with s3_selectors as - ( - select - name as trail_name, + ListOfTables: + - aws_cloudtrail_trail + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( + SELECT + name AS trail_name, is_multi_region_trail, bucket_selector - from + FROM aws_cloudtrail_trail, - jsonb_array_elements(event_selectors) as event_selector, - jsonb_array_elements(event_selector -> 'DataResources') as data_resource, - jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector - where + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE is_multi_region_trail - and data_resource ->> 'Type' = 'AWS::S3::Object' - and event_selector ->> 'ReadWriteType' in - ( - 'WriteOnly', - 'All' - ) + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ('WriteOnly', 'All') ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when count(bucket_selector) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(bucket_selector) > 0 then b.name || ' object-level write events logging enabled.' - else b.name || ' object-level write events logging disabled.' - end as reason - from - aws_s3_bucket as b - left join - s3_selectors - on bucket_selector like (b.arn || '%') - or bucket_selector = 'arn:aws:s3' - group by - b.account_id, b.region, b.arn, b.name, b.tags, b._ctx; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_cloudtrail_trail - - aws_s3_bucket - Parameters: [] + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level write events logging enabled.' + ELSE b.name || ' object-level write events logging disabled.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN + s3_selectors + ON bucket_selector LIKE (b.arn || '%') + OR bucket_selector = 'arn:aws:s3' + GROUP BY + b.account_id, + b.region, + b.arn, + b.name, + b.tags, + b._ctx; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.10 Ensure that Object-level logging for write events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_3_11.yaml b/compliance/controls/aws/aws_cis_v150_3_11.yaml old mode 100755 new mode 100644 index c60aae882..cbd491109 --- a/compliance/controls/aws/aws_cis_v150_3_11.yaml +++ b/compliance/controls/aws/aws_cis_v150_3_11.yaml @@ -1,15 +1,50 @@ +Description: S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets. ID: aws_cis_v150_3_11 -Title: "3.11 Ensure that Object-level logging for read events is enabled for S3 bucket" -Description: "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with s3_selectors as\n(\n select\n name as trail_name,\n is_multi_region_trail,\n bucket_selector\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as event_selector,\n jsonb_array_elements(event_selector -> 'DataResources') as data_resource,\n jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector\n where\n is_multi_region_trail\n and data_resource ->> 'Type' = 'AWS::S3::Object'\n and event_selector ->> 'ReadWriteType' in\n (\n 'ReadOnly',\n 'All'\n )\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when count(bucket_selector) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(bucket_selector) > 0 then b.name || ' object-level read events logging enabled.'\n else b.name || ' object-level read events logging disabled.'\n end as reason\n \n \nfrom\n aws_s3_bucket as b\n left join\n s3_selectors\n on bucket_selector like (b.arn || '%')\n or bucket_selector = 'arn:aws:s3'\ngroup by\n b.account_id, b.region, b.arn, b.name, b.tags, b._ctx;" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( + SELECT + name AS trail_name, + is_multi_region_trail, + bucket_selector + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE + is_multi_region_trail + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ('ReadOnly', 'All') + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level read events logging enabled.' + ELSE b.name || ' object-level read events logging disabled.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN + s3_selectors + ON bucket_selector LIKE (b.arn || '%') + OR bucket_selector = 'arn:aws:s3' + GROUP BY + b.account_id, b.region, b.arn, b.name, b.tags, b._ctx; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.11 Ensure that Object-level logging for read events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_3_2.yaml b/compliance/controls/aws/aws_cis_v150_3_2.yaml old mode 100755 new mode 100644 index 8f5daf1d0..c0d3beed0 --- a/compliance/controls/aws/aws_cis_v150_3_2.yaml +++ b/compliance/controls/aws/aws_cis_v150_3_2.yaml @@ -1,14 +1,30 @@ +Description: CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails. ID: aws_cis_v150_3_2 -Title: "3.2 Ensure CloudTrail log file validation is enabled" -Description: "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_file_validation_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when log_file_validation_enabled then title || ' log file validation enabled.'\n else title || ' log file validation disabled.'\n end as reason\n \n \nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_file_validation_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_file_validation_enabled THEN title || ' log file validation enabled.' + ELSE title || ' log file validation disabled.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.2 Ensure CloudTrail log file validation is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_3_3.yaml b/compliance/controls/aws/aws_cis_v150_3_3.yaml old mode 100755 new mode 100644 index e56a2b12e..0ec111ab6 --- a/compliance/controls/aws/aws_cis_v150_3_3.yaml +++ b/compliance/controls/aws/aws_cis_v150_3_3.yaml @@ -1,70 +1,67 @@ +Description: CloudTrail logs a record of every API call made in your AWS account. These logs files are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs. ID: aws_cis_v150_3_3 -Title: "3.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible" -Description: "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with public_bucket_data as ( - -- note the counts are not exactly CORRECT because of the jsonb_array_elements joins, - -- but will be non-zero if any matches are found - select - t.s3_bucket_name as name, - b.arn, - t.region, - t.account_id, - t.tags, - t._ctx, - count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AllUsers') as all_user_grants, - count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AuthenticatedUsers') as auth_user_grants, - count(s) filter (where s ->> 'Effect' = 'Allow' and p = '*' ) as anon_statements, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id - from - aws_cloudtrail_trail as t - left join aws_s3_bucket as b on t.s3_bucket_name = b.name - left join jsonb_array_elements(acl -> 'Grants') as acl_grant on true - left join jsonb_array_elements(policy_std -> 'Statement') as s on true - left join jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p on true - group by - t.s3_bucket_name, - b.arn, - t.region, - t.account_id, - t.tags, - t._ctx, - t.og_account_id, - t.og_resource_id - ) - select - case - when arn is null then 'arn:aws:s3::' || name - else arn - end as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when arn is null then 'skip' - when all_user_grants > 0 then 'alarm' - when auth_user_grants > 0 then 'alarm' - when anon_statements > 0 then 'alarm' - else 'ok' - end as status, - case - when arn is null then name || ' not found in account ' || account_id || '.' - when all_user_grants > 0 then name || ' grants access to AllUsers in ACL.' - when auth_user_grants > 0 then name || ' grants access to AuthenticatedUsers in ACL.' - when anon_statements > 0 then name || ' grants access to AWS:*" in bucket policy.' - else name || ' does not grant anonymous access in ACL or bucket policy.' - end as reason - - from - public_bucket_data; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH public_bucket_data AS ( + SELECT + t.s3_bucket_name AS name, + b.arn, + t.region, + t.account_id, + t.tags, + t._ctx, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AllUsers') AS all_user_grants, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AuthenticatedUsers') AS auth_user_grants, + COUNT(s) FILTER (WHERE s ->> 'Effect' = 'Allow' AND p = '*' ) AS anon_statements, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id + FROM + aws_cloudtrail_trail AS t + LEFT JOIN aws_s3_bucket AS b ON t.s3_bucket_name = b.name + LEFT JOIN jsonb_array_elements(acl -> 'Grants') AS acl_grant ON TRUE + LEFT JOIN jsonb_array_elements(policy_std -> 'Statement') AS s ON TRUE + LEFT JOIN jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p ON TRUE + GROUP BY + t.s3_bucket_name, + b.arn, + t.region, + t.account_id, + t.tags, + t._ctx, + t.og_account_id, + t.og_resource_id + ) + SELECT + CASE + WHEN arn IS NULL THEN 'arn:aws:s3::' || name + ELSE arn + END AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN arn IS NULL THEN 'skip' + WHEN all_user_grants > 0 THEN 'alarm' + WHEN auth_user_grants > 0 THEN 'alarm' + WHEN anon_statements > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN arn IS NULL THEN name || ' not found in account ' || account_id || '.' + WHEN all_user_grants > 0 THEN name || ' grants access to AllUsers in ACL.' + WHEN auth_user_grants > 0 THEN name || ' grants access to AuthenticatedUsers in ACL.' + WHEN anon_statements > 0 THEN name || ' grants access to AWS:*" in bucket policy.' + ELSE name || ' does not grant anonymous access in ACL or bucket policy.' + END AS reason + FROM + public_bucket_data; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_3_4.yaml b/compliance/controls/aws/aws_cis_v150_3_4.yaml old mode 100755 new mode 100644 index b2bd797c7..baa81007b --- a/compliance/controls/aws/aws_cis_v150_3_4.yaml +++ b/compliance/controls/aws/aws_cis_v150_3_4.yaml @@ -1,14 +1,30 @@ +Description: AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs. ID: aws_cis_v150_3_4 -Title: "3.4 Ensure CloudTrail trails are integrated with CloudWatch Logs" -Description: "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then 'ok'\n else 'alarm'\n end as status,\n case\n when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then title || ' integrated with CloudWatch logs.'\n else title || ' not integrated with CloudWatch logs.'\n end as reason\n \n \nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > current_date - 1) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > current_date - 1) THEN title || ' integrated with CloudWatch logs.' + ELSE title || ' not integrated with CloudWatch logs.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.4 Ensure CloudTrail trails are integrated with CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_3_5.yaml b/compliance/controls/aws/aws_cis_v150_3_5.yaml old mode 100755 new mode 100644 index ef7dfb754..d8530243c --- a/compliance/controls/aws/aws_cis_v150_3_5.yaml +++ b/compliance/controls/aws/aws_cis_v150_3_5.yaml @@ -1,15 +1,66 @@ +Description: AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions. ID: aws_cis_v150_3_5 -Title: "3.5 Ensure AWS Config is enabled in all regions" -Description: "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "-- pgFormatter-ignore\n-- Get count for any region with all matching criteria\nwith global_recorders as (\n select\n count(*) as global_config_recorders\n from\n aws_config_configuration_recorder\n where\n recording_group -> 'IncludeGlobalResourceTypes' = 'true'\n and recording_group -> 'AllSupported' = 'true'\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n)\nselect\n 'arn:aws::' || a.region || ':' || a.account_id as resource,\na.og_account_id as og_account_id,\na.og_resource_id as og_resource_id,\n case\n -- When any of the region satisfies with above CTE\n -- In left join of table, regions now having\n -- 'Recording' and 'LastStatus' matching criteria can be considered as OK\n when\n g.global_config_recorders >= 1\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n then 'ok'\n -- Skip any regions that are disabled in the account.\n when a.opt_in_status = 'not-opted-in' then 'skip'\n else 'alarm'\n end as status,\n -- Below cases are for citing respective reasons for control state\n case\n when a.opt_in_status = 'not-opted-in' then a.region || ' region is disabled.'\n else\n case\n when recording_group -> 'IncludeGlobalResourceTypes' = 'true' then a.region || ' IncludeGlobalResourceTypes enabled,'\n else a.region || ' IncludeGlobalResourceTypes disabled,'\n end ||\n case\n when recording_group -> 'AllSupported' = 'true' then ' AllSupported enabled,'\n else ' AllSupported disabled,'\n end ||\n case\n when status ->> 'Recording' = 'true' then ' Recording enabled'\n else ' Recording disabled'\n end ||\n case\n when status ->> 'LastStatus' = 'SUCCESS' then ' and LastStatus is SUCCESS.'\n else ' and LastStatus is not SUCCESS.'\n end\n end as reason\n \nfrom\n global_recorders as g,\n aws_region as a\n left join aws_config_configuration_recorder as r on r.account_id = a.account_id and r.region = a.name;" - PrimaryTable: aws_config_configuration_recorder ListOfTables: - aws_config_configuration_recorder - aws_region Parameters: [] + PrimaryTable: aws_config_configuration_recorder + QueryToExecute: | + WITH global_recorders AS ( + SELECT + COUNT(*) AS global_config_recorders + FROM + aws_config_configuration_recorder + WHERE + recording_group -> 'IncludeGlobalResourceTypes' = 'true' + AND recording_group -> 'AllSupported' = 'true' + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + ) + + SELECT + 'arn:aws::' || a.region || ':' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN + g.global_config_recorders >= 1 + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + THEN 'ok' + WHEN a.opt_in_status = 'not-opted-in' THEN 'skip' + ELSE 'alarm' + END AS status, + CASE + WHEN a.opt_in_status = 'not-opted-in' THEN a.region || ' region is disabled.' + ELSE + CASE + WHEN recording_group -> 'IncludeGlobalResourceTypes' = 'true' THEN a.region || ' IncludeGlobalResourceTypes enabled,' + ELSE a.region || ' IncludeGlobalResourceTypes disabled,' + END || + CASE + WHEN recording_group -> 'AllSupported' = 'true' THEN ' AllSupported enabled,' + ELSE ' AllSupported disabled,' + END || + CASE + WHEN status ->> 'Recording' = 'true' THEN ' Recording enabled' + ELSE ' Recording disabled' + END || + CASE + WHEN status ->> 'LastStatus' = 'SUCCESS' THEN ' and LastStatus is SUCCESS.' + ELSE ' and LastStatus is not SUCCESS.' + END + END AS reason + + FROM + global_recorders AS g, + aws_region AS a + LEFT JOIN aws_config_configuration_recorder AS r + ON r.account_id = a.account_id AND r.region = a.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.5 Ensure AWS Config is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_3_6.yaml b/compliance/controls/aws/aws_cis_v150_3_6.yaml old mode 100755 new mode 100644 index c94d73985..69019dc37 --- a/compliance/controls/aws/aws_cis_v150_3_6.yaml +++ b/compliance/controls/aws/aws_cis_v150_3_6.yaml @@ -1,32 +1,34 @@ +Description: S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket. ID: aws_cis_v150_3_6 -Title: "3.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket" -Description: "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - t.arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when b.logging is not null then 'ok' - else 'alarm' - end as status, - case - when b.logging is not null then t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' - else t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' - end as reason - from - aws_cloudtrail_trail t - inner join aws_s3_bucket b on t.s3_bucket_name = b.name - where - t.region = t.home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN b.logging IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.logging IS NOT NULL THEN t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' + ELSE t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' + END AS reason + FROM + aws_cloudtrail_trail t + INNER JOIN + aws_s3_bucket b + ON t.s3_bucket_name = b.name + WHERE + t.region = t.home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_3_7.yaml b/compliance/controls/aws/aws_cis_v150_3_7.yaml old mode 100755 new mode 100644 index bc615ea11..11346c686 --- a/compliance/controls/aws/aws_cis_v150_3_7.yaml +++ b/compliance/controls/aws/aws_cis_v150_3_7.yaml @@ -1,30 +1,30 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS. ID: aws_cis_v150_3_7 -Title: "3.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs" -Description: "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when kms_key_id is null then 'alarm' - else 'ok' - end as status, - case - when kms_key_id is null then title || ' logs are not encrypted at rest.' - else title || ' logs are encrypted at rest.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' logs are not encrypted at rest.' + ELSE title || ' logs are encrypted at rest.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_3_8.yaml b/compliance/controls/aws/aws_cis_v150_3_8.yaml old mode 100755 new mode 100644 index a370a6e9b..10afaec39 --- a/compliance/controls/aws/aws_cis_v150_3_8.yaml +++ b/compliance/controls/aws/aws_cis_v150_3_8.yaml @@ -1,14 +1,36 @@ +Description: AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK. ID: aws_cis_v150_3_8 -Title: "3.8 Ensure rotation for customer created symmetric CMKs is enabled" -Description: "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when origin = 'EXTERNAL' then 'skip'\n when key_state = 'PendingDeletion' then 'skip'\n when key_state = 'Disabled' then 'skip'\n when not key_rotation_enabled then 'alarm'\n else 'ok'\n end as status,\n case\n when origin = 'EXTERNAL' then title || ' has imported key material.'\n when key_state = 'PendingDeletion' then title || ' is pending deletion.'\n when key_state = 'Disabled' then title || ' is disabled.'\n when not key_rotation_enabled then title || ' key rotation disabled.'\n else title || ' key rotation enabled.'\n end as reason\n \n \nfrom\n aws_kms_key\nwhere\n key_manager = 'CUSTOMER';" - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN origin = 'EXTERNAL' THEN 'skip' + WHEN key_state = 'PendingDeletion' THEN 'skip' + WHEN key_state = 'Disabled' THEN 'skip' + WHEN NOT key_rotation_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN origin = 'EXTERNAL' THEN title || ' has imported key material.' + WHEN key_state = 'PendingDeletion' THEN title || ' is pending deletion.' + WHEN key_state = 'Disabled' THEN title || ' is disabled.' + WHEN NOT key_rotation_enabled THEN title || ' key rotation disabled.' + ELSE title || ' key rotation enabled.' + END AS reason + FROM + aws_kms_key + WHERE + key_manager = 'CUSTOMER'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.8 Ensure rotation for customer created symmetric CMKs is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_3_9.yaml b/compliance/controls/aws/aws_cis_v150_3_9.yaml old mode 100755 new mode 100644 index 68db7163f..94d9b36e2 --- a/compliance/controls/aws/aws_cis_v150_3_9.yaml +++ b/compliance/controls/aws/aws_cis_v150_3_9.yaml @@ -1,11 +1,17 @@ +Description: VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet "Rejects" for VPCs. ID: aws_cis_v150_3_9 -Title: "3.9 Ensure VPC flow logging is enabled in all VPCs" -Description: "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \\\"Rejects\\\" for VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with vpcs as ( - select + ListOfTables: + - aws_vpc + - aws_vpc_flow_log + Parameters: [] + PrimaryTable: aws_vpc + QueryToExecute: | + WITH vpcs AS ( + SELECT arn, account_id, region, @@ -15,44 +21,38 @@ Query: _ctx, og_account_id, og_resource_id - from + FROM aws_vpc - order by + ORDER BY vpc_id ), - flowlogs as ( - select + flowlogs AS ( + SELECT resource_id, account_id, region - from + FROM aws_vpc_flow_log - order by + ORDER BY resource_id ) - select - v.arn as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when v.account_id <> v.owner_id then 'skip' - when f.resource_id is not null then 'ok' - else 'alarm' - end as status, - case - when v.account_id <> v.owner_id then v.vpc_id || ' is a shared VPC.' - when f.resource_id is not null then v.vpc_id || ' flow logging enabled.' - else v.vpc_id || ' flow logging disabled.' - end as reason - from - vpcs as v - left join flowlogs as f on v.vpc_id = f.resource_id; - PrimaryTable: aws_vpc - ListOfTables: - - aws_vpc - - aws_vpc_flow_log - Parameters: [] + SELECT + v.arn AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.account_id <> v.owner_id THEN 'skip' + WHEN f.resource_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.account_id <> v.owner_id THEN v.vpc_id || ' is a shared VPC.' + WHEN f.resource_id IS NOT NULL THEN v.vpc_id || ' flow logging enabled.' + ELSE v.vpc_id || ' flow logging disabled.' + END AS reason + FROM + vpcs AS v + LEFT JOIN flowlogs AS f ON v.vpc_id = f.resource_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.9 Ensure VPC flow logging is enabled in all VPCs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_4_10.yaml b/compliance/controls/aws/aws_cis_v150_4_10.yaml old mode 100755 new mode 100644 index bb8008afa..85dec1514 --- a/compliance/controls/aws/aws_cis_v150_4_10.yaml +++ b/compliance/controls/aws/aws_cis_v150_4_10.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups. ID: aws_cis_v150_4_10 -Title: "4.10 Ensure a log metric filter and alarm exist for security group changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*RevokeSecurityGroupIngress.+\$\.eventName\s*=\s*RevokeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for security group changes.' - else filter_name || ' forwards events for security group changes.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for security group changes.' + ELSE filter_name || ' forwards events for security group changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.10 Ensure a log metric filter and alarm exist for security group changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_4_14.yaml b/compliance/controls/aws/aws_cis_v150_4_14.yaml old mode 100755 new mode 100644 index 094a0eb10..14dd9ca0a --- a/compliance/controls/aws/aws_cis_v150_4_14.yaml +++ b/compliance/controls/aws/aws_cis_v150_4_14.yaml @@ -1,10 +1,13 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch + Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 + VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs + enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be + established for changes made to VPCs. ID: aws_cis_v150_4_14 -Title: "4.14 Ensure a log metric filter and alarm exist for VPC changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateVpc.+\\$\\.eventName\\s*=\\s*DeleteVpc.+\\$\\.eventName\\s*=\\s*ModifyVpcAttribute.+\\$\\.eventName\\s*=\\s*AcceptVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*CreateVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*DeleteVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*RejectVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*AttachClassicLinkVpc.+\\$\\.eventName\\s*=\\s*DetachClassicLinkVpc.+\\$\\.eventName\\s*=\\s*DisableVpcClassicLink.+\\$\\.eventName\\s*=\\s*EnableVpcClassicLink'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n t.og_account_id as og_account_id,\n t.og_resource_id as og_resource_id,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for VPC changes.'\n else filter_name || ' forwards events for VPC changes.'\n end as reason \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_cloudwatch_alarm @@ -12,7 +15,86 @@ Query: - aws_cloudwatch_log_metric_filter - aws_account Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateVpc.+\$\.eventName\s*=\s*DeleteVpc.+\$\.eventName\s*=\s*ModifyVpcAttribute.+\$\.eventName\s*=\s*AcceptVpcPeeringConnection.+\$\.eventName\s*=\s*CreateVpcPeeringConnection.+\$\.eventName\s*=\s*DeleteVpcPeeringConnection.+\$\.eventName\s*=\s*RejectVpcPeeringConnection.+\$\.eventName\s*=\s*AttachClassicLinkVpc.+\$\.eventName\s*=\s*DetachClassicLinkVpc.+\$\.eventName\s*=\s*DisableVpcClassicLink.+\$\.eventName\s*=\s*EnableVpcClassicLink' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for VPC changes.' + ELSE filter_name || ' forwards events for VPC changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.14 Ensure a log metric filter and alarm exist for VPC changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_4_16.yaml b/compliance/controls/aws/aws_cis_v150_4_16.yaml old mode 100755 new mode 100644 index dc2e52add..1dd89b38a --- a/compliance/controls/aws/aws_cis_v150_4_16.yaml +++ b/compliance/controls/aws/aws_cis_v150_4_16.yaml @@ -1,35 +1,34 @@ +Description: Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products. ID: aws_cis_v150_4_16 -Title: "4.16 Ensure AWS Security Hub is enabled" -Description: "Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - when r.region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) then 'skip' - -- Skip any regions that are disabled in the account. - when r.opt_in_status = 'not-opted-in' then 'skip' - when h.hub_arn is not null then 'ok' - else 'alarm' - end as status, - case - when r.region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) then r.region || ' region not supported.' - when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.' - when h.hub_arn is not null then 'Security Hub enabled in ' || r.region || '.' - else 'Security Hub disabled in ' || r.region || '.' - end as reason - from - aws_region as r - left join aws_securityhub_hub as h on r.account_id = h.account_id and r.name = h.region; - PrimaryTable: aws_securityhub_hub ListOfTables: - aws_region - aws_securityhub_hub Parameters: [] + PrimaryTable: aws_securityhub_hub + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN r.region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) THEN 'skip' + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN h.hub_arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) THEN r.region || ' region not supported.' + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN h.hub_arn IS NOT NULL THEN 'Security Hub enabled in ' || r.region || '.' + ELSE 'Security Hub disabled in ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN aws_securityhub_hub AS h ON r.account_id = h.account_id AND r.name = h.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.16 Ensure AWS Security Hub is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_4_3.yaml b/compliance/controls/aws/aws_cis_v150_4_3.yaml old mode 100755 new mode 100644 index c1990324d..96341a88f --- a/compliance/controls/aws/aws_cis_v150_4_3.yaml +++ b/compliance/controls/aws/aws_cis_v150_4_3.yaml @@ -1,91 +1,91 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for root login attempts. ID: aws_cis_v150_4_3 -Title: "4.3 Ensure a log metric filter and alarm exist for usage of 'root' account" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for root login attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_account + - filter_data + Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn - ), - metric_filters as ( - select - filter.name as filter_name, - filter_pattern, - log_group_name, - metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where - filter.filter_pattern ~ '\s*\$\.userIdentity\.type\s*=\s*"Root".+\$\.userIdentity\.invokedBy NOT EXISTS.+\$\.eventType\s*!=\s*"AwsServiceEvent"' - order by - filter_name - ), - filter_data as ( - select - t.account_id, - t.trail_name, - f.filter_name - from - trails as t - join metric_filters as f on f.log_group_name = t.log_group_name - join alarms as alarm on alarm.metric_name = f.metric_transformation_name - join topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for usage of "root" account.' - else filter_name || ' forwards events for usage of "root" account.' - end as reason, + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.userIdentity\.type\s*=\s*"Root".+\$\.userIdentity\.invokedBy NOT EXISTS.+\$\.eventType\s*!=\s*"AwsServiceEvent"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for usage of "root" account.' + ELSE filter_name || ' forwards events for usage of "root" account.' + END AS reason, a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_account - - filter_data - Parameters: [] + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.3 Ensure a log metric filter and alarm exist for usage of 'root' account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_4_5.yaml b/compliance/controls/aws/aws_cis_v150_4_5.yaml old mode 100755 new mode 100644 index de363f3dd..284afd91c --- a/compliance/controls/aws/aws_cis_v150_4_5.yaml +++ b/compliance/controls/aws/aws_cis_v150_4_5.yaml @@ -1,10 +1,9 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations. ID: aws_cis_v150_4_5 -Title: "4.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateTrail.+\\$\\.eventName\\s*=\\s*UpdateTrail.+\\$\\.eventName\\s*=\\s*DeleteTrail.+\\$\\.eventName\\s*=\\s*StartLogging.+\\$\\.eventName\\s*=\\s*StopLogging'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for CloudTrail configuration changes.'\n else filter_name || ' forwards events for CloudTrail configuration changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_cloudwatch_alarm @@ -12,7 +11,86 @@ Query: - aws_cloudwatch_log_metric_filter - aws_account Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateTrail.+\$\.eventName\s*=\s*UpdateTrail.+\$\.eventName\s*=\s*DeleteTrail.+\$\.eventName\s*=\s*StartLogging.+\$\.eventName\s*=\s*StopLogging' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for CloudTrail configuration changes.' + ELSE filter_name || ' forwards events for CloudTrail configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_4_7.yaml b/compliance/controls/aws/aws_cis_v150_4_7.yaml old mode 100755 new mode 100644 index eb25844cc..251c3e490 --- a/compliance/controls/aws/aws_cis_v150_4_7.yaml +++ b/compliance/controls/aws/aws_cis_v150_4_7.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer-created CMKs that have changed state to disabled or scheduled deletion. ID: aws_cis_v150_4_7 -Title: "4.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*kms.amazonaws.com.+\$\.eventName\s*=\s*DisableKey.+\$\.eventName\s*=\s*ScheduleKeyDeletion' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for disabling/deletion of CMKs.' - else filter_name || ' forwards events for disabling/deletion of CMKs.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for disabling/deletion of CMKs.' + ELSE filter_name || ' forwards events for disabling/deletion of CMKs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_4_8.yaml b/compliance/controls/aws/aws_cis_v150_4_8.yaml old mode 100755 new mode 100644 index b216c226d..f990bf301 --- a/compliance/controls/aws/aws_cis_v150_4_8.yaml +++ b/compliance/controls/aws/aws_cis_v150_4_8.yaml @@ -1,10 +1,9 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies. ID: aws_cis_v150_4_8 -Title: "4.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*s3.amazonaws.com.+\\$\\.eventName\\s*=\\s*PutBucketAcl.+\\$\\.eventName\\s*=\\s*PutBucketPolicy.+\\$\\.eventName\\s*=\\s*PutBucketCors.+\\$\\.eventName\\s*=\\s*PutBucketLifecycle.+\\$\\.eventName\\s*=\\s*PutBucketReplication.+\\$\\.eventName\\s*=\\s*DeleteBucketPolicy.+\\$\\.eventName\\s*=\\s*DeleteBucketCors.+\\$\\.eventName\\s*=\\s*DeleteBucketLifecycle.+\\$\\.eventName\\s*=\\s*DeleteBucketReplication'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for S3 bucket policy changes.'\n else filter_name || ' forwards events for S3 bucket policy changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;" - PrimaryTable: aws_account ListOfTables: - aws_cloudtrail_trail - aws_cloudwatch_alarm @@ -12,7 +11,88 @@ Query: - aws_cloudwatch_log_metric_filter - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*s3.amazonaws.com.+ + \$.eventName\s*=\s*PutBucketAcl.+\$.eventName\s*=\s*PutBucketPolicy.+ + \$.eventName\s*=\s*PutBucketCors.+\$.eventName\s*=\s*PutBucketLifecycle.+ + \$.eventName\s*=\s*PutBucketReplication.+\$.eventName\s*=\s*DeleteBucketPolicy.+ + \$.eventName\s*=\s*DeleteBucketCors.+\$.eventName\s*=\s*DeleteBucketLifecycle.+ + \$.eventName\s*=\s*DeleteBucketReplication' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for S3 bucket policy changes.' + ELSE filter_name || ' forwards events for S3 bucket policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_5_2.yaml b/compliance/controls/aws/aws_cis_v150_5_2.yaml old mode 100755 new mode 100644 index f0df4546a..1458623db --- a/compliance/controls/aws/aws_cis_v150_5_2.yaml +++ b/compliance/controls/aws/aws_cis_v150_5_2.yaml @@ -1,71 +1,64 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_cis_v150_5_2 -Title: "5.2 Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT group_id, - count(*) as num_bad_rules - from + COUNT(*) AS num_bad_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and ( + AND ( cidr_ipv4 = '0.0.0.0/0' - or cidr_ipv6 = '::/0' + OR cidr_ipv6 = '::/0' ) - and ( - ( ip_protocol = '-1' -- all traffic - and from_port is null - ) - or ( - from_port >= 22 - and to_port <= 22 - ) - or ( - from_port >= 3389 - and to_port <= 3389 - ) + AND ( + (ip_protocol = '-1' -- all traffic + AND from_port IS NULL) + OR (from_port >= 22 AND to_port <= 22) + OR (from_port >= 3389 AND to_port <= 3389) ) - group by + GROUP BY group_id ), - security_groups as ( - select + security_groups AS ( + SELECT arn, tags, region, account_id, group_id, _ctx - from + FROM aws_vpc_security_group - order by + ORDER BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when bad_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - end as reason - from - security_groups as sg - left join bad_rules on bad_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + security_groups AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.2 Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_5_3.yaml b/compliance/controls/aws/aws_cis_v150_5_3.yaml old mode 100755 new mode 100644 index d93ce8333..ea45ec73d --- a/compliance/controls/aws/aws_cis_v150_5_3.yaml +++ b/compliance/controls/aws/aws_cis_v150_5_3.yaml @@ -1,57 +1,49 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_cis_v150_5_3 -Title: "5.3 Ensure no security groups allow ingress from ::/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT group_id, - count(*) as num_bad_rules - from + COUNT(*) AS num_bad_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and ( + AND ( cidr_ipv6 = '::/0' ) - and ( - ( ip_protocol = '-1' -- all traffic - and from_port is null - ) - or ( - from_port >= 22 - and to_port <= 22 - ) - or ( - from_port >= 3389 - and to_port <= 3389 - ) + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR (from_port >= 22 AND to_port <= 22) + OR (from_port >= 3389 AND to_port <= 3389) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when bad_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from ::/0.' - else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from ::/0.' - end as reason - from - aws_vpc_security_group as sg - left join bad_rules on bad_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from ::/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from ::/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.3 Ensure no security groups allow ingress from ::/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_5_4.yaml b/compliance/controls/aws/aws_cis_v150_5_4.yaml old mode 100755 new mode 100644 index 1a6469e51..5da26c04a --- a/compliance/controls/aws/aws_cis_v150_5_4.yaml +++ b/compliance/controls/aws/aws_cis_v150_5_4.yaml @@ -1,35 +1,35 @@ +Description: A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. ID: aws_cis_v150_5_4 -Title: "5.4 Ensure the default security group of every VPC restricts all traffic" -Description: "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) = 0 then 'ok' - else 'alarm' - end status, - case - when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) > 0 - then 'Default security group ' || group_id || ' has inbound and outbound rules.' - when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) = 0 - then 'Default security group ' || group_id || ' has inbound rules.' - when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) > 0 - then 'Default security group ' || group_id || ' has outbound rules.' - else 'Default security group ' || group_id || ' has no inbound or outbound rules.' - end reason - from - aws_vpc_security_group - where - group_name = 'default'; - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id, + og_resource_id, + CASE + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has inbound and outbound rules.' + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) = 0 + THEN 'Default security group ' || group_id || ' has inbound rules.' + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has outbound rules.' + ELSE 'Default security group ' || group_id || ' has no inbound or outbound rules.' + END AS reason + FROM + aws_vpc_security_group + WHERE + group_name = 'default'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.4 Ensure the default security group of every VPC restricts all traffic \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v150_5_5.yaml b/compliance/controls/aws/aws_cis_v150_5_5.yaml old mode 100755 new mode 100644 index da85e78c2..e1ba5ac36 --- a/compliance/controls/aws/aws_cis_v150_5_5.yaml +++ b/compliance/controls/aws/aws_cis_v150_5_5.yaml @@ -1,14 +1,22 @@ +Description: Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection. ID: aws_cis_v150_5_5 -Title: "5.5 Ensure routing tables for VPC peering are \\\"least access\\\"" -Description: "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.5 Ensure routing tables for VPC peering are "least access" \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_1.yaml b/compliance/controls/aws/aws_cis_v200_1_1.yaml old mode 100755 new mode 100644 index 94d5335ca..36752c4a8 --- a/compliance/controls/aws/aws_cis_v200_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_1.yaml @@ -1,14 +1,22 @@ +Description: Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. ID: aws_cis_v200_1_1 -Title: "1.1 Maintain current contact details" -Description: "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.1 Maintain current contact details \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_10.yaml b/compliance/controls/aws/aws_cis_v200_1_10.yaml old mode 100755 new mode 100644 index 63398f77b..2d1defcd5 --- a/compliance/controls/aws/aws_cis_v200_1_10.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_10.yaml @@ -1,14 +1,29 @@ +Description: Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password. ID: aws_cis_v200_1_10 -Title: "1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password" -Description: "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when password_enabled and not mfa_active then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then user_name || ' password login disabled.'\n when password_enabled and not mfa_active then user_name || ' password login enabled but no MFA device configured.'\n else user_name || ' password login enabled and MFA device configured.'\n end as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND NOT mfa_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN password_enabled AND NOT mfa_active THEN user_name || ' password login enabled but no MFA device configured.' + ELSE user_name || ' password login enabled and MFA device configured.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_11.yaml b/compliance/controls/aws/aws_cis_v200_1_11.yaml old mode 100755 new mode 100644 index 59818ae11..0220aab89 --- a/compliance/controls/aws/aws_cis_v200_1_11.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_11.yaml @@ -1,32 +1,31 @@ +Description: AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require. ID: aws_cis_v200_1_11 -Title: "1.11 Do not setup access keys during initial user setup for all IAM users that have a console password" -Description: "AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - -- alarm when password is enabled and the key was created within 10 seconds of the user - when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) then 'alarm' - else 'ok' - end as status, - case - when not password_enabled then user_name || ' password login disabled.' - when access_key_1_last_rotated is null then user_name || ' has no access keys.' - when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) - then user_name || ' has access key created during user creation and password login enabled.' - else user_name || ' has access key not created during user creation.' - end as reason - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND (EXTRACT(epoch FROM (access_key_1_last_rotated - user_creation_time)) < 10) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN access_key_1_last_rotated IS NULL THEN user_name || ' has no access keys.' + WHEN password_enabled AND (EXTRACT(epoch FROM (access_key_1_last_rotated - user_creation_time)) < 10) + THEN user_name || ' has access key created during user creation and password login enabled.' + ELSE user_name || ' has access key not created during user creation.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.11 Do not setup access keys during initial user setup for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_12.yaml b/compliance/controls/aws/aws_cis_v200_1_12.yaml old mode 100755 new mode 100644 index 66dccb76c..bfe159414 --- a/compliance/controls/aws/aws_cis_v200_1_12.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_12.yaml @@ -1,14 +1,62 @@ +Description: AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed. ID: aws_cis_v200_1_12 -Title: "1.12 Ensure credentials unused for 45 days or greater are disabled" -Description: "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n --root_account will have always password associated even though AWS credential report returns 'not_supported' for password_enabled\n when user_name = ''\n then 'info'\n when password_enabled and password_last_used is null and password_last_changed < (current_date - interval '45' day)\n then 'alarm'\n when password_enabled and password_last_used < (current_date - interval '45' day)\n then 'alarm'\n when access_key_1_active and access_key_1_last_used_date is null and access_key_1_last_rotated < (current_date - interval '45' day)\n then 'alarm'\n when access_key_1_active and access_key_1_last_used_date < (current_date - interval '45' day)\n then 'alarm'\n when access_key_2_active and access_key_2_last_used_date is null and access_key_2_last_rotated < (current_date - interval '45' day)\n then 'alarm'\n when access_key_2_active and access_key_2_last_used_date < (current_date - interval '45' day)\n then 'alarm'\n else 'ok'\n end status,\n user_name ||\n case\n when not password_enabled\n then ' password not enabled,'\n when password_enabled and password_last_used is null\n then ' password created ' || to_char(password_last_changed, 'DD-Mon-YYYY') || ' never used,'\n else\n ' password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_1_active\n then ' key 1 not enabled,'\n when access_key_1_active and access_key_1_last_used_date is null\n then ' key 1 created ' || to_char(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,'\n else\n ' key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_2_active\n then ' key 2 not enabled.'\n when access_key_2_active and access_key_2_last_used_date is null\n then ' key 2 created ' || to_char(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.'\n else\n ' key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.'\n end\n as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_name = '' + THEN 'info' + WHEN password_enabled AND password_last_used IS NULL AND password_last_changed < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN password_enabled AND password_last_used < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL AND access_key_1_last_rotated < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL AND access_key_2_last_rotated < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + ELSE 'ok' + END status, + user_name || + CASE + WHEN NOT password_enabled + THEN ' password not enabled,' + WHEN password_enabled AND password_last_used IS NULL + THEN ' password created ' || TO_CHAR(password_last_changed, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_1_active + THEN ' key 1 not enabled,' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL + THEN ' key 1 created ' || TO_CHAR(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_2_active + THEN ' key 2 not enabled.' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL + THEN ' key 2 created ' || TO_CHAR(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' + ELSE + ' key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.12 Ensure credentials unused for 45 days or greater are disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_13.yaml b/compliance/controls/aws/aws_cis_v200_1_13.yaml old mode 100755 new mode 100644 index 1b963cdc0..2da8e426d --- a/compliance/controls/aws/aws_cis_v200_1_13.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_13.yaml @@ -1,35 +1,36 @@ +Description: Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK). ID: aws_cis_v200_1_13 -Title: "1.13 Ensure there is only one active access key available for any single IAM user" -Description: "Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - u.arn as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when count(k.*) > 1 then 'alarm' - else 'ok' - end as status, - u.name || ' has ' || count(k.*) || ' active access key(s).' as reason - from - aws_iam_user as u - left join aws_iam_access_key as k on u.name = k.user_name and u.account_id = k.account_id - where - k.status = 'Active' or k.status is null - group by + ListOfTables: + - aws_iam_user + - aws_iam_access_key + Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + u.arn AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(k.*) > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + u.name || ' has ' || COUNT(k.*) || ' active access key(s).' AS reason + FROM + aws_iam_user AS u + LEFT JOIN aws_iam_access_key AS k + ON u.name = k.user_name AND u.account_id = k.account_id + WHERE + k.status = 'Active' OR k.status IS NULL + GROUP BY u.arn, u.name, u.account_id, u.tags, u._ctx; - PrimaryTable: aws_iam_user - ListOfTables: - - aws_iam_user - - aws_iam_access_key - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.13 Ensure there is only one active access key available for any single IAM user \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_14.yaml b/compliance/controls/aws/aws_cis_v200_1_14.yaml old mode 100755 new mode 100644 index d3c66eb1c..dd6b8137a --- a/compliance/controls/aws/aws_cis_v200_1_14.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_14.yaml @@ -1,14 +1,27 @@ +Description: Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated. ID: aws_cis_v200_1_14 -Title: "1.14 Ensure access keys are rotated every 90 days or less" -Description: "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when create_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end status,\n user_name || ' ' || access_key_id || ' created ' || to_char(create_date , 'DD-Mon-YYYY') ||\n ' (' || extract(day from current_timestamp - create_date) || ' days).'\n as reason\n \nfrom\n aws_iam_access_key;" - PrimaryTable: aws_iam_access_key ListOfTables: - aws_iam_access_key Parameters: [] + PrimaryTable: aws_iam_access_key + QueryToExecute: | + SELECT + 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || ' ' || access_key_id || ' created ' || TO_CHAR(create_date, 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM current_timestamp - create_date) || ' days).' + AS reason + FROM + aws_iam_access_key; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.14 Ensure access keys are rotated every 90 days or less \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_15.yaml b/compliance/controls/aws/aws_cis_v200_1_15.yaml old mode 100755 new mode 100644 index 9c535c46f..406aff295 --- a/compliance/controls/aws/aws_cis_v200_1_15.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_15.yaml @@ -1,14 +1,26 @@ +Description: 'IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended.' ID: aws_cis_v200_1_15 -Title: "1.15 Ensure IAM Users Receive Permissions Only Through Groups" -Description: "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when inline_policies is null and attached_policy_arns is null then 'ok'\n else 'alarm'\n end status,\n name || ' has ' || coalesce(jsonb_array_length(inline_policies),0) || ' inline and ' ||\n coalesce(jsonb_array_length(attached_policy_arns),0) || ' directly attached policies.' as reason\n \n \nfrom\n aws_iam_user;" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN inline_policies IS NULL AND attached_policy_arns IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' has ' || COALESCE(jsonb_array_length(inline_policies), 0) || ' inline and ' || + COALESCE(jsonb_array_length(attached_policy_arns), 0) || ' directly attached policies.' AS reason + FROM + aws_iam_user; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.15 Ensure IAM Users Receive Permissions Only Through Groups \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_16.yaml b/compliance/controls/aws/aws_cis_v200_1_16.yaml old mode 100755 new mode 100644 index a5b09faa8..c60e2ea86 --- a/compliance/controls/aws/aws_cis_v200_1_16.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_16.yaml @@ -1,55 +1,56 @@ +Description: IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege - that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges. ID: aws_cis_v200_1_16 -Title: "1.16 Ensure IAM policies that allow full \\\"*:*\\\" administrative privileges are not attached" -Description: "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with star_access_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH star_access_policies AS ( + SELECT arn, is_aws_managed, - count(*) as num_bad_statements - from + COUNT(*) AS num_bad_statements + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - (action = '*' - or action = '*:*' - ) + AND resource = '*' + AND ( + action = '*' + OR action = '*:*' ) - and is_attached - group by + AND is_attached + GROUP BY arn, is_aws_managed ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when s.arn is not null and s.is_aws_managed then 'info' - when s.arn is null then 'ok' - else 'alarm' - end status, - case - when s.arn is not null and s.is_aws_managed then p.name || ' is an AWS managed policy with ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - else p.name || ' contains ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - end as reason - from - aws_iam_policy as p - left join star_access_policies as s on p.arn = s.arn - where + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN 'info' + WHEN s.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN + p.name || ' is an AWS managed policy with ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + ELSE + p.name || ' contains ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + END AS reason + FROM + aws_iam_policy AS p + LEFT JOIN star_access_policies AS s ON p.arn = s.arn + WHERE p.is_attached; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.16 Ensure IAM policies that allow full "*:*" administrative privileges are not attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_17.yaml b/compliance/controls/aws/aws_cis_v200_1_17.yaml old mode 100755 new mode 100644 index 6e1cdfbf7..ac80e9c9a --- a/compliance/controls/aws/aws_cis_v200_1_17.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_17.yaml @@ -1,50 +1,50 @@ +Description: AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support. ID: aws_cis_v200_1_17 -Title: "1.17 Ensure a support role has been created to manage incidents with AWS Support" -Description: "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - -- pgFormatter-ignore - with support_role_count as - ( - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - count(policy_arn), + ListOfTables: + - aws_account + - aws_iam_role + Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH support_role_count AS ( + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + COUNT(policy_arn), a.account_id, a._ctx - from - aws_account as a - left join aws_iam_role as r on r.account_id = a.account_id - left join jsonb_array_elements_text(attached_policy_arns) as policy_arn on true - where - split_part(policy_arn, '/', 2) = 'AWSSupportAccess' - or policy_arn is null - group by + FROM + aws_account AS a + LEFT JOIN aws_iam_role AS r + ON r.account_id = a.account_id + LEFT JOIN jsonb_array_elements_text(attached_policy_arns) AS policy_arn + ON TRUE + WHERE + SPLIT_PART(policy_arn, '/', 2) = 'AWSSupportAccess' + OR policy_arn IS NULL + GROUP BY a.account_id, a.partition, a._ctx ) - select + SELECT resource, - (select og_account_id from aws_account where account_id = support_role_count.account_id) as og_account_id, - (select og_resource_id from aws_account where account_id = support_role_count.account_id) as og_resource_id, - case - when count > 0 then 'ok' - else 'alarm' - end as status, - case - when count = 1 then 'AWSSupportAccess policy attached to 1 role.' - when count > 1 then 'AWSSupportAccess policy attached to ' || count || ' roles.' - else 'AWSSupportAccess policy not attached to any role.' - end as reason - from + (SELECT og_account_id FROM aws_account WHERE account_id = support_role_count.account_id) AS og_account_id, + (SELECT og_resource_id FROM aws_account WHERE account_id = support_role_count.account_id) AS og_resource_id, + CASE + WHEN count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN count = 1 THEN 'AWSSupportAccess policy attached to 1 role.' + WHEN count > 1 THEN 'AWSSupportAccess policy attached to ' || count || ' roles.' + ELSE 'AWSSupportAccess policy not attached to any role.' + END AS reason + FROM support_role_count; - PrimaryTable: aws_iam_role - ListOfTables: - - aws_account - - aws_iam_role - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.17 Ensure a support role has been created to manage incidents with AWS Support \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_18.yaml b/compliance/controls/aws/aws_cis_v200_1_18.yaml old mode 100755 new mode 100644 index 8d2c4d55d..e136b8a0a --- a/compliance/controls/aws/aws_cis_v200_1_18.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_18.yaml @@ -1,14 +1,22 @@ +Description: AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. "AWS Access" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources. ID: aws_cis_v200_1_18 -Title: "1.18 Ensure IAM instance roles are used for AWS resource access from instances" -Description: "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \\\"AWS Access\\\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.18 Ensure IAM instance roles are used for AWS resource access from instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_19.yaml b/compliance/controls/aws/aws_cis_v200_1_19.yaml old mode 100755 new mode 100644 index 81312c92d..ae2a00d08 --- a/compliance/controls/aws/aws_cis_v200_1_19.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_19.yaml @@ -1,28 +1,30 @@ +Description: To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console. ID: aws_cis_v200_1_19 -Title: "1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed" -Description: "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case when expiration < (current_date - interval '1' second) then 'alarm' - else 'ok' - end as status, - case when expiration < (current_date - interval '1' second) then - name || ' expired ' || to_char(expiration, 'DD-Mon-YYYY') || '.' - else - name || ' valid until ' || to_char(expiration, 'DD-Mon-YYYY') || '.' - end as reason - from - aws_iam_server_certificate; - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: [] + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN expiration < (CURRENT_DATE - INTERVAL '1' SECOND) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expiration < (CURRENT_DATE - INTERVAL '1' SECOND) THEN + name || ' expired ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + ELSE + name || ' valid until ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_iam_server_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_2.yaml b/compliance/controls/aws/aws_cis_v200_1_2.yaml old mode 100755 new mode 100644 index 54b5ae667..7de44e9de --- a/compliance/controls/aws/aws_cis_v200_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_2.yaml @@ -1,15 +1,54 @@ +Description: AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided. ID: aws_cis_v200_1_2 -Title: "1.2 Ensure security contact information is registered" -Description: "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alternate_security_contact as (\n select\n name,\n account_id\n from\n aws_account_alternate_contact\n where\n contact_type = 'SECURITY'\n),\naccount as (\n select\n arn,\n partition,\n title,\n account_id,\n _ctx\n from\n aws_account\n)\nselect\n arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.partition = 'aws-us-gov' then 'info'\n -- Name is a required field if setting a security contact\n when c.name is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.partition = 'aws-us-gov' then a.title || ' in GovCloud, manual verification required.'\n when c.name is not null then a.title || ' has security contact ' || c.name || ' registered.'\n else a.title || ' security contact not registered.'\n end as reason\n \nfrom\n account as a,\n alternate_security_contact as c\nwhere\n c.account_id = a.account_id;" - PrimaryTable: aws_account ListOfTables: - aws_account_alternate_contact - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH alternate_security_contact AS ( + SELECT + name, + account_id + FROM + aws_account_alternate_contact + WHERE + contact_type = 'SECURITY' + ), + account AS ( + SELECT + arn, + partition, + title, + account_id, + _ctx + FROM + aws_account + ) + SELECT + arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.partition = 'aws-us-gov' THEN 'info' + -- Name is a required field if setting a security contact + WHEN c.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.partition = 'aws-us-gov' THEN a.title || ' in GovCloud, manual verification required.' + WHEN c.name IS NOT NULL THEN a.title || ' has security contact ' || c.name || ' registered.' + ELSE a.title || ' security contact not registered.' + END AS reason + FROM + account AS a, + alternate_security_contact AS c + WHERE + c.account_id = a.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.2 Ensure security contact information is registered \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_20.yaml b/compliance/controls/aws/aws_cis_v200_1_20.yaml old mode 100755 new mode 100644 index f8dd673f1..bda3ecea5 --- a/compliance/controls/aws/aws_cis_v200_1_20.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_20.yaml @@ -1,33 +1,36 @@ +Description: Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region. ID: aws_cis_v200_1_20 -Title: "1.20 Ensure that IAM Access analyzer is enabled for all regions" -Description: "Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - -- Skip any regions that are disabled in the account. - when r.opt_in_status = 'not-opted-in' then 'skip' - when aa.arn is not null then 'ok' - else 'alarm' - end as status, - case - when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.' - when aa.arn is not null then aa.name || ' enabled in ' || r.region || '.' - else 'Access Analyzer not enabled in ' || r.region || '.' - end as reason - from - aws_region as r - left join aws_accessanalyzer_analyzer as aa on r.account_id = aa.account_id and r.region = aa.region; - PrimaryTable: aws_region ListOfTables: - aws_region - aws_accessanalyzer_analyzer Parameters: [] + PrimaryTable: aws_region + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN aa.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN aa.arn IS NOT NULL THEN aa.name || ' enabled in ' || r.region || '.' + ELSE 'Access Analyzer not enabled in ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN + aws_accessanalyzer_analyzer AS aa + ON + r.account_id = aa.account_id + AND r.region = aa.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.20 Ensure that IAM Access analyzer is enabled for all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_21.yaml b/compliance/controls/aws/aws_cis_v200_1_21.yaml old mode 100755 new mode 100644 index 91b51f00b..8d38d2f2a --- a/compliance/controls/aws/aws_cis_v200_1_21.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_21.yaml @@ -1,14 +1,22 @@ +Description: In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provide via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations. ID: aws_cis_v200_1_21 -Title: "1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments" -Description: "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provide via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_3.yaml b/compliance/controls/aws/aws_cis_v200_1_3.yaml old mode 100755 new mode 100644 index caeea37b7..b1ba99e97 --- a/compliance/controls/aws/aws_cis_v200_1_3.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_3.yaml @@ -1,14 +1,22 @@ +Description: The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established. ID: aws_cis_v200_1_3 -Title: "1.3 Ensure security questions are registered in the AWS account" -Description: "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.3 Ensure security questions are registered in the AWS account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_4.yaml b/compliance/controls/aws/aws_cis_v200_1_4.yaml old mode 100755 new mode 100644 index 8e6000155..4118b493a --- a/compliance/controls/aws/aws_cis_v200_1_4.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_4.yaml @@ -1,14 +1,28 @@ +Description: The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be deleted. ID: aws_cis_v200_1_4 -Title: "1.4 Ensure no 'root' user account access key exists" -Description: "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be deleted." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_access_keys_present > 0 then 'alarm'\n else 'ok'\n end status,\n case\n when account_access_keys_present > 0 then 'Root user access keys exist.'\n else 'No root user access keys exist.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_access_keys_present > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN account_access_keys_present > 0 THEN 'Root user access keys exist.' + ELSE 'No root user access keys exist.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.4 Ensure no 'root' user account access key exists \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_5.yaml b/compliance/controls/aws/aws_cis_v200_1_5.yaml old mode 100755 new mode 100644 index 99b406ddc..3c5590b56 --- a/compliance/controls/aws/aws_cis_v200_1_5.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_5.yaml @@ -1,14 +1,28 @@ +Description: The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. ID: aws_cis_v200_1_5 -Title: "1.5 Ensure MFA is enabled for the 'root' user account" -Description: "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_mfa_enabled then 'ok'\n else 'alarm'\n end status,\n case\n when account_mfa_enabled then 'MFA enabled for root account.'\n else 'MFA not enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_mfa_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN account_mfa_enabled THEN 'MFA enabled for root account.' + ELSE 'MFA not enabled for root account.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.5 Ensure MFA is enabled for the 'root' user account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_7.yaml b/compliance/controls/aws/aws_cis_v200_1_7.yaml old mode 100755 new mode 100644 index b0f705915..4cdfa3c90 --- a/compliance/controls/aws/aws_cis_v200_1_7.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_7.yaml @@ -1,14 +1,40 @@ +Description: With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks. ID: aws_cis_v200_1_7 -Title: "1.7 Eliminate use of the 'root' user for administrative and daily tasks" -Description: "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when password_last_used >= (current_date - interval '90' day) then 'alarm'\n when access_key_1_last_used_date <= (current_date - interval '90' day) then 'alarm'\n when access_key_2_last_used_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end as status,\n case\n when password_last_used is null then 'Root never logged in with password.'\n else 'Root password used ' || to_char(password_last_used , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - password_last_used) || ' days).'\n end ||\n case\n when access_key_1_last_used_date is null then ' Access Key 1 never used.'\n else ' Access Key 1 used ' || to_char(access_key_1_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_1_last_used_date) || ' days).'\n end ||\n case\n when access_key_2_last_used_date is null then ' Access Key 2 never used.'\n else ' Access Key 2 used ' || to_char(access_key_2_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_2_last_used_date) || ' days).'\n end as reason\n \nfrom\n aws_iam_credential_report\nwhere\n user_name = '';" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_last_used >= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + WHEN access_key_1_last_used_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + WHEN access_key_2_last_used_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN password_last_used IS NULL THEN 'Root never logged in with password.' + ELSE 'Root password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - password_last_used) || ' days).' + END || + CASE + WHEN access_key_1_last_used_date IS NULL THEN ' Access Key 1 never used.' + ELSE ' Access Key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - access_key_1_last_used_date) || ' days).' + END || + CASE + WHEN access_key_2_last_used_date IS NULL THEN ' Access Key 2 never used.' + ELSE ' Access Key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - access_key_2_last_used_date) || ' days).' + END AS reason + FROM + aws_iam_credential_report + WHERE + user_name = ''; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.7 Eliminate use of the 'root' user for administrative and daily tasks \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_1_8.yaml b/compliance/controls/aws/aws_cis_v200_1_8.yaml old mode 100755 new mode 100644 index 695ef9825..b7f4ab4f5 --- a/compliance/controls/aws/aws_cis_v200_1_8.yaml +++ b/compliance/controls/aws/aws_cis_v200_1_8.yaml @@ -1,15 +1,32 @@ +Description: Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure passwords are at least a given length. It is recommended that the password policy require a minimum password length of 14. ID: aws_cis_v200_1_8 -Title: "1.8 Ensure IAM password policy requires minimum length of 14 or greater" -Description: "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when minimum_password_length >= 14 then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n else 'Minimum password length set to ' || minimum_password_length || '.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN minimum_password_length >= 14 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + ELSE 'Minimum password length set to ' || minimum_password_length || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.8 Ensure IAM password policy requires minimum length of 14 or greater \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_2_1_1.yaml b/compliance/controls/aws/aws_cis_v200_2_1_1.yaml old mode 100755 new mode 100644 index 62953b99e..bf4b4bb0e --- a/compliance/controls/aws/aws_cis_v200_2_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v200_2_1_1.yaml @@ -1,48 +1,48 @@ +Description: At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS. ID: aws_cis_v200_2_1_1 -Title: "2.1.1 Ensure S3 Bucket Policy is set to deny HTTP requests" -Description: "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ssl_ok as ( - select - distinct name, + ListOfTables: + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH ssl_ok AS ( + SELECT + DISTINCT name, arn, - 'ok' as status - from + 'ok' AS status + FROM aws_s3_bucket, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p, - jsonb_array_elements_text(s -> 'Action') as a, - jsonb_array_elements_text(s -> 'Resource') as r, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + jsonb_array_elements_text(s -> 'Action') AS a, + jsonb_array_elements_text(s -> 'Resource') AS r, jsonb_array_elements_text( s -> 'Condition' -> 'Bool' -> 'aws:securetransport' - ) as ssl - where + ) AS ssl + WHERE p = '*' - and s ->> 'Effect' = 'Deny' - and ssl :: bool = false + AND s ->> 'Effect' = 'Deny' + AND ssl::bool = FALSE ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when ok.status = 'ok' then 'ok' - else 'alarm' - end status, - case - when ok.status = 'ok' then b.name || ' bucket policy enforces HTTPS.' - else b.name || ' bucket policy does not enforce HTTPS.' - end reason - from - aws_s3_bucket as b - left join ssl_ok as ok on ok.name = b.name; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_s3_bucket - Parameters: [] + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN ok.status = 'ok' THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN ok.status = 'ok' THEN b.name || ' bucket policy enforces HTTPS.' + ELSE b.name || ' bucket policy does not enforce HTTPS.' + END reason + FROM + aws_s3_bucket AS b + LEFT JOIN ssl_ok AS ok ON ok.name = b.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.1 Ensure S3 Bucket Policy is set to deny HTTP requests \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_2_1_2.yaml b/compliance/controls/aws/aws_cis_v200_2_1_2.yaml old mode 100755 new mode 100644 index 6c581cc92..aca7b59b3 --- a/compliance/controls/aws/aws_cis_v200_2_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v200_2_1_2.yaml @@ -1,28 +1,28 @@ +Description: Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication. ID: aws_cis_v200_2_1_2 -Title: "2.1.2 Ensure MFA Delete is enabled on S3 buckets" -Description: "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when versioning_mfa_delete then 'ok' - else 'alarm' - end as status, - case - when versioning_mfa_delete then name || ' MFA delete enabled.' - else name || ' MFA delete disabled.' - end as reason - from - aws_s3_bucket; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN versioning_mfa_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN versioning_mfa_delete THEN name || ' MFA delete enabled.' + ELSE name || ' MFA delete disabled.' + END AS reason + FROM + aws_s3_bucket; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.2 Ensure MFA Delete is enabled on S3 buckets \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_2_1_3.yaml b/compliance/controls/aws/aws_cis_v200_2_1_3.yaml old mode 100755 new mode 100644 index aea4a9e08..546bbcc7f --- a/compliance/controls/aws/aws_cis_v200_2_1_3.yaml +++ b/compliance/controls/aws/aws_cis_v200_2_1_3.yaml @@ -1,40 +1,40 @@ +Description: Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified, and protected. Macie, along with other 3rd party tools, can automatically provide an inventory of Amazon S3 buckets. ID: aws_cis_v200_2_1_3 -Title: "2.1.3 Ensure all data in Amazon S3 has been discovered, classified and secured when required" -Description: "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bucket_list as ( - select - trim(b::text, '"' ) as bucket_name - from - aws_macie2_classification_job, - jsonb_array_elements(s3_job_definition -> 'BucketDefinitions') as d, - jsonb_array_elements(d -> 'Buckets') as b - ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when b.region = any(array['us-gov-east-1', 'us-gov-west-1']) then 'skip' - when l.bucket_name is not null then 'ok' - else 'alarm' - end as status, - case - when b.region = any(array['us-gov-east-1', 'us-gov-west-1']) then b.title || ' not protected by Macie as Macie is not supported in ' || b.region || '.' - when l.bucket_name is not null then b.title || ' protected by Macie.' - else b.title || ' not protected by Macie.' - end as reason - from - aws_s3_bucket as b - left join bucket_list as l on b.name = l.bucket_name; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_macie2_classification_job - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH bucket_list AS ( + SELECT + TRIM(b::text, '"' ) AS bucket_name + FROM + aws_macie2_classification_job, + jsonb_array_elements(s3_job_definition -> 'BucketDefinitions') AS d, + jsonb_array_elements(d -> 'Buckets') AS b + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN b.region = ANY(ARRAY['us-gov-east-1', 'us-gov-west-1']) THEN 'skip' + WHEN l.bucket_name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.region = ANY(ARRAY['us-gov-east-1', 'us-gov-west-1']) THEN b.title || ' not protected by Macie as Macie is not supported in ' || b.region || '.' + WHEN l.bucket_name IS NOT NULL THEN b.title || ' protected by Macie.' + ELSE b.title || ' not protected by Macie.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN bucket_list AS l ON b.name = l.bucket_name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.3 Ensure all data in Amazon S3 has been discovered, classified, and secured when required \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_2_1_4.yaml b/compliance/controls/aws/aws_cis_v200_2_1_4.yaml old mode 100755 new mode 100644 index 56453c7db..651707d7c --- a/compliance/controls/aws/aws_cis_v200_2_1_4.yaml +++ b/compliance/controls/aws/aws_cis_v200_2_1_4.yaml @@ -1,46 +1,46 @@ +Description: Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principle with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, Block public access (bucket settings) prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, Block public access (account settings) prevents all buckets, and contained objects, from becoming publicly accessible across the entire account. ID: aws_cis_v200_2_1_4 -Title: "2.1.4 Ensure that S3 Buckets are configured with 'Block public access (bucket settings)'" -Description: "Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principle with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, Block public access (bucket settings) prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, Block public access (account settings) prevents all buckets, and contained objects, from becoming publicly accessible across the entire account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - bucket.og_account_id as og_account_id, - bucket.og_resource_id as og_resource_id, - case - when (bucket.block_public_acls or s3account.block_public_acls) - and (bucket.block_public_policy or s3account.block_public_policy) - and (bucket.ignore_public_acls or s3account.ignore_public_acls) - and (bucket.restrict_public_buckets or s3account.restrict_public_buckets) - then 'ok' - else 'alarm' - end as status, - case - when (bucket.block_public_acls or s3account.block_public_acls) - and (bucket.block_public_policy or s3account.block_public_policy) - and (bucket.ignore_public_acls or s3account.ignore_public_acls) - and (bucket.restrict_public_buckets or s3account.restrict_public_buckets) - then name || ' all public access blocks enabled.' - else name || ' not enabled for: ' || - concat_ws(', ', - case when not (bucket.block_public_acls or s3account.block_public_acls) then 'block_public_acls' end, - case when not (bucket.block_public_policy or s3account.block_public_policy) then 'block_public_policy' end, - case when not (bucket.ignore_public_acls or s3account.ignore_public_acls) then 'ignore_public_acls' end, - case when not (bucket.restrict_public_buckets or s3account.restrict_public_buckets) then 'restrict_public_buckets' end - ) || '.' - end as reason - from - aws_s3_bucket as bucket, - aws_s3_account_settings as s3account - where - s3account.account_id = bucket.account_id; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket - aws_s3_account_settings Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + bucket.og_account_id AS og_account_id, + bucket.og_resource_id AS og_resource_id, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN name || ' all public access blocks enabled.' + ELSE name || ' not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT (bucket.block_public_acls OR s3account.block_public_acls) THEN 'block_public_acls' END, + CASE WHEN NOT (bucket.block_public_policy OR s3account.block_public_policy) THEN 'block_public_policy' END, + CASE WHEN NOT (bucket.ignore_public_acls OR s3account.ignore_public_acls) THEN 'ignore_public_acls' END, + CASE WHEN NOT (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) THEN 'restrict_public_buckets' END + ) || '.' + END AS reason + FROM + aws_s3_bucket AS bucket, + aws_s3_account_settings AS s3account + WHERE + s3account.account_id = bucket.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.4 Ensure that S3 Buckets are configured with 'Block public access (bucket settings)' \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_2_2_1.yaml b/compliance/controls/aws/aws_cis_v200_2_2_1.yaml old mode 100755 new mode 100644 index e29d1a349..3a86365f7 --- a/compliance/controls/aws/aws_cis_v200_2_2_1.yaml +++ b/compliance/controls/aws/aws_cis_v200_2_2_1.yaml @@ -1,14 +1,28 @@ +Description: Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported. ID: aws_cis_v200_2_2_1 -Title: "2.2.1 Ensure EBS Volume Encryption is Enabled in all Regions" -Description: "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then volume_id || ' encrypted.'\n else volume_id || ' not encrypted.'\n end as reason\n \n \nfrom\n aws_ebs_volume;" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN volume_id || ' encrypted.' + ELSE volume_id || ' not encrypted.' + END AS reason + FROM + aws_ebs_volume; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.2.1 Ensure EBS Volume Encryption is Enabled in all Regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_2_3_1.yaml b/compliance/controls/aws/aws_cis_v200_2_3_1.yaml old mode 100755 new mode 100644 index 0fce89803..58dc45460 --- a/compliance/controls/aws/aws_cis_v200_2_3_1.yaml +++ b/compliance/controls/aws/aws_cis_v200_2_3_1.yaml @@ -1,28 +1,28 @@ +Description: Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance. ID: aws_cis_v200_2_3_1 -Title: "2.3.1 Ensure that encryption-at-rest is enabled for RDS Instances" -Description: "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when storage_encrypted then 'ok' - else 'alarm' - end as status, - case - when storage_encrypted then title || ' encrypted at rest.' - else title || ' not encrypted at rest.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3.1 Ensure that encryption-at-rest is enabled for RDS Instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_2_3_2.yaml b/compliance/controls/aws/aws_cis_v200_2_3_2.yaml old mode 100755 new mode 100644 index 73082f600..16e0ae9bb --- a/compliance/controls/aws/aws_cis_v200_2_3_2.yaml +++ b/compliance/controls/aws/aws_cis_v200_2_3_2.yaml @@ -1,28 +1,28 @@ +Description: Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines. ID: aws_cis_v200_2_3_2 -Title: "2.3.2 Ensure Auto Minor Version Upgrade feature is Enabled for RDS Instances" -Description: "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when auto_minor_version_upgrade then 'ok' - else 'alarm' - end as status, - case - when auto_minor_version_upgrade then title || ' automatic minor version upgrades enabled.' - else title || ' automatic minor version upgrades not enabled.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrades enabled.' + ELSE title || ' automatic minor version upgrades not enabled.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3.2 Ensure Auto Minor Version Upgrade feature is Enabled for RDS Instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_2_3_3.yaml b/compliance/controls/aws/aws_cis_v200_2_3_3.yaml old mode 100755 new mode 100644 index bc63c56cc..8f9418aa0 --- a/compliance/controls/aws/aws_cis_v200_2_3_3.yaml +++ b/compliance/controls/aws/aws_cis_v200_2_3_3.yaml @@ -1,28 +1,28 @@ +Description: Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance. ID: aws_cis_v200_2_3_3 -Title: "2.3.3 Ensure that public access is not given to RDS Instance" -Description: "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when publicly_accessible then 'alarm' - else 'ok' - end status, - case - when publicly_accessible then title || ' publicly accessible.' - else title || ' not publicly accessible.' - end reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3.3 Ensure that public access is not given to RDS Instance \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_2_4_1.yaml b/compliance/controls/aws/aws_cis_v200_2_4_1.yaml old mode 100755 new mode 100644 index bd3e95012..6e843a400 --- a/compliance/controls/aws/aws_cis_v200_2_4_1.yaml +++ b/compliance/controls/aws/aws_cis_v200_2_4_1.yaml @@ -1,28 +1,28 @@ +Description: EFS data should be encrypted at rest using AWS KMS (Key Management Service). ID: aws_cis_v200_2_4_1 -Title: "2.4.1 Ensure that encryption is enabled for EFS file systems" -Description: "EFS data should be encrypted at rest using AWS KMS (Key Management Service)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when encrypted then 'ok' - else 'alarm' - end as status, - case - when encrypted then title || ' encrypted at rest.' - else title || ' not encrypted at rest.' - end as reason - from - aws_efs_file_system; - PrimaryTable: aws_efs_file_system ListOfTables: - aws_efs_file_system Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_efs_file_system; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.4.1 Ensure that encryption is enabled for EFS file systems \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_3_10.yaml b/compliance/controls/aws/aws_cis_v200_3_10.yaml old mode 100755 new mode 100644 index dfa1ff889..9c3521bbc --- a/compliance/controls/aws/aws_cis_v200_3_10.yaml +++ b/compliance/controls/aws/aws_cis_v200_3_10.yaml @@ -1,15 +1,48 @@ +Description: S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets. ID: aws_cis_v200_3_10 -Title: "3.10 Ensure that Object-level logging for write events is enabled for S3 bucket" -Description: "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with s3_selectors as\n(\n select\n name as trail_name,\n is_multi_region_trail,\n bucket_selector\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as event_selector,\n jsonb_array_elements(event_selector -> 'DataResources') as data_resource,\n jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector\n where\n is_multi_region_trail\n and data_resource ->> 'Type' = 'AWS::S3::Object'\n and event_selector ->> 'ReadWriteType' in\n (\n 'WriteOnly',\n 'All'\n )\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when count(bucket_selector) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(bucket_selector) > 0 then b.name || ' object-level write events logging enabled.'\n else b.name || ' object-level write events logging disabled.'\n end as reason\n \n \nfrom\n aws_s3_bucket as b\n left join\n s3_selectors\n on bucket_selector like (b.arn || '%')\n or bucket_selector = 'arn:aws:s3'\ngroup by\n b.account_id, b.region, b.arn, b.name, b.tags, b._ctx;" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( + SELECT + name AS trail_name, + is_multi_region_trail, + bucket_selector + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE + is_multi_region_trail + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ('WriteOnly', 'All') + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level write events logging enabled.' + ELSE b.name || ' object-level write events logging disabled.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN + s3_selectors ON bucket_selector LIKE (b.arn || '%') OR bucket_selector = 'arn:aws:s3' + GROUP BY + b.account_id, b.region, b.arn, b.name, b.tags, b._ctx; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.10 Ensure that Object-level logging for write events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_3_11.yaml b/compliance/controls/aws/aws_cis_v200_3_11.yaml old mode 100755 new mode 100644 index 41fff4aed..e2cec0375 --- a/compliance/controls/aws/aws_cis_v200_3_11.yaml +++ b/compliance/controls/aws/aws_cis_v200_3_11.yaml @@ -1,55 +1,60 @@ +Description: S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets. ID: aws_cis_v200_3_11 -Title: "3.11 Ensure that Object-level logging for read events is enabled for S3 bucket" -Description: "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with s3_selectors as + ListOfTables: + - aws_cloudtrail_trail + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( - select - name as trail_name, + SELECT + name AS trail_name, is_multi_region_trail, bucket_selector - from + FROM aws_cloudtrail_trail, - jsonb_array_elements(event_selectors) as event_selector, - jsonb_array_elements(event_selector -> 'DataResources') as data_resource, - jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector - where + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE is_multi_region_trail - and data_resource ->> 'Type' = 'AWS::S3::Object' - and event_selector ->> 'ReadWriteType' in + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ( 'ReadOnly', 'All' ) ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when count(bucket_selector) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(bucket_selector) > 0 then b.name || ' object-level read events logging enabled.' - else b.name || ' object-level read events logging disabled.' - end as reason - from - aws_s3_bucket as b - left join + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level read events logging enabled.' + ELSE b.name || ' object-level read events logging disabled.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN s3_selectors - on bucket_selector like (b.arn || '%') - or bucket_selector = 'arn:aws:s3' - group by - b.account_id, b.region, b.arn, b.name, b.tags, b._ctx; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_cloudtrail_trail - - aws_s3_bucket - Parameters: [] + ON bucket_selector LIKE (b.arn || '%') + OR bucket_selector = 'arn:aws:s3' + GROUP BY + b.account_id, + b.region, + b.arn, + b.name, + b.tags, + b._ctx; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.11 Ensure that Object-level logging for read events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_3_2.yaml b/compliance/controls/aws/aws_cis_v200_3_2.yaml old mode 100755 new mode 100644 index 1f9ece403..913e18ce4 --- a/compliance/controls/aws/aws_cis_v200_3_2.yaml +++ b/compliance/controls/aws/aws_cis_v200_3_2.yaml @@ -1,14 +1,30 @@ +Description: CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails. ID: aws_cis_v200_3_2 -Title: "3.2 Ensure CloudTrail log file validation is enabled" -Description: "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_file_validation_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when log_file_validation_enabled then title || ' log file validation enabled.'\n else title || ' log file validation disabled.'\n end as reason\n \n \nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_file_validation_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_file_validation_enabled THEN title || ' log file validation enabled.' + ELSE title || ' log file validation disabled.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.2 Ensure CloudTrail log file validation is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_3_3.yaml b/compliance/controls/aws/aws_cis_v200_3_3.yaml old mode 100755 new mode 100644 index 5da9688ff..e1b8ef496 --- a/compliance/controls/aws/aws_cis_v200_3_3.yaml +++ b/compliance/controls/aws/aws_cis_v200_3_3.yaml @@ -1,65 +1,65 @@ +Description: CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. + It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to + prevent public access to the CloudTrail logs. ID: aws_cis_v200_3_3 -Title: "3.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible" -Description: "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with public_bucket_data as ( - -- note the counts are not exactly CORRECT because of the jsonb_array_elements joins, - -- but will be non-zero if any matches are found - select - t.s3_bucket_name as name, - b.arn, - t.region, - t.account_id, - t.tags, - t._ctx, - count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AllUsers') as all_user_grants, - count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AuthenticatedUsers') as auth_user_grants, - count(s) filter (where s ->> 'Effect' = 'Allow' and p = '*' ) as anon_statements - from - aws_cloudtrail_trail as t - left join aws_s3_bucket as b on t.s3_bucket_name = b.name - left join jsonb_array_elements(acl -> 'Grants') as acl_grant on true - left join jsonb_array_elements(policy_std -> 'Statement') as s on true - left join jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p on true - group by - t.s3_bucket_name, - b.arn, - t.region, - t.account_id, - t.tags, - t._ctx - ) - select - case - when arn is null then 'arn:aws:s3::' || name - else arn - end as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when arn is null then 'skip' - when all_user_grants > 0 then 'alarm' - when auth_user_grants > 0 then 'alarm' - when anon_statements > 0 then 'alarm' - else 'ok' - end as status, - case - when arn is null then name || ' not found in account ' || account_id || '.' - when all_user_grants > 0 then name || ' grants access to AllUsers in ACL.' - when auth_user_grants > 0 then name || ' grants access to AuthenticatedUsers in ACL.' - when anon_statements > 0 then name || ' grants access to AWS:*" in bucket policy.' - else name || ' does not grant anonymous access in ACL or bucket policy.' - end as reason - from - public_bucket_data; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH public_bucket_data AS ( + SELECT + t.s3_bucket_name AS name, + b.arn, + t.region, + t.account_id, + t.tags, + t._ctx, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AllUsers') AS all_user_grants, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AuthenticatedUsers') AS auth_user_grants, + COUNT(s) FILTER (WHERE s ->> 'Effect' = 'Allow' AND p = '*') AS anon_statements + FROM + aws_cloudtrail_trail AS t + LEFT JOIN aws_s3_bucket AS b ON t.s3_bucket_name = b.name + LEFT JOIN jsonb_array_elements(acl -> 'Grants') AS acl_grant ON true + LEFT JOIN jsonb_array_elements(policy_std -> 'Statement') AS s ON true + LEFT JOIN jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p ON true + GROUP BY + t.s3_bucket_name, + b.arn, + t.region, + t.account_id, + t.tags, + t._ctx + ) + SELECT + CASE + WHEN arn IS NULL THEN 'arn:aws:s3::' || name + ELSE arn + END AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN arn IS NULL THEN 'skip' + WHEN all_user_grants > 0 THEN 'alarm' + WHEN auth_user_grants > 0 THEN 'alarm' + WHEN anon_statements > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN arn IS NULL THEN name || ' not found in account ' || account_id || '.' + WHEN all_user_grants > 0 THEN name || ' grants access to AllUsers in ACL.' + WHEN auth_user_grants > 0 THEN name || ' grants access to AuthenticatedUsers in ACL.' + WHEN anon_statements > 0 THEN name || ' grants access to AWS:*" in bucket policy.' + ELSE name || ' does not grant anonymous access in ACL or bucket policy.' + END AS reason + FROM + public_bucket_data; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_3_4.yaml b/compliance/controls/aws/aws_cis_v200_3_4.yaml old mode 100755 new mode 100644 index 6f92cd85d..4b868a6f4 --- a/compliance/controls/aws/aws_cis_v200_3_4.yaml +++ b/compliance/controls/aws/aws_cis_v200_3_4.yaml @@ -1,13 +1,29 @@ +Description: AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs. ID: aws_cis_v200_3_4 -Title: "3.4 Ensure CloudTrail trails are integrated with CloudWatch Logs" -Description: "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then 'ok'\n else 'alarm'\n end as status,\n case\n when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then title || ' integrated with CloudWatch logs.'\n else title || ' not integrated with CloudWatch logs.'\n end as reason\n \n \nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > current_date - 1) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > current_date - 1) THEN title || ' integrated with CloudWatch logs.' + ELSE title || ' not integrated with CloudWatch logs.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.4 Ensure CloudTrail trails are integrated with CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_3_5.yaml b/compliance/controls/aws/aws_cis_v200_3_5.yaml old mode 100755 new mode 100644 index 93666b175..7f45689f0 --- a/compliance/controls/aws/aws_cis_v200_3_5.yaml +++ b/compliance/controls/aws/aws_cis_v200_3_5.yaml @@ -1,15 +1,71 @@ +Description: AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions. ID: aws_cis_v200_3_5 -Title: "3.5 Ensure AWS Config is enabled in all regions" -Description: "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "-- pgFormatter-ignore\n-- Get count for any region with all matching criteria\nwith global_recorders as (\n select\n count(*) as global_config_recorders\n from\n aws_config_configuration_recorder\n where\n recording_group -> 'IncludeGlobalResourceTypes' = 'true'\n and recording_group -> 'AllSupported' = 'true'\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n)\nselect\n 'arn:aws::' || a.region || ':' || a.account_id as resource,\na.og_account_id as og_account_id,\na.og_resource_id as og_resource_id,\n case\n -- When any of the region satisfies with above CTE\n -- In left join of table, regions now having\n -- 'Recording' and 'LastStatus' matching criteria can be considered as OK\n when\n g.global_config_recorders >= 1\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n then 'ok'\n -- Skip any regions that are disabled in the account.\n when a.opt_in_status = 'not-opted-in' then 'skip'\n else 'alarm'\n end as status,\n -- Below cases are for citing respective reasons for control state\n case\n when a.opt_in_status = 'not-opted-in' then a.region || ' region is disabled.'\n else\n case\n when recording_group -> 'IncludeGlobalResourceTypes' = 'true' then a.region || ' IncludeGlobalResourceTypes enabled,'\n else a.region || ' IncludeGlobalResourceTypes disabled,'\n end ||\n case\n when recording_group -> 'AllSupported' = 'true' then ' AllSupported enabled,'\n else ' AllSupported disabled,'\n end ||\n case\n when status ->> 'Recording' = 'true' then ' Recording enabled'\n else ' Recording disabled'\n end ||\n case\n when status ->> 'LastStatus' = 'SUCCESS' then ' and LastStatus is SUCCESS.'\n else ' and LastStatus is not SUCCESS.'\n end\n end as reason\n \nfrom\n global_recorders as g,\n aws_region as a\n left join aws_config_configuration_recorder as r on r.account_id = a.account_id and r.region = a.name;" - PrimaryTable: aws_config_configuration_recorder ListOfTables: - aws_config_configuration_recorder - aws_region Parameters: [] + PrimaryTable: aws_config_configuration_recorder + QueryToExecute: | + WITH global_recorders AS ( + SELECT + COUNT(*) AS global_config_recorders + FROM + aws_config_configuration_recorder + WHERE + recording_group -> 'IncludeGlobalResourceTypes' = 'true' + AND recording_group -> 'AllSupported' = 'true' + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + ) + SELECT + 'arn:aws::' || a.region || ':' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN g.global_config_recorders >= 1 + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + THEN 'ok' + WHEN a.opt_in_status = 'not-opted-in' + THEN 'skip' + ELSE 'alarm' + END AS status, + CASE + WHEN a.opt_in_status = 'not-opted-in' + THEN a.region || ' region is disabled.' + ELSE + CASE + WHEN recording_group -> 'IncludeGlobalResourceTypes' = 'true' + THEN a.region || ' IncludeGlobalResourceTypes enabled,' + ELSE a.region || ' IncludeGlobalResourceTypes disabled,' + END || + CASE + WHEN recording_group -> 'AllSupported' = 'true' + THEN ' AllSupported enabled,' + ELSE ' AllSupported disabled,' + END || + CASE + WHEN status ->> 'Recording' = 'true' + THEN ' Recording enabled' + ELSE ' Recording disabled' + END || + CASE + WHEN status ->> 'LastStatus' = 'SUCCESS' + THEN ' and LastStatus is SUCCESS.' + ELSE ' and LastStatus is not SUCCESS.' + END + END AS reason + FROM + global_recorders AS g, + aws_region AS a + LEFT JOIN + aws_config_configuration_recorder AS r + ON r.account_id = a.account_id + AND r.region = a.name Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.5 Ensure AWS Config is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_3_6.yaml b/compliance/controls/aws/aws_cis_v200_3_6.yaml old mode 100755 new mode 100644 index b1cee0aa5..24aaf2721 --- a/compliance/controls/aws/aws_cis_v200_3_6.yaml +++ b/compliance/controls/aws/aws_cis_v200_3_6.yaml @@ -1,32 +1,32 @@ +Description: S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket. ID: aws_cis_v200_3_6 -Title: "3.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket" -Description: "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - t.arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when b.logging is not null then 'ok' - else 'alarm' - end as status, - case - when b.logging is not null then t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' - else t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' - end as reason - from - aws_cloudtrail_trail t - inner join aws_s3_bucket b on t.s3_bucket_name = b.name - where - t.region = t.home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN b.logging IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.logging IS NOT NULL THEN t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' + ELSE t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' + END AS reason + FROM + aws_cloudtrail_trail t + INNER JOIN aws_s3_bucket b ON t.s3_bucket_name = b.name + WHERE + t.region = t.home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_3_7.yaml b/compliance/controls/aws/aws_cis_v200_3_7.yaml old mode 100755 new mode 100644 index a04e8c978..fb6987045 --- a/compliance/controls/aws/aws_cis_v200_3_7.yaml +++ b/compliance/controls/aws/aws_cis_v200_3_7.yaml @@ -1,14 +1,30 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS. ID: aws_cis_v200_3_7 -Title: "3.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs" -Description: "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kms_key_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_key_id is null then title || ' logs are not encrypted at rest.'\n else title || ' logs are encrypted at rest.'\n end as reason\n \n \nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' logs are not encrypted at rest.' + ELSE title || ' logs are encrypted at rest.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_3_8.yaml b/compliance/controls/aws/aws_cis_v200_3_8.yaml old mode 100755 new mode 100644 index 583e21f14..e451ddfc4 --- a/compliance/controls/aws/aws_cis_v200_3_8.yaml +++ b/compliance/controls/aws/aws_cis_v200_3_8.yaml @@ -1,14 +1,36 @@ +Description: AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK. ID: aws_cis_v200_3_8 -Title: "3.8 Ensure rotation for customer created symmetric CMKs is enabled" -Description: "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when origin = 'EXTERNAL' then 'skip'\n when key_state = 'PendingDeletion' then 'skip'\n when key_state = 'Disabled' then 'skip'\n when not key_rotation_enabled then 'alarm'\n else 'ok'\n end as status,\n case\n when origin = 'EXTERNAL' then title || ' has imported key material.'\n when key_state = 'PendingDeletion' then title || ' is pending deletion.'\n when key_state = 'Disabled' then title || ' is disabled.'\n when not key_rotation_enabled then title || ' key rotation disabled.'\n else title || ' key rotation enabled.'\n end as reason\n \n \nfrom\n aws_kms_key\nwhere\n key_manager = 'CUSTOMER';" - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN origin = 'EXTERNAL' THEN 'skip' + WHEN key_state = 'PendingDeletion' THEN 'skip' + WHEN key_state = 'Disabled' THEN 'skip' + WHEN NOT key_rotation_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN origin = 'EXTERNAL' THEN title || ' has imported key material.' + WHEN key_state = 'PendingDeletion' THEN title || ' is pending deletion.' + WHEN key_state = 'Disabled' THEN title || ' is disabled.' + WHEN NOT key_rotation_enabled THEN title || ' key rotation disabled.' + ELSE title || ' key rotation enabled.' + END AS reason + FROM + aws_kms_key + WHERE + key_manager = 'CUSTOMER'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.8 Ensure rotation for customer created symmetric CMKs is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_3_9.yaml b/compliance/controls/aws/aws_cis_v200_3_9.yaml old mode 100755 new mode 100644 index 80ef47a2b..43aa197ca --- a/compliance/controls/aws/aws_cis_v200_3_9.yaml +++ b/compliance/controls/aws/aws_cis_v200_3_9.yaml @@ -1,11 +1,17 @@ +Description: VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet "Rejects" for VPCs. ID: aws_cis_v200_3_9 -Title: "3.9 Ensure VPC flow logging is enabled in all VPCs" -Description: "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \\\"Rejects\\\" for VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with vpcs as ( - select + ListOfTables: + - aws_vpc + - aws_vpc_flow_log + Parameters: [] + PrimaryTable: aws_vpc + QueryToExecute: | + WITH vpcs AS ( + SELECT arn, account_id, region, @@ -13,44 +19,38 @@ Query: vpc_id, tags, _ctx - from + FROM aws_vpc - order by + ORDER BY vpc_id ), - flowlogs as ( - select + flowlogs AS ( + SELECT resource_id, account_id, region - from + FROM aws_vpc_flow_log - order by + ORDER BY resource_id ) - select - v.arn as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when v.account_id <> v.owner_id then 'skip' - when f.resource_id is not null then 'ok' - else 'alarm' - end as status, - case - when v.account_id <> v.owner_id then v.vpc_id || ' is a shared VPC.' - when f.resource_id is not null then v.vpc_id || ' flow logging enabled.' - else v.vpc_id || ' flow logging disabled.' - end as reason - from - vpcs as v - left join flowlogs as f on v.vpc_id = f.resource_id; - PrimaryTable: aws_vpc - ListOfTables: - - aws_vpc - - aws_vpc_flow_log - Parameters: [] + SELECT + v.arn AS resource, + v.account_id AS og_account_id, + v.vpc_id AS og_resource_id, + CASE + WHEN v.account_id <> v.owner_id THEN 'skip' + WHEN f.resource_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.account_id <> v.owner_id THEN v.vpc_id || ' is a shared VPC.' + WHEN f.resource_id IS NOT NULL THEN v.vpc_id || ' flow logging enabled.' + ELSE v.vpc_id || ' flow logging disabled.' + END AS reason + FROM + vpcs AS v + LEFT JOIN flowlogs AS f ON v.vpc_id = f.resource_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.9 Ensure VPC flow logging is enabled in all VPCs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_4_12.yaml b/compliance/controls/aws/aws_cis_v200_4_12.yaml old mode 100755 new mode 100644 index 7f15273f8..557249005 --- a/compliance/controls/aws/aws_cis_v200_4_12.yaml +++ b/compliance/controls/aws/aws_cis_v200_4_12.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways. ID: aws_cis_v200_4_12 -Title: "4.12 Ensure changes to network gateways are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateCustomerGateway.+\$\.eventName\s*=\s*DeleteCustomerGateway.+\$\.eventName\s*=\s*AttachInternetGateway.+\$\.eventName\s*=\s*CreateInternetGateway.+\$\.eventName\s*=\s*DeleteInternetGateway.+\$\.eventName\s*=\s*DetachInternetGateway' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for changes to network gateways.' - else filter_name || ' forwards events for changes to network gateways.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to network gateways.' + ELSE filter_name || ' forwards events for changes to network gateways.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.12 Ensure changes to network gateways are monitored \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_4_3.yaml b/compliance/controls/aws/aws_cis_v200_4_3.yaml old mode 100755 new mode 100644 index 95ca3a54e..e090a9db6 --- a/compliance/controls/aws/aws_cis_v200_4_3.yaml +++ b/compliance/controls/aws/aws_cis_v200_4_3.yaml @@ -1,10 +1,11 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, + or an external Security information and event management (SIEM) environment, and establishing corresponding + metric filters and alarms. ID: aws_cis_v200_4_3 -Title: "4.3 Ensure usage of 'root' account is monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.userIdentity\\.type\\s*=\\s*\"Root\".+\\$\\.userIdentity\\.invokedBy NOT EXISTS.+\\$\\.eventType\\s*!=\\s*\"AwsServiceEvent\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for usage of \"root\" account.'\n else filter_name || ' forwards events for usage of \"root\" account.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_cloudwatch_alarm @@ -12,7 +13,87 @@ Query: - aws_cloudwatch_log_metric_filter - aws_account Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.userIdentity.type\s*=\s*"Root".+\$.userIdentity.invokedBy NOT EXISTS.+\$.eventType\s*!=\s*"AwsServiceEvent"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for usage of "root" account.' + ELSE filter_name || ' forwards events for usage of "root" account.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.3 Ensure usage of 'root' account is monitored \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_4_6.yaml b/compliance/controls/aws/aws_cis_v200_4_6.yaml old mode 100755 new mode 100644 index 1df40c2d4..a57787eb2 --- a/compliance/controls/aws/aws_cis_v200_4_6.yaml +++ b/compliance/controls/aws/aws_cis_v200_4_6.yaml @@ -1,10 +1,9 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts. ID: aws_cis_v200_4_6 -Title: "4.6 Ensure AWS Management Console authentication failures are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*ConsoleLogin.+\\$\\.errorMessage\\s*=\\s*\"Failed authentication\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n f.account_id as og_account_id,\n f.trail_name as og_resource_id,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console authentication failures.'\n else f.filter_name || ' forwards events for console authentication failures.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_cloudwatch_alarm @@ -12,7 +11,87 @@ Query: - aws_cloudwatch_log_metric_filter - aws_account Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se->>'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*ConsoleLogin.+\$\.errorMessage\s*=\s*"Failed authentication"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + f.account_id AS og_account_id, + f.trail_name AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console authentication failures.' + ELSE f.filter_name || ' forwards events for console authentication failures.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.6 Ensure AWS Management Console authentication failures are monitored \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_5_2.yaml b/compliance/controls/aws/aws_cis_v200_5_2.yaml old mode 100755 new mode 100644 index 98ec9d9cc..f2e896da6 --- a/compliance/controls/aws/aws_cis_v200_5_2.yaml +++ b/compliance/controls/aws/aws_cis_v200_5_2.yaml @@ -1,71 +1,70 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389, using either the TCP (6), UDP (17) or ALL (-1) protocols. ID: aws_cis_v200_5_2 -Title: "5.2 Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389, using either the TCP (6), UDP (17) or ALL (-1) protocols." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT group_id, - count(*) as num_bad_rules - from + COUNT(*) AS num_bad_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and ( + AND ( cidr_ipv4 = '0.0.0.0/0' - or cidr_ipv6 = '::/0' + OR cidr_ipv6 = '::/0' ) - and ( - ( ip_protocol = '-1' -- all traffic - and from_port is null - ) - or ( - from_port >= 22 - and to_port <= 22 - ) - or ( - from_port >= 3389 - and to_port <= 3389 - ) + AND ( + (ip_protocol = '-1' + AND from_port IS NULL) + OR ( + from_port = 22 + AND to_port = 22 + ) + OR ( + from_port = 3389 + AND to_port = 3389 + ) ) - group by + GROUP BY group_id ), - security_groups as ( - select + security_groups AS ( + SELECT arn, tags, region, account_id, group_id, _ctx - from + FROM aws_vpc_security_group - order by + ORDER BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when bad_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - end as reason - from - security_groups as sg - left join bad_rules on bad_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + security_groups AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.2 Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_5_3.yaml b/compliance/controls/aws/aws_cis_v200_5_3.yaml old mode 100755 new mode 100644 index 2f13ce5bf..a7be1e15a --- a/compliance/controls/aws/aws_cis_v200_5_3.yaml +++ b/compliance/controls/aws/aws_cis_v200_5_3.yaml @@ -1,57 +1,56 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_cis_v200_5_3 -Title: "5.3 Ensure no security groups allow ingress from ::/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT group_id, - count(*) as num_bad_rules - from + COUNT(*) AS num_bad_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and ( + AND ( cidr_ipv6 = '::/0' ) - and ( - ( ip_protocol = '-1' -- all traffic - and from_port is null - ) - or ( - from_port >= 22 - and to_port <= 22 - ) - or ( - from_port >= 3389 - and to_port <= 3389 - ) + AND ( + (ip_protocol = '-1' + AND from_port IS NULL) + OR ( + from_port >= 22 + AND to_port <= 22 + ) + OR ( + from_port >= 3389 + AND to_port <= 3389 + ) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when bad_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from ::/0.' - else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from ::/0.' - end as reason - from - aws_vpc_security_group as sg - left join bad_rules on bad_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from ::/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from ::/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.3 Ensure no security groups allow ingress from ::/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_5_4.yaml b/compliance/controls/aws/aws_cis_v200_5_4.yaml old mode 100755 new mode 100644 index 45ebe1abe..68c49e827 --- a/compliance/controls/aws/aws_cis_v200_5_4.yaml +++ b/compliance/controls/aws/aws_cis_v200_5_4.yaml @@ -1,14 +1,36 @@ +Description: A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. ID: aws_cis_v200_5_4 -Title: "5.4 Ensure the default security group of every VPC restricts all traffic" -Description: "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) = 0 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has inbound and outbound rules.'\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) = 0\n then 'Default security group ' || group_id || ' has inbound rules.'\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has outbound rules.'\n else 'Default security group ' || group_id || ' has no inbound or outbound rules.'\n end reason\n \n \nfrom\n aws_vpc_security_group\nwhere\n group_name = 'default';" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(ip_permissions) = 0 + AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(ip_permissions) > 0 + AND jsonb_array_length(ip_permissions_egress) > 0 THEN 'Default security group ' || group_id || ' has inbound and outbound rules.' + WHEN jsonb_array_length(ip_permissions) > 0 + AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'Default security group ' || group_id || ' has inbound rules.' + WHEN jsonb_array_length(ip_permissions) = 0 + AND jsonb_array_length(ip_permissions_egress) > 0 THEN 'Default security group ' || group_id || ' has outbound rules.' + ELSE 'Default security group ' || group_id || ' has no inbound or outbound rules.' + END AS reason + FROM + aws_vpc_security_group + WHERE + group_name = 'default'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.4 Ensure the default security group of every VPC restricts all traffic \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_5_5.yaml b/compliance/controls/aws/aws_cis_v200_5_5.yaml old mode 100755 new mode 100644 index 12aedfba0..e4499292f --- a/compliance/controls/aws/aws_cis_v200_5_5.yaml +++ b/compliance/controls/aws/aws_cis_v200_5_5.yaml @@ -1,14 +1,22 @@ +Description: Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection. ID: aws_cis_v200_5_5 -Title: "5.5 Ensure routing tables for VPC peering are \\\"least access\\\"" -Description: "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.5 Ensure routing tables for VPC peering are "least access" \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v200_5_6.yaml b/compliance/controls/aws/aws_cis_v200_5_6.yaml old mode 100755 new mode 100644 index a3dbe8883..320a44a00 --- a/compliance/controls/aws/aws_cis_v200_5_6.yaml +++ b/compliance/controls/aws/aws_cis_v200_5_6.yaml @@ -1,14 +1,28 @@ +Description: When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method). ID: aws_cis_v200_5_6 -Title: "5.6 Ensure that EC2 Metadata Service only allows IMDSv2" -Description: "When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when metadata_options ->> 'HttpTokens' = 'optional' then 'alarm'\n else 'ok'\n end as status,\n case\n when metadata_options ->> 'HttpTokens' = 'optional' then title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).'\n else title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).'\n end as reason\n \n \nfrom\n aws_ec2_instance;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' + ELSE title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' + END AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.6 Ensure that EC2 Metadata Service only allows IMDSv2 \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_1.yaml b/compliance/controls/aws/aws_cis_v300_1_1.yaml old mode 100755 new mode 100644 index bda945900..abe17b598 --- a/compliance/controls/aws/aws_cis_v300_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_1.yaml @@ -1,14 +1,22 @@ +Description: Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. ID: aws_cis_v300_1_1 -Title: "1.1 Maintain current contact details" -Description: "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.1 Maintain current contact details \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_10.yaml b/compliance/controls/aws/aws_cis_v300_1_10.yaml old mode 100755 new mode 100644 index 819b1b29b..75bcdc78a --- a/compliance/controls/aws/aws_cis_v300_1_10.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_10.yaml @@ -1,29 +1,29 @@ +Description: Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password. ID: aws_cis_v300_1_10 -Title: "1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password" -Description: "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when password_enabled and not mfa_active then 'alarm' - else 'ok' - end as status, - case - when not password_enabled then user_name || ' password login disabled.' - when password_enabled and not mfa_active then user_name || ' password login enabled but no MFA device configured.' - else user_name || ' password login enabled and MFA device configured.' - end as reason - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND NOT mfa_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN password_enabled AND NOT mfa_active THEN user_name || ' password login enabled but no MFA device configured.' + ELSE user_name || ' password login enabled and MFA device configured.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.10 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_11.yaml b/compliance/controls/aws/aws_cis_v300_1_11.yaml old mode 100755 new mode 100644 index f7e7c2ff6..d6dcb9a4f --- a/compliance/controls/aws/aws_cis_v300_1_11.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_11.yaml @@ -1,32 +1,36 @@ +Description: AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require. ID: aws_cis_v300_1_11 -Title: "1.11 Do not setup access keys during initial user setup for all IAM users that have a console password" -Description: "AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - -- alarm when password is enabled and the key was created within 10 seconds of the user - when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) then 'alarm' - else 'ok' - end as status, - case - when not password_enabled then user_name || ' password login disabled.' - when access_key_1_last_rotated is null then user_name || ' has no access keys.' - when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) - then user_name || ' has access key created during user creation and password login enabled.' - else user_name || ' has access key not created during user creation.' - end as reason - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled + AND (EXTRACT(EPOCH FROM (access_key_1_last_rotated - user_creation_time)) < 10) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled + THEN user_name || ' password login disabled.' + WHEN access_key_1_last_rotated IS NULL + THEN user_name || ' has no access keys.' + WHEN password_enabled + AND (EXTRACT(EPOCH FROM (access_key_1_last_rotated - user_creation_time)) < 10) + THEN user_name || ' has access key created during user creation and password login enabled.' + ELSE user_name || ' has access key not created during user creation.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.11 Do not setup access keys during initial user setup for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_12.yaml b/compliance/controls/aws/aws_cis_v300_1_12.yaml old mode 100755 new mode 100644 index 62cb799ce..542d2b8ef --- a/compliance/controls/aws/aws_cis_v300_1_12.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_12.yaml @@ -1,14 +1,62 @@ +Description: AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed. ID: aws_cis_v300_1_12 -Title: "1.12 Ensure credentials unused for 45 days or greater are disabled" -Description: "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n --root_account will have always password associated even though AWS credential report returns 'not_supported' for password_enabled\n when user_name = ''\n then 'info'\n when password_enabled and password_last_used is null and password_last_changed < (current_date - interval '45' day)\n then 'alarm'\n when password_enabled and password_last_used < (current_date - interval '45' day)\n then 'alarm'\n when access_key_1_active and access_key_1_last_used_date is null and access_key_1_last_rotated < (current_date - interval '45' day)\n then 'alarm'\n when access_key_1_active and access_key_1_last_used_date < (current_date - interval '45' day)\n then 'alarm'\n when access_key_2_active and access_key_2_last_used_date is null and access_key_2_last_rotated < (current_date - interval '45' day)\n then 'alarm'\n when access_key_2_active and access_key_2_last_used_date < (current_date - interval '45' day)\n then 'alarm'\n else 'ok'\n end status,\n user_name ||\n case\n when not password_enabled\n then ' password not enabled,'\n when password_enabled and password_last_used is null\n then ' password created ' || to_char(password_last_changed, 'DD-Mon-YYYY') || ' never used,'\n else\n ' password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_1_active\n then ' key 1 not enabled,'\n when access_key_1_active and access_key_1_last_used_date is null\n then ' key 1 created ' || to_char(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,'\n else\n ' key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_2_active\n then ' key 2 not enabled.'\n when access_key_2_active and access_key_2_last_used_date is null\n then ' key 2 created ' || to_char(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.'\n else\n ' key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.'\n end\n as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_name = '' + THEN 'info' + WHEN password_enabled AND password_last_used IS NULL AND password_last_changed < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN password_enabled AND password_last_used < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL AND access_key_1_last_rotated < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL AND access_key_2_last_rotated < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date < (CURRENT_DATE - INTERVAL '45' DAY) + THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || + CASE + WHEN NOT password_enabled + THEN ' password not enabled,' + WHEN password_enabled AND password_last_used IS NULL + THEN ' password created ' || TO_CHAR(password_last_changed, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_1_active + THEN ' key 1 not enabled,' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL + THEN ' key 1 created ' || TO_CHAR(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_2_active + THEN ' key 2 not enabled.' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL + THEN ' key 2 created ' || TO_CHAR(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' + ELSE + ' key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.12 Ensure credentials unused for 45 days or greater are disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_14.yaml b/compliance/controls/aws/aws_cis_v300_1_14.yaml old mode 100755 new mode 100644 index 7d2799e4e..2827e2344 --- a/compliance/controls/aws/aws_cis_v300_1_14.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_14.yaml @@ -1,14 +1,26 @@ +Description: Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated. ID: aws_cis_v300_1_14 -Title: "1.14 Ensure access keys are rotated every 90 days or less" -Description: "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when create_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end status,\n user_name || ' ' || access_key_id || ' created ' || to_char(create_date , 'DD-Mon-YYYY') ||\n ' (' || extract(day from current_timestamp - create_date) || ' days).'\n as reason\n \nfrom\n aws_iam_access_key;" - PrimaryTable: aws_iam_access_key ListOfTables: - aws_iam_access_key Parameters: [] + PrimaryTable: aws_iam_access_key + QueryToExecute: | + SELECT + 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_date <= (current_date - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || ' ' || access_key_id || ' created ' || TO_CHAR(create_date, 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM current_timestamp - create_date) || ' days).' AS reason + FROM + aws_iam_access_key; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.14 Ensure access keys are rotated every 90 days or less \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_15.yaml b/compliance/controls/aws/aws_cis_v300_1_15.yaml old mode 100755 new mode 100644 index 989970c88..0d5cf9023 --- a/compliance/controls/aws/aws_cis_v300_1_15.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_15.yaml @@ -1,14 +1,27 @@ +Description: 'IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended.' ID: aws_cis_v300_1_15 -Title: "1.15 Ensure IAM Users Receive Permissions Only Through Groups" -Description: "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when inline_policies is null and attached_policy_arns is null then 'ok'\n else 'alarm'\n end status,\n name || ' has ' || coalesce(jsonb_array_length(inline_policies),0) || ' inline and ' ||\n coalesce(jsonb_array_length(attached_policy_arns),0) || ' directly attached policies.' as reason\n \n \nfrom\n aws_iam_user;" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN inline_policies IS NULL AND attached_policy_arns IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' has ' || COALESCE(jsonb_array_length(inline_policies), 0) || + ' inline and ' || COALESCE(jsonb_array_length(attached_policy_arns), 0) || + ' directly attached policies.' AS reason + FROM + aws_iam_user; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.15 Ensure IAM Users Receive Permissions Only Through Groups \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_16.yaml b/compliance/controls/aws/aws_cis_v300_1_16.yaml old mode 100755 new mode 100644 index c6c0dc116..c29588b9f --- a/compliance/controls/aws/aws_cis_v300_1_16.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_16.yaml @@ -1,55 +1,53 @@ +Description: IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges. ID: aws_cis_v300_1_16 -Title: "1.16 Ensure IAM policies that allow full \\\"*:*\\\" administrative privileges are not attached" -Description: "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with star_access_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH star_access_policies AS ( + SELECT arn, is_aws_managed, - count(*) as num_bad_statements - from + COUNT(*) AS num_bad_statements + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - (action = '*' - or action = '*:*' - ) + AND resource = '*' + AND ( + action = '*' OR action = '*:*' ) - and is_attached - group by + AND is_attached + GROUP BY arn, is_aws_managed ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when s.arn is not null and s.is_aws_managed then 'info' - when s.arn is null then 'ok' - else 'alarm' - end status, - case - when s.arn is not null and s.is_aws_managed then p.name || ' is an AWS managed policy with ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - else p.name || ' contains ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' - end as reason - from - aws_iam_policy as p - left join star_access_policies as s on p.arn = s.arn - where + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN 'info' + WHEN s.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN p.name || ' is an AWS managed policy with ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + ELSE p.name || ' contains ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + END AS reason + FROM + aws_iam_policy AS p + LEFT JOIN star_access_policies AS s ON p.arn = s.arn + WHERE p.is_attached; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.16 Ensure IAM policies that allow full "*:*" administrative privileges are not attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_17.yaml b/compliance/controls/aws/aws_cis_v300_1_17.yaml old mode 100755 new mode 100644 index c1e341847..67b5dcdf5 --- a/compliance/controls/aws/aws_cis_v300_1_17.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_17.yaml @@ -1,54 +1,52 @@ +Description: AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support. ID: aws_cis_v300_1_17 -Title: "1.17 Ensure a support role has been created to manage incidents with AWS Support" -Description: "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - -- pgFormatter-ignore - with support_role_count as - ( - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - count(policy_arn), + ListOfTables: + - aws_account + - aws_iam_role + Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH support_role_count AS ( + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + COUNT(policy_arn), a.account_id, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, a._ctx - from - aws_account as a - left join aws_iam_role as r on r.account_id = a.account_id - left join jsonb_array_elements_text(attached_policy_arns) as policy_arn on true - where - split_part(policy_arn, '/', 2) = 'AWSSupportAccess' - or policy_arn is null - group by + FROM + aws_account AS a + LEFT JOIN aws_iam_role AS r ON r.account_id = a.account_id + LEFT JOIN jsonb_array_elements_text(attached_policy_arns) AS policy_arn ON TRUE + WHERE + SPLIT_PART(policy_arn, '/', 2) = 'AWSSupportAccess' + OR policy_arn IS NULL + GROUP BY a.account_id, a.partition, a.og_account_id, a.og_resource_id, a._ctx ) - select + SELECT resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when count > 0 then 'ok' - else 'alarm' - end as status, - case - when count = 1 then 'AWSSupportAccess policy attached to 1 role.' - when count > 1 then 'AWSSupportAccess policy attached to ' || count || ' roles.' - else 'AWSSupportAccess policy not attached to any role.' - end as reason - from + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN count = 1 THEN 'AWSSupportAccess policy attached to 1 role.' + WHEN count > 1 THEN 'AWSSupportAccess policy attached to ' || count || ' roles.' + ELSE 'AWSSupportAccess policy not attached to any role.' + END AS reason + FROM support_role_count; - PrimaryTable: aws_iam_role - ListOfTables: - - aws_account - - aws_iam_role - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.17 Ensure a support role has been created to manage incidents with AWS Support \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_18.yaml b/compliance/controls/aws/aws_cis_v300_1_18.yaml old mode 100755 new mode 100644 index b2af7a4eb..d7d1047c9 --- a/compliance/controls/aws/aws_cis_v300_1_18.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_18.yaml @@ -1,14 +1,22 @@ +Description: AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. "AWS Access" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources. ID: aws_cis_v300_1_18 -Title: "1.18 Ensure IAM instance roles are used for AWS resource access from instances" -Description: "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \\\"AWS Access\\\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.18 Ensure IAM instance roles are used for AWS resource access from instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_19.yaml b/compliance/controls/aws/aws_cis_v300_1_19.yaml old mode 100755 new mode 100644 index 0b62e0e09..da3956a28 --- a/compliance/controls/aws/aws_cis_v300_1_19.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_19.yaml @@ -1,14 +1,30 @@ +Description: To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console. ID: aws_cis_v300_1_19 -Title: "1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed" -Description: "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case when expiration < (current_date - interval '1' second) then 'alarm'\n else 'ok'\n end as status,\n case when expiration < (current_date - interval '1' second) then\n name || ' expired ' || to_char(expiration, 'DD-Mon-YYYY') || '.'\n else\n name || ' valid until ' || to_char(expiration, 'DD-Mon-YYYY') || '.'\n end as reason\n \n \nfrom\n aws_iam_server_certificate;" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: [] + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN expiration < (current_date - INTERVAL '1' SECOND) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expiration < (current_date - INTERVAL '1' SECOND) THEN + name || ' expired ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + ELSE + name || ' valid until ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_iam_server_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.19 Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_2.yaml b/compliance/controls/aws/aws_cis_v300_1_2.yaml old mode 100755 new mode 100644 index 9dc158054..a8b10e658 --- a/compliance/controls/aws/aws_cis_v300_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_2.yaml @@ -1,56 +1,55 @@ +Description: AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided. ID: aws_cis_v300_1_2 -Title: "1.2 Ensure security contact information is registered" -Description: "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alternate_security_contact as ( - select - name, - account_id - from - aws_account_alternate_contact - where - contact_type = 'SECURITY' - ), - account as ( - select - arn, - partition, - title, - account_id, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - _ctx - from - aws_account - ) - select - arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.partition = 'aws-us-gov' then 'info' - -- Name is a required field if setting a security contact - when c.name is not null then 'ok' - else 'alarm' - end as status, - case - when a.partition = 'aws-us-gov' then a.title || ' in GovCloud, manual verification required.' - when c.name is not null then a.title || ' has security contact ' || c.name || ' registered.' - else a.title || ' security contact not registered.' - end as reason - from - account as a, - alternate_security_contact as c - where - c.account_id = a.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account_alternate_contact - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH alternate_security_contact AS ( + SELECT + name, + account_id + FROM + aws_account_alternate_contact + WHERE + contact_type = 'SECURITY' + ), + account AS ( + SELECT + arn, + partition, + title, + account_id, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + _ctx + FROM + aws_account + ) + SELECT + arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.partition = 'aws-us-gov' THEN 'info' + WHEN c.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.partition = 'aws-us-gov' THEN a.title || ' in GovCloud, manual verification required.' + WHEN c.name IS NOT NULL THEN a.title || ' has security contact ' || c.name || ' registered.' + ELSE a.title || ' security contact not registered.' + END AS reason + FROM + account AS a, + alternate_security_contact AS c + WHERE + c.account_id = a.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.2 Ensure security contact information is registered \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_20.yaml b/compliance/controls/aws/aws_cis_v300_1_20.yaml old mode 100755 new mode 100644 index 25d408756..179cebc60 --- a/compliance/controls/aws/aws_cis_v300_1_20.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_20.yaml @@ -1,15 +1,35 @@ +Description: Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region. ID: aws_cis_v300_1_20 -Title: "1.20 Ensure that IAM Access analyzer is enabled for all regions" -Description: "Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource,\n r.og_account_id as og_account_id,\n r.og_resource_id as og_resource_id,\n case\n -- Skip any regions that are disabled in the account.\n when r.opt_in_status = 'not-opted-in' then 'skip'\n when aa.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.'\n when aa.arn is not null then aa.name || ' enabled in ' || r.region || '.'\n else 'Access Analyzer not enabled in ' || r.region || '.'\n end as reason\n \nfrom\n aws_region as r\n left join aws_accessanalyzer_analyzer as aa on r.account_id = aa.account_id and r.region = aa.region;" - PrimaryTable: aws_accessanalyzer_analyzer ListOfTables: - aws_region - aws_accessanalyzer_analyzer Parameters: [] + PrimaryTable: aws_accessanalyzer_analyzer + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN aa.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN aa.arn IS NOT NULL THEN aa.name || ' enabled in ' || r.region || '.' + ELSE 'Access Analyzer not enabled in ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN + aws_accessanalyzer_analyzer AS aa + ON + r.account_id = aa.account_id AND r.region = aa.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.20 Ensure that IAM Access analyzer is enabled for all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_21.yaml b/compliance/controls/aws/aws_cis_v300_1_21.yaml old mode 100755 new mode 100644 index 3ad0a109d..bcd81ff98 --- a/compliance/controls/aws/aws_cis_v300_1_21.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_21.yaml @@ -1,14 +1,22 @@ +Description: In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provide via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations. ID: aws_cis_v300_1_21 -Title: "1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments" -Description: "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provide via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.21 Ensure IAM users are managed centrally via identity federation or AWS Organizations for multi-account environments \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_3.yaml b/compliance/controls/aws/aws_cis_v300_1_3.yaml old mode 100755 new mode 100644 index ceb9627c5..89dfc1bd9 --- a/compliance/controls/aws/aws_cis_v300_1_3.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_3.yaml @@ -1,23 +1,22 @@ +Description: The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established. ID: aws_cis_v300_1_3 -Title: "1.3 Ensure security questions are registered in the AWS account" -Description: "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || partition || ':::' || account_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason - - from - aws_account; - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.3 Ensure security questions are registered in the AWS account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_4.yaml b/compliance/controls/aws/aws_cis_v300_1_4.yaml old mode 100755 new mode 100644 index a598b0f15..bb7d7ce01 --- a/compliance/controls/aws/aws_cis_v300_1_4.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_4.yaml @@ -1,14 +1,28 @@ +Description: The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be deleted. ID: aws_cis_v300_1_4 -Title: "1.4 Ensure no 'root' user account access key exists" -Description: "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be deleted." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_access_keys_present > 0 then 'alarm'\n else 'ok'\n end status,\n case\n when account_access_keys_present > 0 then 'Root user access keys exist.'\n else 'No root user access keys exist.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_access_keys_present > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN account_access_keys_present > 0 THEN 'Root user access keys exist.' + ELSE 'No root user access keys exist.' + END AS reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.4 Ensure no 'root' user account access key exists \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_5.yaml b/compliance/controls/aws/aws_cis_v300_1_5.yaml old mode 100755 new mode 100644 index 3a0289043..d597685c1 --- a/compliance/controls/aws/aws_cis_v300_1_5.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_5.yaml @@ -1,14 +1,28 @@ +Description: The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. ID: aws_cis_v300_1_5 -Title: "1.5 Ensure MFA is enabled for the 'root' user account" -Description: "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_mfa_enabled then 'ok'\n else 'alarm'\n end status,\n case\n when account_mfa_enabled then 'MFA enabled for root account.'\n else 'MFA not enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_mfa_enabled THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN account_mfa_enabled THEN 'MFA enabled for root account.' + ELSE 'MFA not enabled for root account.' + END reason + FROM + aws_iam_account_summary; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.5 Ensure MFA is enabled for the 'root' user account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_6.yaml b/compliance/controls/aws/aws_cis_v300_1_6.yaml old mode 100755 new mode 100644 index b452b9160..2acc874df --- a/compliance/controls/aws/aws_cis_v300_1_6.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_6.yaml @@ -1,31 +1,33 @@ +Description: The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root user account be protected with a hardware MFA. ID: aws_cis_v300_1_6 -Title: "1.6 Ensure hardware MFA is enabled for the 'root' user account" -Description: "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root user account be protected with a hardware MFA." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || s.partition || ':::' || s.account_id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when s.account_mfa_enabled and d.serial_number is null then 'ok' - else 'alarm' - end status, - case - when s.account_mfa_enabled = false then 'MFA not enabled for root account.' - when d.serial_number is not null then 'MFA enabled for root account, but the MFA associated is a virtual device.' - else 'Hardware MFA device enabled for root account.' - end reason - from - aws_iam_account_summary as s - left join aws_iam_virtual_mfa_device as d on (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root'; - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary - aws_iam_virtual_mfa_device Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || s.partition || ':::' || s.account_id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN s.account_mfa_enabled AND d.serial_number IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.account_mfa_enabled = FALSE THEN 'MFA not enabled for root account.' + WHEN d.serial_number IS NOT NULL THEN 'MFA enabled for root account, but the MFA associated is a virtual device.' + ELSE 'Hardware MFA device enabled for root account.' + END AS reason + FROM + aws_iam_account_summary AS s + LEFT JOIN + aws_iam_virtual_mfa_device AS d + ON (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.6 Ensure hardware MFA is enabled for the 'root' user account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_7.yaml b/compliance/controls/aws/aws_cis_v300_1_7.yaml old mode 100755 new mode 100644 index 31a2af62c..a068c7267 --- a/compliance/controls/aws/aws_cis_v300_1_7.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_7.yaml @@ -1,14 +1,40 @@ +Description: With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks. ID: aws_cis_v300_1_7 -Title: "1.7 Eliminate use of the 'root' user for administrative and daily tasks" -Description: "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when password_last_used >= (current_date - interval '90' day) then 'alarm'\n when access_key_1_last_used_date <= (current_date - interval '90' day) then 'alarm'\n when access_key_2_last_used_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end as status,\n case\n when password_last_used is null then 'Root never logged in with password.'\n else 'Root password used ' || to_char(password_last_used , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - password_last_used) || ' days).'\n end ||\n case\n when access_key_1_last_used_date is null then ' Access Key 1 never used.'\n else ' Access Key 1 used ' || to_char(access_key_1_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_1_last_used_date) || ' days).'\n end ||\n case\n when access_key_2_last_used_date is null then ' Access Key 2 never used.'\n else ' Access Key 2 used ' || to_char(access_key_2_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_2_last_used_date) || ' days).'\n end as reason\n \nfrom\n aws_iam_credential_report\nwhere\n user_name = '';" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_last_used >= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + WHEN access_key_1_last_used_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + WHEN access_key_2_last_used_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN password_last_used IS NULL THEN 'Root never logged in with password.' + ELSE 'Root password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - password_last_used) || ' days).' + END || + CASE + WHEN access_key_1_last_used_date IS NULL THEN ' Access Key 1 never used.' + ELSE ' Access Key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - access_key_1_last_used_date) || ' days).' + END || + CASE + WHEN access_key_2_last_used_date IS NULL THEN ' Access Key 2 never used.' + ELSE ' Access Key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - access_key_2_last_used_date) || ' days).' + END AS reason + FROM + aws_iam_credential_report + WHERE + user_name = ''; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.7 Eliminate use of the 'root' user for administrative and daily tasks \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_1_8.yaml b/compliance/controls/aws/aws_cis_v300_1_8.yaml old mode 100755 new mode 100644 index 7aabbd2d8..28cd4760e --- a/compliance/controls/aws/aws_cis_v300_1_8.yaml +++ b/compliance/controls/aws/aws_cis_v300_1_8.yaml @@ -1,30 +1,33 @@ +Description: Password policies are, in part, used to enforce password complexity requirements. + IAM password policies can be used to ensure password are at least a given length. + It is recommended that the password policy require a minimum password length of 14. ID: aws_cis_v300_1_8 -Title: "1.8 Ensure IAM password policy requires minimum length of 14 or greater" -Description: "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when minimum_password_length >= 14 then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - else 'Minimum password length set to ' || minimum_password_length || '.' - end as reason - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN minimum_password_length >= 14 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + ELSE 'Minimum password length set to ' || minimum_password_length || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.8 Ensure IAM password policy requires minimum length of 14 or greater \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_2_1_1.yaml b/compliance/controls/aws/aws_cis_v300_2_1_1.yaml old mode 100755 new mode 100644 index 7c15a5c97..bf1deb02c --- a/compliance/controls/aws/aws_cis_v300_2_1_1.yaml +++ b/compliance/controls/aws/aws_cis_v300_2_1_1.yaml @@ -1,49 +1,47 @@ +Description: At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS. ID: aws_cis_v300_2_1_1 -Title: "2.1.1 Ensure S3 Bucket Policy is set to deny HTTP requests" -Description: "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ssl_ok as ( - select - distinct name, + ListOfTables: + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH ssl_ok AS ( + SELECT + DISTINCT name, arn, - 'ok' as status - from + 'ok' AS status + FROM aws_s3_bucket, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p, - jsonb_array_elements_text(s -> 'Action') as a, - jsonb_array_elements_text(s -> 'Resource') as r, - jsonb_array_elements_text( - s -> 'Condition' -> 'Bool' -> 'aws:securetransport' - ) as ssl - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + jsonb_array_elements_text(s -> 'Action') AS a, + jsonb_array_elements_text(s -> 'Resource') AS r, + jsonb_array_elements_text(s -> 'Condition' -> 'Bool' -> 'aws:securetransport') AS ssl + WHERE p = '*' - and s ->> 'Effect' = 'Deny' - and ssl :: bool = false + AND s ->> 'Effect' = 'Deny' + AND ssl::bool = FALSE ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when ok.status = 'ok' then 'ok' - else 'alarm' - end status, - case - when ok.status = 'ok' then b.name || ' bucket policy enforces HTTPS.' - else b.name || ' bucket policy does not enforce HTTPS.' - end reason - from - aws_s3_bucket as b - left join ssl_ok as ok on ok.name = b.name; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_s3_bucket - Parameters: [] + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN ok.status = 'ok' THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN ok.status = 'ok' THEN b.name || ' bucket policy enforces HTTPS.' + ELSE b.name || ' bucket policy does not enforce HTTPS.' + END reason + FROM + aws_s3_bucket AS b + LEFT JOIN ssl_ok AS ok ON ok.name = b.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.1 Ensure S3 Bucket Policy is set to deny HTTP requests \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_2_1_2.yaml b/compliance/controls/aws/aws_cis_v300_2_1_2.yaml old mode 100755 new mode 100644 index 7cb012270..fb48d4d1e --- a/compliance/controls/aws/aws_cis_v300_2_1_2.yaml +++ b/compliance/controls/aws/aws_cis_v300_2_1_2.yaml @@ -1,14 +1,28 @@ +Description: Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication. ID: aws_cis_v300_2_1_2 -Title: "2.1.2 Ensure MFA Delete is enabled on S3 buckets" -Description: "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when versioning_mfa_delete then 'ok'\n else 'alarm'\n end as status,\n case\n when versioning_mfa_delete then name || ' MFA delete enabled.'\n else name || ' MFA delete disabled.'\n end as reason\n \n \nfrom\n aws_s3_bucket;" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN versioning_mfa_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN versioning_mfa_delete THEN name || ' MFA delete enabled.' + ELSE name || ' MFA delete disabled.' + END AS reason + FROM + aws_s3_bucket; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.2 Ensure MFA Delete is enabled on S3 buckets \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_2_1_3.yaml b/compliance/controls/aws/aws_cis_v300_2_1_3.yaml old mode 100755 new mode 100644 index 56daf9df3..db8450c0f --- a/compliance/controls/aws/aws_cis_v300_2_1_3.yaml +++ b/compliance/controls/aws/aws_cis_v300_2_1_3.yaml @@ -1,40 +1,40 @@ +Description: Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets. ID: aws_cis_v300_2_1_3 -Title: "2.1.3 Ensure all data in Amazon S3 has been discovered, classified and secured when required" -Description: "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bucket_list as ( - select - trim(b::text, '"' ) as bucket_name - from - aws_macie2_classification_job, - jsonb_array_elements(s3_job_definition -> 'BucketDefinitions') as d, - jsonb_array_elements(d -> 'Buckets') as b - ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when b.region = any(array['us-gov-east-1', 'us-gov-west-1']) then 'skip' - when l.bucket_name is not null then 'ok' - else 'alarm' - end as status, - case - when b.region = any(array['us-gov-east-1', 'us-gov-west-1']) then b.title || ' not protected by Macie as Macie is not supported in ' || b.region || '.' - when l.bucket_name is not null then b.title || ' protected by Macie.' - else b.title || ' not protected by Macie.' - end as reason - from - aws_s3_bucket as b - left join bucket_list as l on b.name = l.bucket_name; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_macie2_classification_job - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH bucket_list AS ( + SELECT + TRIM(b::text, '"' ) AS bucket_name + FROM + aws_macie2_classification_job, + JSONB_ARRAY_ELEMENTS(s3_job_definition -> 'BucketDefinitions') AS d, + JSONB_ARRAY_ELEMENTS(d -> 'Buckets') AS b + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN b.region = ANY(ARRAY['us-gov-east-1', 'us-gov-west-1']) THEN 'skip' + WHEN l.bucket_name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.region = ANY(ARRAY['us-gov-east-1', 'us-gov-west-1']) THEN b.title || ' not protected by Macie as Macie is not supported in ' || b.region || '.' + WHEN l.bucket_name IS NOT NULL THEN b.title || ' protected by Macie.' + ELSE b.title || ' not protected by Macie.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN bucket_list AS l ON b.name = l.bucket_name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.3 Ensure all data in Amazon S3 has been discovered, classified and secured when required \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_2_2_1.yaml b/compliance/controls/aws/aws_cis_v300_2_2_1.yaml old mode 100755 new mode 100644 index 970b04a8a..bc1c8019d --- a/compliance/controls/aws/aws_cis_v300_2_2_1.yaml +++ b/compliance/controls/aws/aws_cis_v300_2_2_1.yaml @@ -1,28 +1,28 @@ +Description: Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported. ID: aws_cis_v300_2_2_1 -Title: "2.2.1 Ensure EBS Volume Encryption is Enabled in all Regions" -Description: "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when encrypted then 'ok' - else 'alarm' - end as status, - case - when encrypted then volume_id || ' encrypted.' - else volume_id || ' not encrypted.' - end as reason - from - aws_ebs_volume; - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN volume_id || ' encrypted.' + ELSE volume_id || ' not encrypted.' + END AS reason + FROM + aws_ebs_volume; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.2.1 Ensure EBS Volume Encryption is Enabled in all Regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_2_3_1.yaml b/compliance/controls/aws/aws_cis_v300_2_3_1.yaml old mode 100755 new mode 100644 index 0783c3a10..86410e152 --- a/compliance/controls/aws/aws_cis_v300_2_3_1.yaml +++ b/compliance/controls/aws/aws_cis_v300_2_3_1.yaml @@ -1,14 +1,28 @@ +Description: Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance. ID: aws_cis_v300_2_3_1 -Title: "2.3.1 Ensure that encryption-at-rest is enabled for RDS Instances" -Description: "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_rds_db_instance;" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3.1 Ensure that encryption-at-rest is enabled for RDS Instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_2_3_2.yaml b/compliance/controls/aws/aws_cis_v300_2_3_2.yaml old mode 100755 new mode 100644 index 46e598b8d..99c154e1c --- a/compliance/controls/aws/aws_cis_v300_2_3_2.yaml +++ b/compliance/controls/aws/aws_cis_v300_2_3_2.yaml @@ -1,28 +1,28 @@ +Description: Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines. ID: aws_cis_v300_2_3_2 -Title: "2.3.2 Ensure Auto Minor Version Upgrade feature is Enabled for RDS Instances" -Description: "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when auto_minor_version_upgrade then 'ok' - else 'alarm' - end as status, - case - when auto_minor_version_upgrade then title || ' automatic minor version upgrades enabled.' - else title || ' automatic minor version upgrades not enabled.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrades enabled.' + ELSE title || ' automatic minor version upgrades not enabled.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3.2 Ensure Auto Minor Version Upgrade feature is Enabled for RDS Instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_2_3_3.yaml b/compliance/controls/aws/aws_cis_v300_2_3_3.yaml old mode 100755 new mode 100644 index 15dea6ad0..136bb06cc --- a/compliance/controls/aws/aws_cis_v300_2_3_3.yaml +++ b/compliance/controls/aws/aws_cis_v300_2_3_3.yaml @@ -1,14 +1,28 @@ +Description: Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance. ID: aws_cis_v300_2_3_3 -Title: "2.3.3 Ensure that public access is not given to RDS Instance" -Description: "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when publicly_accessible then 'alarm'\n else 'ok'\n end status,\n case\n when publicly_accessible then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end reason\n \n \nfrom\n aws_rds_db_instance;" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.3.3 Ensure that public access is not given to RDS Instance \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_2_4_1.yaml b/compliance/controls/aws/aws_cis_v300_2_4_1.yaml old mode 100755 new mode 100644 index 6d9cab764..4d533fd85 --- a/compliance/controls/aws/aws_cis_v300_2_4_1.yaml +++ b/compliance/controls/aws/aws_cis_v300_2_4_1.yaml @@ -1,14 +1,28 @@ +Description: EFS data should be encrypted at rest using AWS KMS (Key Management Service). ID: aws_cis_v300_2_4_1 -Title: "2.4.1 Ensure that encryption is enabled for EFS file systems" -Description: "EFS data should be encrypted at rest using AWS KMS (Key Management Service)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_efs_file_system;" - PrimaryTable: aws_efs_file_system ListOfTables: - aws_efs_file_system Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_efs_file_system; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.4.1 Ensure that encryption is enabled for EFS file systems \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_3_2.yaml b/compliance/controls/aws/aws_cis_v300_3_2.yaml old mode 100755 new mode 100644 index bbdb5cff5..4c700b943 --- a/compliance/controls/aws/aws_cis_v300_3_2.yaml +++ b/compliance/controls/aws/aws_cis_v300_3_2.yaml @@ -1,14 +1,30 @@ +Description: CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails. ID: aws_cis_v300_3_2 -Title: "3.2 Ensure CloudTrail log file validation is enabled" -Description: "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_file_validation_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when log_file_validation_enabled then title || ' log file validation enabled.'\n else title || ' log file validation disabled.'\n end as reason\n \n \nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_file_validation_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_file_validation_enabled THEN title || ' log file validation enabled.' + ELSE title || ' log file validation disabled.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.2 Ensure CloudTrail log file validation is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_3_3.yaml b/compliance/controls/aws/aws_cis_v300_3_3.yaml old mode 100755 new mode 100644 index 14dbc2424..bfe59de08 --- a/compliance/controls/aws/aws_cis_v300_3_3.yaml +++ b/compliance/controls/aws/aws_cis_v300_3_3.yaml @@ -1,10 +1,14 @@ +Description: AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions. ID: aws_cis_v300_3_3 -Title: "3.3 Ensure AWS Config is enabled in all regions" -Description: "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions." IntegrationType: - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_config_configuration_recorder + - aws_region + Parameters: [] + PrimaryTable: aws_config_configuration_recorder QueryToExecute: | WITH global_recorders AS ( SELECT @@ -17,47 +21,53 @@ Query: AND status ->> 'Recording' = 'true' AND status ->> 'LastStatus' = 'SUCCESS' ) + SELECT 'arn:aws::' || a.region || ':' || a.account_id AS resource, r.og_account_id AS og_account_id, r.og_resource_id AS og_resource_id, CASE - WHEN - g.global_config_recorders >= 1 + WHEN g.global_config_recorders >= 1 AND status ->> 'Recording' = 'true' AND status ->> 'LastStatus' = 'SUCCESS' THEN 'OK' - WHEN a.opt_in_status = 'not-opted-in' THEN 'SKIP' + WHEN a.opt_in_status = 'not-opted-in' + THEN 'SKIP' ELSE 'ALARM' END AS status, CASE - WHEN a.opt_in_status = 'not-opted-in' THEN a.region || ' region is disabled.' + WHEN a.opt_in_status = 'not-opted-in' + THEN a.region || ' region is disabled.' ELSE CASE - WHEN recording_group -> 'IncludeGlobalResourceTypes' = 'true' THEN a.region || ' IncludeGlobalResourceTypes enabled,' + WHEN recording_group -> 'IncludeGlobalResourceTypes' = 'true' + THEN a.region || ' IncludeGlobalResourceTypes enabled,' ELSE a.region || ' IncludeGlobalResourceTypes disabled,' END || CASE - WHEN recording_group -> 'AllSupported' = 'true' THEN ' AllSupported enabled,' + WHEN recording_group -> 'AllSupported' = 'true' + THEN ' AllSupported enabled,' ELSE ' AllSupported disabled,' - END || + END || CASE - WHEN status ->> 'Recording' = 'true' THEN ' Recording enabled' + WHEN status ->> 'Recording' = 'true' + THEN ' Recording enabled' ELSE ' Recording disabled' - END || + END || CASE - WHEN status ->> 'LastStatus' = 'SUCCESS' THEN ' and LastStatus is SUCCESS.' + WHEN status ->> 'LastStatus' = 'SUCCESS' + THEN ' and LastStatus is SUCCESS.' ELSE ' and LastStatus is not SUCCESS.' END END AS reason FROM global_recorders AS g, aws_region AS a - LEFT JOIN aws_config_configuration_recorder AS r ON r.account_id = a.account_id AND r.region = a.name; - PrimaryTable: aws_config_configuration_recorder - ListOfTables: - - aws_config_configuration_recorder - - aws_region - Parameters: [] -Tags: {} + LEFT JOIN + aws_config_configuration_recorder AS r + ON + r.account_id = a.account_id + AND r.region = a.name; Severity: low +Tags: {} +Title: 3.3 Ensure AWS Config is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_3_4.yaml b/compliance/controls/aws/aws_cis_v300_3_4.yaml old mode 100755 new mode 100644 index 0564a5039..ad8eb63a1 --- a/compliance/controls/aws/aws_cis_v300_3_4.yaml +++ b/compliance/controls/aws/aws_cis_v300_3_4.yaml @@ -1,32 +1,33 @@ +Description: S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket. ID: aws_cis_v300_3_4 -Title: "3.4 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket" -Description: "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - t.arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when b.logging is not null then 'ok' - else 'alarm' - end as status, - case - when b.logging is not null then t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' - else t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' - end as reason - from - aws_cloudtrail_trail t - inner join aws_s3_bucket b on t.s3_bucket_name = b.name - where - t.region = t.home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN b.logging IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.logging IS NOT NULL THEN t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' + ELSE t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' + END AS reason + FROM + aws_cloudtrail_trail t + INNER JOIN + aws_s3_bucket b ON t.s3_bucket_name = b.name + WHERE + t.region = t.home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.4 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_3_5.yaml b/compliance/controls/aws/aws_cis_v300_3_5.yaml old mode 100755 new mode 100644 index 0993767dc..1a485f9db --- a/compliance/controls/aws/aws_cis_v300_3_5.yaml +++ b/compliance/controls/aws/aws_cis_v300_3_5.yaml @@ -1,14 +1,30 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS. ID: aws_cis_v300_3_5 -Title: "3.5 Ensure CloudTrail logs are encrypted at rest using KMS CMKs" -Description: "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kms_key_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_key_id is null then title || ' logs are not encrypted at rest.'\n else title || ' logs are encrypted at rest.'\n end as reason\n \n \nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' logs are not encrypted at rest.' + ELSE title || ' logs are encrypted at rest.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.5 Ensure CloudTrail logs are encrypted at rest using KMS CMKs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_3_6.yaml b/compliance/controls/aws/aws_cis_v300_3_6.yaml old mode 100755 new mode 100644 index e9eef1d20..ac7b170cc --- a/compliance/controls/aws/aws_cis_v300_3_6.yaml +++ b/compliance/controls/aws/aws_cis_v300_3_6.yaml @@ -1,36 +1,36 @@ +Description: AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the customer-created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK ID: aws_cis_v300_3_6 -Title: "3.6 Ensure rotation for customer-created symmetric CMKs is enabled" -Description: "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the customercreated customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when origin = 'EXTERNAL' then 'skip' - when key_state = 'PendingDeletion' then 'skip' - when key_state = 'Disabled' then 'skip' - when not key_rotation_enabled then 'alarm' - else 'ok' - end as status, - case - when origin = 'EXTERNAL' then title || ' has imported key material.' - when key_state = 'PendingDeletion' then title || ' is pending deletion.' - when key_state = 'Disabled' then title || ' is disabled.' - when not key_rotation_enabled then title || ' key rotation disabled.' - else title || ' key rotation enabled.' - end as reason - from - aws_kms_key - where - key_manager = 'CUSTOMER'; - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN origin = 'EXTERNAL' THEN 'skip' + WHEN key_state = 'PendingDeletion' THEN 'skip' + WHEN key_state = 'Disabled' THEN 'skip' + WHEN NOT key_rotation_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN origin = 'EXTERNAL' THEN title || ' has imported key material.' + WHEN key_state = 'PendingDeletion' THEN title || ' is pending deletion.' + WHEN key_state = 'Disabled' THEN title || ' is disabled.' + WHEN NOT key_rotation_enabled THEN title || ' key rotation disabled.' + ELSE title || ' key rotation enabled.' + END AS reason + FROM + aws_kms_key + WHERE + key_manager = 'CUSTOMER'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.6 Ensure rotation for customer-created symmetric CMKs is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_3_8.yaml b/compliance/controls/aws/aws_cis_v300_3_8.yaml old mode 100755 new mode 100644 index 87559c0da..e153406af --- a/compliance/controls/aws/aws_cis_v300_3_8.yaml +++ b/compliance/controls/aws/aws_cis_v300_3_8.yaml @@ -1,15 +1,60 @@ +Description: S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets. ID: aws_cis_v300_3_8 -Title: "3.8 Ensure that Object-level logging for write events is enabled for S3 bucket" -Description: "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with s3_selectors as\n(\n select\n name as trail_name,\n is_multi_region_trail,\n bucket_selector,\n og_account_id,\n og_resource_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as event_selector,\n jsonb_array_elements(event_selector -> 'DataResources') as data_resource,\n jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector\n where\n is_multi_region_trail\n and data_resource ->> 'Type' = 'AWS::S3::Object'\n and event_selector ->> 'ReadWriteType' in\n (\n 'WriteOnly',\n 'All'\n )\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when count(bucket_selector) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(bucket_selector) > 0 then b.name || ' object-level write events logging enabled.'\n else b.name || ' object-level write events logging disabled.'\n end as reason\n \n \nfrom\n aws_s3_bucket as b\n left join\n s3_selectors\n on bucket_selector like (b.arn || '%')\n or bucket_selector = 'arn:aws:s3'\ngroup by\n b.account_id, b.og_account_id, b.og_resource_id, b.region, b.arn, b.name, b.tags, b._ctx;" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( + SELECT + name AS trail_name, + is_multi_region_trail, + bucket_selector, + og_account_id, + og_resource_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE + is_multi_region_trail + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ('WriteOnly', 'All') + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level write events logging enabled.' + ELSE b.name || ' object-level write events logging disabled.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN + s3_selectors + ON + bucket_selector LIKE (b.arn || '%') + OR bucket_selector = 'arn:aws:s3' + GROUP BY + b.account_id, + b.og_account_id, + b.og_resource_id, + b.region, + b.arn, + b.name, + b.tags, + b._ctx; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.8 Ensure that Object-level logging for write events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_3_9.yaml b/compliance/controls/aws/aws_cis_v300_3_9.yaml old mode 100755 new mode 100644 index 2160829c4..98763d9be --- a/compliance/controls/aws/aws_cis_v300_3_9.yaml +++ b/compliance/controls/aws/aws_cis_v300_3_9.yaml @@ -1,57 +1,57 @@ +Description: S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets. ID: aws_cis_v300_3_9 -Title: "3.9 Ensure that Object-level logging for read events is enabled for S3 bucket" -Description: "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with s3_selectors as + ListOfTables: + - aws_cloudtrail_trail + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( - select - name as trail_name, + SELECT + name AS trail_name, is_multi_region_trail, bucket_selector, og_account_id, og_resource_id - from + FROM aws_cloudtrail_trail, - jsonb_array_elements(event_selectors) as event_selector, - jsonb_array_elements(event_selector -> 'DataResources') as data_resource, - jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector - where + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE is_multi_region_trail - and data_resource ->> 'Type' = 'AWS::S3::Object' - and event_selector ->> 'ReadWriteType' in + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ( 'ReadOnly', 'All' ) ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when count(bucket_selector) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(bucket_selector) > 0 then b.name || ' object-level read events logging enabled.' - else b.name || ' object-level read events logging disabled.' - end as reason - from - aws_s3_bucket as b - left join + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level read events logging enabled.' + ELSE b.name || ' object-level read events logging disabled.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN s3_selectors - on bucket_selector like (b.arn || '%') - or bucket_selector = 'arn:aws:s3' - group by + ON bucket_selector LIKE (b.arn || '%') + OR bucket_selector = 'arn:aws:s3' + GROUP BY b.account_id, b.og_account_id, b.og_resource_id, b.region, b.arn, b.name, b.tags, b._ctx; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_cloudtrail_trail - - aws_s3_bucket - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.9 Ensure that Object-level logging for read events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_4_11.yaml b/compliance/controls/aws/aws_cis_v300_4_11.yaml old mode 100755 new mode 100644 index 4bdaf7255..a83d2d688 --- a/compliance/controls/aws/aws_cis_v300_4_11.yaml +++ b/compliance/controls/aws/aws_cis_v300_4_11.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs. ID: aws_cis_v300_4_11 -Title: "4.11 Ensure Network Access Control Lists (NACL) changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateNetworkAcl.+\$\.eventName\s*=\s*CreateNetworkAclEntry.+\$\.eventName\s*=\s*DeleteNetworkAcl.+\$\.eventName\s*=\s*DeleteNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclAssociation' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for changes to NACLs.' - else filter_name || ' forwards events for changes to NACLs.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to NACLs.' + ELSE filter_name || ' forwards events for changes to NACLs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.11 Ensure Network Access Control Lists (NACL) changes are monitored \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_4_12.yaml b/compliance/controls/aws/aws_cis_v300_4_12.yaml old mode 100755 new mode 100644 index 53b230144..b06b5bc6f --- a/compliance/controls/aws/aws_cis_v300_4_12.yaml +++ b/compliance/controls/aws/aws_cis_v300_4_12.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways. ID: aws_cis_v300_4_12 -Title: "4.12 Ensure changes to network gateways are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateCustomerGateway.+\$\.eventName\s*=\s*DeleteCustomerGateway.+\$\.eventName\s*=\s*AttachInternetGateway.+\$\.eventName\s*=\s*CreateInternetGateway.+\$\.eventName\s*=\s*DeleteInternetGateway.+\$\.eventName\s*=\s*DetachInternetGateway' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for changes to network gateways.' - else filter_name || ' forwards events for changes to network gateways.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to network gateways.' + ELSE filter_name || ' forwards events for changes to network gateways.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.12 Ensure changes to network gateways are monitored \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_4_14.yaml b/compliance/controls/aws/aws_cis_v300_4_14.yaml old mode 100755 new mode 100644 index 6ff37b8fb..bd07ad1c5 --- a/compliance/controls/aws/aws_cis_v300_4_14.yaml +++ b/compliance/controls/aws/aws_cis_v300_4_14.yaml @@ -1,96 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs. ID: aws_cis_v300_4_14 -Title: "4.14 Ensure VPC changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_cloudwatch_alarm + - aws_sns_topic_subscription + - aws_cloudwatch_log_metric_filter + - aws_account + Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails AS ( + SELECT trail.account_id, - trail.name as trail_name, + trail.name AS trail_name, trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - order by + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY trail_name ), - alarms as ( - select + alarms AS ( + SELECT metric_name, - action_arn as topic_arn - from + action_arn AS topic_arn + FROM aws_cloudwatch_alarm, - jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn - order by + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY metric_name ), - topic_subscriptions as ( - select + topic_subscriptions AS ( + SELECT subscription_arn, topic_arn - from + FROM aws_sns_topic_subscription - order by + ORDER BY subscription_arn ), - metric_filters as ( - select - filter.name as filter_name, + metric_filters AS ( + SELECT + filter.name AS filter_name, filter_pattern, log_group_name, metric_transformation_name - from - aws_cloudwatch_log_metric_filter as filter - where + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateVpc.+\$\.eventName\s*=\s*DeleteVpc.+\$\.eventName\s*=\s*ModifyVpcAttribute.+\$\.eventName\s*=\s*AcceptVpcPeeringConnection.+\$\.eventName\s*=\s*CreateVpcPeeringConnection.+\$\.eventName\s*=\s*DeleteVpcPeeringConnection.+\$\.eventName\s*=\s*RejectVpcPeeringConnection.+\$\.eventName\s*=\s*AttachClassicLinkVpc.+\$\.eventName\s*=\s*DetachClassicLinkVpc.+\$\.eventName\s*=\s*DisableVpcClassicLink.+\$\.eventName\s*=\s*EnableVpcClassicLink' - order by + ORDER BY filter_name ), - filter_data as ( - select + filter_data AS ( + SELECT t.account_id, t.trail_name, f.filter_name - from - trails as t - join - metric_filters as f on f.log_group_name = t.log_group_name - join - alarms as alarm on alarm.metric_name = f.metric_transformation_name - join - topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - f.account_id as og_account_id, - f.trail_name as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for VPC changes.' - else filter_name || ' forwards events for VPC changes.' - end as reason - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_cloudtrail_trail - ListOfTables: - - aws_cloudtrail_trail - - aws_cloudwatch_alarm - - aws_sns_topic_subscription - - aws_cloudwatch_log_metric_filter - - aws_account - Parameters: [] + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + f.account_id AS og_account_id, + f.trail_name AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for VPC changes.' + ELSE filter_name || ' forwards events for VPC changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.14 Ensure VPC changes are monitored \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_5_2.yaml b/compliance/controls/aws/aws_cis_v300_5_2.yaml old mode 100755 new mode 100644 index 76c5e2c46..79c69b437 --- a/compliance/controls/aws/aws_cis_v300_5_2.yaml +++ b/compliance/controls/aws/aws_cis_v300_5_2.yaml @@ -1,73 +1,72 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389, using either the TCP (6), UDP (17) or ALL (-1) protocols. ID: aws_cis_v300_5_2 -Title: "5.2 Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389, using either the TCP (6), UDP (17) or ALL (-1) protocols." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT group_id, - count(*) as num_bad_rules - from + COUNT(*) AS num_bad_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and ( + AND ( cidr_ipv4 = '0.0.0.0/0' - or cidr_ipv6 = '::/0' + OR cidr_ipv6 = '::/0' ) - and ( - ( ip_protocol = '-1' -- all traffic - and from_port is null - ) - or ( - from_port >= 22 - and to_port <= 22 + AND ( + ( ip_protocol = '-1' + AND from_port IS NULL) + OR ( + from_port >= 22 + AND to_port <= 22 ) - or ( - from_port >= 3389 - and to_port <= 3389 + OR ( + from_port >= 3389 + AND to_port <= 3389 ) ) - group by + GROUP BY group_id ), - security_groups as ( - select + security_groups AS ( + SELECT arn, tags, region, account_id, group_id, - og_account_id as og_account_id, - og_resource_id as og_resource_id, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, _ctx - from + FROM aws_vpc_security_group - order by + ORDER BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when bad_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - end as reason - from - security_groups as sg - left join bad_rules on bad_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + security_groups AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.2 Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_5_3.yaml b/compliance/controls/aws/aws_cis_v300_5_3.yaml old mode 100755 new mode 100644 index 68cf4a30d..f29ef43db --- a/compliance/controls/aws/aws_cis_v300_5_3.yaml +++ b/compliance/controls/aws/aws_cis_v300_5_3.yaml @@ -1,57 +1,57 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_cis_v300_5_3 -Title: "5.3 Ensure no security groups allow ingress from ::/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT group_id, - count(*) as num_bad_rules - from + COUNT(*) AS num_bad_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and ( + AND ( cidr_ipv6 = '::/0' ) - and ( - ( ip_protocol = '-1' -- all traffic - and from_port is null + AND ( + ( ip_protocol = '-1' -- all traffic + AND from_port IS NULL ) - or ( + OR ( from_port >= 22 - and to_port <= 22 + AND to_port <= 22 ) - or ( + OR ( from_port >= 3389 - and to_port <= 3389 + AND to_port <= 3389 ) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when bad_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from ::/0.' - else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from ::/0.' - end as reason - from - aws_vpc_security_group as sg - left join bad_rules on bad_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from ::/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from ::/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.3 Ensure no security groups allow ingress from ::/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_5_5.yaml b/compliance/controls/aws/aws_cis_v300_5_5.yaml old mode 100755 new mode 100644 index 4f49458a6..e09e79388 --- a/compliance/controls/aws/aws_cis_v300_5_5.yaml +++ b/compliance/controls/aws/aws_cis_v300_5_5.yaml @@ -1,14 +1,22 @@ +Description: Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection. ID: aws_cis_v300_5_5 -Title: "5.5 Ensure routing tables for VPC peering are \\\"least access\\\"" -Description: "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'info' as status,\n 'Manual verification required.' as reason\n \nfrom\n aws_account;" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason + FROM + aws_account; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.5 Ensure routing tables for VPC peering are "least access" \ No newline at end of file diff --git a/compliance/controls/aws/aws_cis_v300_5_6.yaml b/compliance/controls/aws/aws_cis_v300_5_6.yaml old mode 100755 new mode 100644 index 18662a87b..72842b48d --- a/compliance/controls/aws/aws_cis_v300_5_6.yaml +++ b/compliance/controls/aws/aws_cis_v300_5_6.yaml @@ -1,28 +1,28 @@ +Description: When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method). ID: aws_cis_v300_5_6 -Title: "5.6 Ensure that EC2 Metadata Service only allows IMDSv2" -Description: "When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when metadata_options ->> 'HttpTokens' = 'optional' then 'alarm' - else 'ok' - end as status, - case - when metadata_options ->> 'HttpTokens' = 'optional' then title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' - else title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' - end as reason - from - aws_ec2_instance; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' + ELSE title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' + END AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.6 Ensure that EC2 Metadata Service only allows IMDSv2 \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudformation_stack_drift_detection_check.yaml b/compliance/controls/aws/aws_cloudformation_stack_drift_detection_check.yaml old mode 100755 new mode 100644 index ba7cea8ee..14ffc2808 --- a/compliance/controls/aws/aws_cloudformation_stack_drift_detection_check.yaml +++ b/compliance/controls/aws/aws_cloudformation_stack_drift_detection_check.yaml @@ -1,13 +1,32 @@ +Description: Ensure that the actual configuration of a Cloud Formation stack differs, or has drifted, from the expected configuration, a stack is considered to have drifted if one or more of its resources differ from their expected configuration. ID: aws_cloudformation_stack_drift_detection_check -Title: "CloudFormation stacks differ from the expected configuration" -Description: "Ensure that the actual configuration of a Cloud Formation stack differs, or has drifted, from the expected configuration, a stack is considered to have drifted if one or more of its resources differ from their expected configuration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when stack_drift_status = 'IN_SYNC' then 'ok'\n when stack_drift_status = 'DRIFTED' then 'alarm'\n else 'skip'\n end as status,\n case\n when stack_drift_status = 'IN_SYNC' then title || ' drift status is ' || stack_drift_status || '.'\n when stack_drift_status = 'DRIFTED' then title || ' drift status is ' || stack_drift_status || '.'\n else title || ' drift status is ' || stack_drift_status || '.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudformation_stack;\n" - PrimaryTable: aws_cloudformation_stack ListOfTables: - aws_cloudformation_stack Parameters: [] + PrimaryTable: aws_cloudformation_stack + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN stack_drift_status = 'IN_SYNC' THEN 'ok' + WHEN stack_drift_status = 'DRIFTED' THEN 'alarm' + ELSE 'skip' + END AS status, + CASE + WHEN stack_drift_status = 'IN_SYNC' THEN title || ' drift status is ' || stack_drift_status || '.' + WHEN stack_drift_status = 'DRIFTED' THEN title || ' drift status is ' || stack_drift_status || '.' + ELSE title || ' drift status is ' || stack_drift_status || '.' + END AS reason, + region, + account_id + FROM + aws_cloudformation_stack; Severity: high Tags: category: @@ -20,5 +39,4 @@ Tags: - aws service: - AWS/CloudFormation -IntegrationType: - - aws_cloud_account +Title: CloudFormation stacks differ from the expected configuration \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudformation_stack_notifications_enabled.yaml b/compliance/controls/aws/aws_cloudformation_stack_notifications_enabled.yaml old mode 100755 new mode 100644 index 843f7e628..9b402d25e --- a/compliance/controls/aws/aws_cloudformation_stack_notifications_enabled.yaml +++ b/compliance/controls/aws/aws_cloudformation_stack_notifications_enabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure CloudFormation stacks are associated with an SNS topic to receive notifications when an event occurs. ID: aws_cloudformation_stack_notifications_enabled -Title: "CloudFormation stacks should have notifications enabled" -Description: "Ensure CloudFormation stacks are associated with an SNS topic to receive notifications when an event occurs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(notification_arns) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when jsonb_array_length(notification_arns) > 0 then title || ' notifications enabled.'\n else title || ' notifications disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudformation_stack;\n" - PrimaryTable: aws_cloudformation_stack ListOfTables: - aws_cloudformation_stack Parameters: [] + PrimaryTable: aws_cloudformation_stack + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(notification_arns) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(notification_arns) > 0 THEN title || ' notifications enabled.' + ELSE title || ' notifications disabled.' + END AS reason, + region, + account_id + FROM + aws_cloudformation_stack; Severity: low Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/CloudFormation -IntegrationType: - - aws_cloud_account +Title: CloudFormation stacks should have notifications enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudformation_stack_output_no_secrets.yaml b/compliance/controls/aws/aws_cloudformation_stack_output_no_secrets.yaml old mode 100755 new mode 100644 index ca0ae9ff9..3b16d324f --- a/compliance/controls/aws/aws_cloudformation_stack_output_no_secrets.yaml +++ b/compliance/controls/aws/aws_cloudformation_stack_output_no_secrets.yaml @@ -1,14 +1,19 @@ +Description: Ensure CloudFormation stacks outputs do not contain secrets like user names, passwords, and tokens. It is recommended to remove secrets since outputs cannot be encrypted resulting in any entity with basic read-metadata-only and access to CloudFormation outputs having access to these secrets. ID: aws_cloudformation_stack_output_no_secrets -Title: "CloudFormation stacks outputs should not have any secrets" -Description: "Ensure CloudFormation stacks outputs do not contain secrets like user names, passwords, and tokens. It is recommended to remove secrets since outputs cannot be encrypted resulting in any entity with basic read-metadata-only and access to CloudFormation outputs having access to these secrets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with stack_output as ( - select + ListOfTables: + - aws_cloudformation_stack + Parameters: [] + PrimaryTable: aws_cloudformation_stack + QueryToExecute: | + WITH stack_output AS ( + SELECT id, - jsonb_array_elements(outputs) -> 'OutputKey' as k, - jsonb_array_elements(outputs) -> 'OutputValue' as v, + jsonb_array_elements(outputs) -> 'OutputKey' AS k, + jsonb_array_elements(outputs) -> 'OutputValue' AS v, region, account_id, tags, @@ -17,40 +22,37 @@ Query: title, og_account_id, og_resource_id - from + FROM aws_cloudformation_stack ), - stack_with_secrets as ( - select - distinct id - from + stack_with_secrets AS ( + SELECT + DISTINCT id + FROM stack_output - where - lower(k::text) like any (array ['%pass%', '%secret%','%token%','%key%']) - or k::text ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' or lower(v::text) like any (array ['%pass%', '%secret%','%token%','%key%']) or v::text ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' + WHERE + LOWER(k::text) LIKE ANY (ARRAY ['%pass%', '%secret%', '%token%', '%key%']) + OR k::text ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' + OR LOWER(v::text) LIKE ANY (ARRAY ['%pass%', '%secret%', '%token%', '%key%']) + OR v::text ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' ) - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when c.outputs is null then 'ok' - when s.id is null then 'ok' - else 'alarm' - end as status, - case - when c.outputs is null then title || ' has no outputs.' - when s.id is null then title || ' no secrets found in outputs.' - else title || ' has secrets in outputs.' - end as reason - from - stack_output as c - left join stack_with_secrets as s on c.id = s.id - PrimaryTable: aws_cloudformation_stack - ListOfTables: - - aws_cloudformation_stack - Parameters: [] + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.outputs IS NULL THEN 'ok' + WHEN s.id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.outputs IS NULL THEN title || ' has no outputs.' + WHEN s.id IS NULL THEN title || ' no secrets found in outputs.' + ELSE title || ' has secrets in outputs.' + END AS reason + FROM + stack_output AS c + LEFT JOIN stack_with_secrets AS s ON c.id = s.id Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudFormation stacks outputs should not have any secrets \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudformation_stack_rollback_enabled.yaml b/compliance/controls/aws/aws_cloudformation_stack_rollback_enabled.yaml old mode 100755 new mode 100644 index 0bf94f1a6..56a18d0f2 --- a/compliance/controls/aws/aws_cloudformation_stack_rollback_enabled.yaml +++ b/compliance/controls/aws/aws_cloudformation_stack_rollback_enabled.yaml @@ -1,14 +1,28 @@ +Description: Ensure CloudFormation stacks have the rollback feature enabled. Rollback triggers enable you to have AWS CloudFormation monitor the state of your application during stack creation and updating, and to rollback that operation if the application breaches the threshold of any of the alarms you've specified. ID: aws_cloudformation_stack_rollback_enabled -Title: "CloudFormation stacks should have rollback enabled" -Description: "Ensure CloudFormation stacks have the rollback feature enabled. Rollback triggers enable you to have AWS CloudFormation monitor the state of your application during stack creation and updating, and to rollback that operation if the application breaches the threshold of any of the alarms you've specified." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when not disable_rollback then 'ok'\n else 'alarm'\n end as status,\n case\n when not disable_rollback then title || ' rollback enabled.'\n else title || ' rollback disabled.'\n end as reason\n \n \nfrom\n aws_cloudformation_stack;" - PrimaryTable: aws_cloudformation_stack ListOfTables: - aws_cloudformation_stack Parameters: [] + PrimaryTable: aws_cloudformation_stack + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT disable_rollback THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT disable_rollback THEN title || ' rollback enabled.' + ELSE title || ' rollback disabled.' + END AS reason + FROM + aws_cloudformation_stack; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudFormation stacks should have rollback enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudformation_stack_termination_protection_enabled.yaml b/compliance/controls/aws/aws_cloudformation_stack_termination_protection_enabled.yaml old mode 100755 new mode 100644 index c5d19cdee..8878aa521 --- a/compliance/controls/aws/aws_cloudformation_stack_termination_protection_enabled.yaml +++ b/compliance/controls/aws/aws_cloudformation_stack_termination_protection_enabled.yaml @@ -1,28 +1,28 @@ +Description: Ensure that AWS CloudFormation stacks have termination protection feature enabled in order to protect them from being accidentally deleted. The safety feature can be enabled when you create the CloudFormation stack or for existing stacks using the AWS API (UpdateTerminationProtection command). ID: aws_cloudformation_stack_termination_protection_enabled -Title: "Cloudformation stacks termination protection should be enabled" -Description: "Ensure that AWS CloudFormation stacks have termination protection feature enabled in order to protect them from being accidentally deleted. The safety feature can be enabled when you create the CloudFormation stack or for existing stacks using the AWS API (UpdateTerminationProtection command)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when enable_termination_protection then 'ok' - else 'alarm' - end as status, - case - when enable_termination_protection then title || ' termination protection enabled.' - else title || ' termination protection disabled.' - end as reason - from - aws_cloudformation_stack; - PrimaryTable: aws_cloudformation_stack ListOfTables: - aws_cloudformation_stack Parameters: [] + PrimaryTable: aws_cloudformation_stack + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enable_termination_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_termination_protection THEN title || ' termination protection enabled.' + ELSE title || ' termination protection disabled.' + END AS reason + FROM + aws_cloudformation_stack; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Cloudformation stacks termination protection should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_configured_with_origin_failover.yaml b/compliance/controls/aws/aws_cloudfront_distribution_configured_with_origin_failover.yaml old mode 100755 new mode 100644 index d1639e38f..09aba9b88 --- a/compliance/controls/aws/aws_cloudfront_distribution_configured_with_origin_failover.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_configured_with_origin_failover.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether an AWS CloudFront distribution is configured with an origin group that has two or more origins. CloudFront origin failover can increase availability. Origin failover automatically redirects traffic to a secondary origin if the primary origin is unavailable or if it returns specific HTTP response status codes. ID: aws_cloudfront_distribution_configured_with_origin_failover -Title: "CloudFront distributions should have origin failover configured" -Description: "This control checks whether an AWS CloudFront distribution is configured with an origin group that has two or more origins. CloudFront origin failover can increase availability. Origin failover automatically redirects traffic to a secondary origin if the primary origin is unavailable or if it returns specific HTTP response status codes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when origin_groups ->> 'Items' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when origin_groups ->> 'Items' is not null then title || ' origin group is configured.'\n else title || ' origin group not configured.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudfront_distribution;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN origin_groups ->> 'Items' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN origin_groups ->> 'Items' IS NOT NULL THEN title || ' origin group is configured.' + ELSE title || ' origin group not configured.' + END AS reason, + region, + account_id + FROM + aws_cloudfront_distribution; Severity: low Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should have origin failover configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_custom_origins_encryption_in_transit_enabled.yaml b/compliance/controls/aws/aws_cloudfront_distribution_custom_origins_encryption_in_transit_enabled.yaml old mode 100755 new mode 100644 index c5c05bc2f..88a81e647 --- a/compliance/controls/aws/aws_cloudfront_distribution_custom_origins_encryption_in_transit_enabled.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_custom_origins_encryption_in_transit_enabled.yaml @@ -1,13 +1,63 @@ +Description: This control checks if AWS CloudFront distributions are encrypting traffic to custom origins. This control fails for a CloudFront distribution whose origin protocol policy allows 'http-only'. This control also fails if the distribution's origin protocol policy is 'match-viewer' while the viewer protocol policy is 'allow-all'. ID: aws_cloudfront_distribution_custom_origins_encryption_in_transit_enabled -Title: "CloudFront distributions should encrypt traffic to custom origins" -Description: "This control checks if AWS CloudFront distributions are encrypting traffic to custom origins. This control fails for a CloudFront distribution whose origin protocol policy allows 'http-only'. This control also fails if the distribution's origin protocol policy is 'match-viewer' while the viewer protocol policy is 'allow-all'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with viewer_protocol_policy_value as (\n select\n distinct arn\n from\n aws_cloudfront_distribution,\n jsonb_array_elements(\n case jsonb_typeof(cache_behaviors -> 'Items')\n when 'array' then (cache_behaviors -> 'Items')\n else null end\n ) as cb\n where\n cb ->> 'ViewerProtocolPolicy' = 'allow-all'\n),\norigin_protocol_policy_value as (\n select\n distinct arn,\n o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' as origin_protocol_policy\n from\n aws_cloudfront_distribution,\n jsonb_array_elements(origins) as o\n where\n o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'http-only'\n or o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'match-viewer'\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when o.arn is not null and o.origin_protocol_policy = 'http-only' then 'alarm'\n when o.arn is not null and o.origin_protocol_policy = 'match-viewer' and ( v.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') ) then 'alarm'\n else 'ok'\n end as status,\n case\n when o.arn is not null and o.origin_protocol_policy = 'http-only' then title || ' custom origins traffic not encrypted in transit.'\n when o.arn is not null and o.origin_protocol_policy = 'match-viewer' and ( v.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') ) then title || ' custom origins traffic not encrypted in transit.'\n else title || ' custom origins traffic encrypted in transit.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudfront_distribution as b\n left join origin_protocol_policy_value as o on b.arn = o.arn\n left join viewer_protocol_policy_value as v on b.arn = v.arn;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + WITH viewer_protocol_policy_value AS ( + SELECT + DISTINCT arn + FROM + aws_cloudfront_distribution, + JSONB_ARRAY_ELEMENTS( + CASE JSONB_TYPEOF(cache_behaviors -> 'Items') + WHEN 'array' THEN (cache_behaviors -> 'Items') + ELSE NULL END + ) AS cb + WHERE + cb ->> 'ViewerProtocolPolicy' = 'allow-all' + ), + origin_protocol_policy_value AS ( + SELECT + DISTINCT arn, + o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' AS origin_protocol_policy + FROM + aws_cloudfront_distribution, + JSONB_ARRAY_ELEMENTS(origins) AS o + WHERE + o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'http-only' + OR o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'match-viewer' + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'http-only' THEN 'alarm' + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'match-viewer' AND + ( v.arn IS NOT NULL OR (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'http-only' + THEN title || ' custom origins traffic not encrypted in transit.' + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'match-viewer' AND + (v.arn IS NOT NULL OR (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all')) + THEN title || ' custom origins traffic not encrypted in transit.' + ELSE title || ' custom origins traffic encrypted in transit.' + END AS reason, + region, + account_id + FROM + aws_cloudfront_distribution AS b + LEFT JOIN origin_protocol_policy_value AS o ON b.arn = o.arn + LEFT JOIN viewer_protocol_policy_value AS v ON b.arn = v.arn Severity: medium Tags: aws_foundational_security: @@ -22,5 +72,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should encrypt traffic to custom origins \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_default_root_object_configured.yaml b/compliance/controls/aws/aws_cloudfront_distribution_default_root_object_configured.yaml old mode 100755 new mode 100644 index 3c00f5b4d..4898c36c7 --- a/compliance/controls/aws/aws_cloudfront_distribution_default_root_object_configured.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_default_root_object_configured.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether an AWS CloudFront distribution is configured to return a specific object that is the default root object. The control fails if the CloudFront distribution does not have a default root object configured. ID: aws_cloudfront_distribution_default_root_object_configured -Title: "CloudFront distributions should have a default root object configured" -Description: "This control checks whether an AWS CloudFront distribution is configured to return a specific object that is the default root object. The control fails if the CloudFront distribution does not have a default root object configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when default_root_object = '' then 'alarm'\n else 'ok'\n end as status,\n case\n when default_root_object = '' then title || ' default root object not configured.'\n else title || ' default root object configured.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudfront_distribution;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN default_root_object = '' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN default_root_object = '' THEN title || ' default root object not configured.' + ELSE title || ' default root object configured.' + END AS reason, + region, + account_id + FROM + aws_cloudfront_distribution; Severity: critical Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should have a default root object configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_encryption_in_transit_enabled.yaml b/compliance/controls/aws/aws_cloudfront_distribution_encryption_in_transit_enabled.yaml old mode 100755 new mode 100644 index c13aa28c6..5c606d54f --- a/compliance/controls/aws/aws_cloudfront_distribution_encryption_in_transit_enabled.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_encryption_in_transit_enabled.yaml @@ -1,13 +1,49 @@ +Description: This control checks whether an AWS CloudFront distribution requires viewers to use HTTPS directly or whether it uses redirection. The control fails if ViewerProtocolPolicy is set to allow-all for defaultCacheBehavior or for cacheBehaviors. ID: aws_cloudfront_distribution_encryption_in_transit_enabled -Title: "CloudFront distributions should require encryption in transit" -Description: "This control checks whether an AWS CloudFront distribution requires viewers to use HTTPS directly or whether it uses redirection. The control fails if ViewerProtocolPolicy is set to allow-all for defaultCacheBehavior or for cacheBehaviors." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with data as (\n select\n distinct arn\n from\n aws_cloudfront_distribution,\n jsonb_array_elements(\n case jsonb_typeof(cache_behaviors -> 'Items')\n when 'array' then (cache_behaviors -> 'Items')\n else null end\n ) as cb\n where\n cb ->> 'ViewerProtocolPolicy' = 'allow-all'\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when d.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') then 'alarm'\n else 'ok'\n end as status,\n case\n when d.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') then title || ' data not encrypted in transit.'\n else title || ' data encrypted in transit.'\n end as reason\n \n , b.region, b.account_id\nfrom\n aws_cloudfront_distribution as b\n left join data as d on b.arn = d.arn;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + WITH data AS ( + SELECT + DISTINCT arn + FROM + aws_cloudfront_distribution, + jsonb_array_elements( + CASE jsonb_typeof(cache_behaviors -> 'Items') + WHEN 'array' THEN (cache_behaviors -> 'Items') + ELSE NULL + END + ) AS cb + WHERE + cb ->> 'ViewerProtocolPolicy' = 'allow-all' + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN d.arn IS NOT NULL + OR (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.arn IS NOT NULL + OR (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') + THEN title || ' data not encrypted in transit.' + ELSE title || ' data encrypted in transit.' + END AS reason, + b.region, + b.account_id + FROM + aws_cloudfront_distribution AS b + LEFT JOIN data AS d ON b.arn = d.arn; Severity: medium Tags: aws_foundational_security: @@ -22,5 +58,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should require encryption in transit \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_field_level_encryption_enabled.yaml b/compliance/controls/aws/aws_cloudfront_distribution_field_level_encryption_enabled.yaml old mode 100755 new mode 100644 index 785567c4e..95adaaee2 --- a/compliance/controls/aws/aws_cloudfront_distribution_field_level_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_field_level_encryption_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an AWS CloudFront distribution has field-level encryption enabled. The control fails if CloudFront distribution field-level encryption is not enabled. ID: aws_cloudfront_distribution_field_level_encryption_enabled -Title: "CloudFront distributions should have field level encryption enabled" -Description: "This control checks whether an AWS CloudFront distribution has field-level encryption enabled. The control fails if CloudFront distribution field-level encryption is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when default_cache_behavior ->> 'FieldLevelEncryptionId' = '' then 'alarm' - else 'ok' - end as status, - case - when default_cache_behavior ->> 'FieldLevelEncryptionId' = '' then title || ' field level encryption disabled.' - else title || ' field level encryption enabled.' - end as reason - from - aws_cloudfront_distribution; - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN default_cache_behavior ->> 'FieldLevelEncryptionId' = '' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN default_cache_behavior ->> 'FieldLevelEncryptionId' = '' THEN title || ' field level encryption disabled.' + ELSE title || ' field level encryption enabled.' + END AS reason + FROM + aws_cloudfront_distribution; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should have field level encryption enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_geo_restrictions_enabled.yaml b/compliance/controls/aws/aws_cloudfront_distribution_geo_restrictions_enabled.yaml old mode 100755 new mode 100644 index 614bb6930..8b291258a --- a/compliance/controls/aws/aws_cloudfront_distribution_geo_restrictions_enabled.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_geo_restrictions_enabled.yaml @@ -1,14 +1,28 @@ +Description: Geographic restriction is used to restrict access to all of the files that are associated with a distribution at the country level. ID: aws_cloudfront_distribution_geo_restrictions_enabled -Title: "CloudFront distributions should have geo restriction enabled" -Description: "Geographic restriction is used to restrict access to all of the files that are associated with a distribution at the country level." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when restrictions -> 'GeoRestriction' ->> 'RestrictionType' = 'none' then 'alarm'\n else 'ok'\n end as status,\n case\n when restrictions -> 'GeoRestriction' ->> 'RestrictionType' = 'none' then title || ' Geo Restriction disabled.'\n else title || ' Geo Restriction enabled.'\n end as reason\n \n \nfrom\n aws_cloudfront_distribution;" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN restrictions -> 'GeoRestriction' ->> 'RestrictionType' = 'none' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN restrictions -> 'GeoRestriction' ->> 'RestrictionType' = 'none' THEN title || ' Geo Restriction disabled.' + ELSE title || ' Geo Restriction enabled.' + END AS reason + FROM + aws_cloudfront_distribution; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should have geo restriction enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_latest_tls_version.yaml b/compliance/controls/aws/aws_cloudfront_distribution_latest_tls_version.yaml old mode 100755 new mode 100644 index 942422c84..bfb4cb9d5 --- a/compliance/controls/aws/aws_cloudfront_distribution_latest_tls_version.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_latest_tls_version.yaml @@ -1,30 +1,30 @@ +Description: This control checks whether CloudFront distribution uses latest TLS version. ID: aws_cloudfront_distribution_latest_tls_version -Title: "CloudFront distributions should have latest TLS version" -Description: "This control checks whether CloudFront distribution uses latest TLS version." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when viewer_certificate ->> 'CertificateSource' = 'cloudfront' - and viewer_certificate ->> 'MinimumProtocolVersion' = 'TLSv1.2_2021' then 'ok' - else 'alarm' - end as status, - case - when viewer_certificate ->> 'CertificateSource' = 'cloudfront' - and viewer_certificate ->> 'MinimumProtocolVersion' = 'TLSv1.2_2021' then title || ' uses latest TLS version.' - else title || ' not uses latest TLS version.' - end as reason - from - aws_cloudfront_distribution; - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN viewer_certificate ->> 'CertificateSource' = 'cloudfront' + AND viewer_certificate ->> 'MinimumProtocolVersion' = 'TLSv1.2_2021' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN viewer_certificate ->> 'CertificateSource' = 'cloudfront' + AND viewer_certificate ->> 'MinimumProtocolVersion' = 'TLSv1.2_2021' THEN title || ' uses latest TLS version.' + ELSE title || ' does not use latest TLS version.' + END AS reason + FROM + aws_cloudfront_distribution; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should have latest TLS version \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_logging_enabled.yaml b/compliance/controls/aws/aws_cloudfront_distribution_logging_enabled.yaml old mode 100755 new mode 100644 index ed8bc11ca..1915b588d --- a/compliance/controls/aws/aws_cloudfront_distribution_logging_enabled.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_logging_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks if AWS CloudFront distributions are configured to capture information from AWS Simple Storage Service (AWS S3) server access logs. This rule is non-compliant if a CloudFront distribution does not have logging configured. ID: aws_cloudfront_distribution_logging_enabled -Title: "CloudFront distributions access logs should be enabled" -Description: "This control checks if AWS CloudFront distributions are configured to capture information from AWS Simple Storage Service (AWS S3) server access logs. This rule is non-compliant if a CloudFront distribution does not have logging configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when logging ->> 'Enabled' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when logging ->> 'Enabled' = 'true' then title || ' logging enabled.'\n else title || ' logging disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudfront_distribution;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logging ->> 'Enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN logging ->> 'Enabled' = 'true' THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason, + region, + account_id + FROM + aws_cloudfront_distribution; Severity: medium Tags: category: @@ -24,5 +41,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions access logs should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_no_deprecated_ssl_protocol.yaml b/compliance/controls/aws/aws_cloudfront_distribution_no_deprecated_ssl_protocol.yaml old mode 100755 new mode 100644 index 91b0a3681..89237b757 --- a/compliance/controls/aws/aws_cloudfront_distribution_no_deprecated_ssl_protocol.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_no_deprecated_ssl_protocol.yaml @@ -1,13 +1,41 @@ +Description: This control checks if AWS CloudFront distributions are using deprecated SSL protocols for HTTPS communication between CloudFront edge locations and your custom origins. This control fails if a CloudFront distribution has a CustomOriginConfig where OriginSslProtocols includes SSLv3. ID: aws_cloudfront_distribution_no_deprecated_ssl_protocol -Title: "CloudFront distributions should not use deprecated SSL protocols between edge locations and custom origins" -Description: "This control checks if AWS CloudFront distributions are using deprecated SSL protocols for HTTPS communication between CloudFront edge locations and your custom origins. This control fails if a CloudFront distribution has a CustomOriginConfig where OriginSslProtocols includes SSLv3." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with origin_ssl_protocols as (\n select\n distinct arn,\n o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' as origin_protocol_policy\n from\n aws_cloudfront_distribution,\n jsonb_array_elements(origins) as o\n where\n o -> 'CustomOriginConfig' -> 'OriginSslProtocols' -> 'Items' @> '[\"SSLv3\"]'\n)\nselect\n b.arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when o.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when o.arn is null then title || ' does not have deprecated SSL protocols.'\n else title || ' has deprecated SSL protocols.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudfront_distribution as b\n left join origin_ssl_protocols as o on b.arn = o.arn;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + WITH origin_ssl_protocols AS ( + SELECT + DISTINCT arn, + o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' AS origin_protocol_policy + FROM + aws_cloudfront_distribution, + jsonb_array_elements(origins) AS o + WHERE + o -> 'CustomOriginConfig' -> 'OriginSslProtocols' -> 'Items' @> '["SSLv3"]' + ) + SELECT + b.arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN o.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN o.arn IS NULL THEN title || ' does not have deprecated SSL protocols.' + ELSE title || ' has deprecated SSL protocols.' + END AS reason, + region, + account_id + FROM + aws_cloudfront_distribution AS b + LEFT JOIN origin_ssl_protocols AS o ON b.arn = o.arn; Severity: medium Tags: aws_foundational_security: @@ -22,5 +50,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should not use deprecated SSL protocols between edge locations and custom origins \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_no_non_existent_s3_origin.yaml b/compliance/controls/aws/aws_cloudfront_distribution_no_non_existent_s3_origin.yaml old mode 100755 new mode 100644 index d4fdfc4ce..d01eec497 --- a/compliance/controls/aws/aws_cloudfront_distribution_no_non_existent_s3_origin.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_no_non_existent_s3_origin.yaml @@ -1,53 +1,53 @@ +Description: This control checks whether AWS CloudFront distributions are pointing to non-existent AWS S3 origins. The control fails for a CloudFront distribution if the origin is configured to point to a non-existent bucket. This control only applies to CloudFront distributions where an S3 bucket without static website hosting is the S3 origin. ID: aws_cloudfront_distribution_no_non_existent_s3_origin -Title: "CloudFront distributions should not point to non-existent S3 origins" -Description: "This control checks whether AWS CloudFront distributions are pointing to non-existent AWS S3 origins. The control fails for a CloudFront distribution if the origin is configured to point to a non-existent bucket. This control only applies to CloudFront distributions where an S3 bucket without static website hosting is the S3 origin." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with distribution_with_non_existent_bucket as ( - select - distinct d.arn as arn, - to_jsonb(string_to_array((string_agg(split_part(o ->> 'Id', '.s3', 1), ',')),',')) as bucket_name_list - from - aws_cloudfront_distribution as d, - jsonb_array_elements(d.origins) as o - left join aws_s3_bucket as b on b.name = split_part(o ->> 'Id', '.s3', 1) - where - b.name is null - and o ->> 'DomainName' like '%.s3.%' - group by - d.arn - ) - select - distinct b.arn as resource, - d.og_account_id as og_account_id, - d.og_resource_id as og_resource_id, - case - when b.arn is null then 'ok' - else 'alarm' - end as status, - case - when b.arn is null then title || ' does not point to any non-existent S3 origins.' - when jsonb_array_length(b.bucket_name_list) > 0 - then title || - case - when jsonb_array_length(b.bucket_name_list) > 2 - then concat(' point to non-existent S3 origins ', b.bucket_name_list #>> '{0}', ', ', b.bucket_name_list #>> '{1}', ' and ' || (jsonb_array_length(b.bucket_name_list) - 2)::text || ' more.' ) - when jsonb_array_length(b.bucket_name_list) = 2 - then concat(' point to non-existent S3 origins ', b.bucket_name_list #>> '{0}', ' and ', b.bucket_name_list #>> '{1}', '.') - else concat(' point to non-existent S3 origin ', b.bucket_name_list #>> '{0}', '.') - end - end as reason - - , region, account_id - from - aws_cloudfront_distribution as d - left join distribution_with_non_existent_bucket as b on b.arn = d.arn; - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + WITH distribution_with_non_existent_bucket AS ( + SELECT + DISTINCT d.arn AS arn, + TO_JSONB(STRING_TO_ARRAY((STRING_AGG(SPLIT_PART(o ->> 'Id', '.s3', 1), ',')), ',')) AS bucket_name_list + FROM + aws_cloudfront_distribution AS d, + JSONB_ARRAY_ELEMENTS(d.origins) AS o + LEFT JOIN aws_s3_bucket AS b ON b.name = SPLIT_PART(o ->> 'Id', '.s3', 1) + WHERE + b.name IS NULL + AND o ->> 'DomainName' LIKE '%.s3.%' + GROUP BY + d.arn + ) + SELECT + DISTINCT b.arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NULL THEN title || ' does not point to any non-existent S3 origins.' + WHEN JSONB_ARRAY_LENGTH(b.bucket_name_list) > 0 THEN title || + CASE + WHEN JSONB_ARRAY_LENGTH(b.bucket_name_list) > 2 + THEN CONCAT(' point to non-existent S3 origins ', b.bucket_name_list #>> '{0}', ', ', b.bucket_name_list #>> '{1}', ' and ' || (JSONB_ARRAY_LENGTH(b.bucket_name_list) - 2)::TEXT || ' more.' ) + WHEN JSONB_ARRAY_LENGTH(b.bucket_name_list) = 2 + THEN CONCAT(' point to non-existent S3 origins ', b.bucket_name_list #>> '{0}', ' and ', b.bucket_name_list #>> '{1}', '.') + ELSE CONCAT(' point to non-existent S3 origin ', b.bucket_name_list #>> '{0}', '.') + END + END AS reason, + region, + account_id + FROM + aws_cloudfront_distribution AS d + LEFT JOIN distribution_with_non_existent_bucket AS b ON b.arn = d.arn; Severity: high Tags: aws_foundational_security: @@ -62,5 +62,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should not point to non-existent S3 origins \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_origin_access_identity_enabled.yaml b/compliance/controls/aws/aws_cloudfront_distribution_origin_access_identity_enabled.yaml old mode 100755 new mode 100644 index c8d08d3eb..0cb455f96 --- a/compliance/controls/aws/aws_cloudfront_distribution_origin_access_identity_enabled.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_origin_access_identity_enabled.yaml @@ -1,13 +1,36 @@ +Description: This control checks whether an AWS CloudFront distribution with AWS S3 Origin type + has Origin Access Identity (OAI) configured. The control fails if OAI is not configured. ID: aws_cloudfront_distribution_origin_access_identity_enabled -Title: "CloudFront distributions should have origin access identity enabled" -Description: "This control checks whether an AWS CloudFront distribution with AWS S3 Origin type has Origin Access Identity (OAI) configured. The control fails if OAI is not configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when o ->> 'DomainName' not like '%s3.amazonaws.com' then 'skip'\n when o ->> 'DomainName' like '%s3.amazonaws.com'\n and o -> 'S3OriginConfig' ->> 'OriginAccessIdentity' = '' then 'alarm'\n else 'ok'\n end as status,\n case\n when o ->> 'DomainName' not like '%s3.amazonaws.com' then title || ' origin type is not s3.'\n when o ->> 'DomainName' like '%s3.amazonaws.com'\n and o -> 'S3OriginConfig' ->> 'OriginAccessIdentity' = '' then title || ' origin access identity not configured.'\n else title || ' origin access identity configured.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudfront_distribution,\n jsonb_array_elements(origins) as o;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN o ->> 'DomainName' NOT LIKE '%s3.amazonaws.com' THEN 'skip' + WHEN o ->> 'DomainName' LIKE '%s3.amazonaws.com' + AND o -> 'S3OriginConfig' ->> 'OriginAccessIdentity' = '' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN o ->> 'DomainName' NOT LIKE '%s3.amazonaws.com' THEN title || ' origin type is not s3.' + WHEN o ->> 'DomainName' LIKE '%s3.amazonaws.com' + AND o -> 'S3OriginConfig' ->> 'OriginAccessIdentity' = '' THEN title || ' origin access identity not configured.' + ELSE title || ' origin access identity configured.' + END AS reason, + region, + account_id + FROM + aws_cloudfront_distribution, + jsonb_array_elements(origins) AS o; Severity: medium Tags: aws_foundational_security: @@ -22,5 +45,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should have origin access identity enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_sni_enabled.yaml b/compliance/controls/aws/aws_cloudfront_distribution_sni_enabled.yaml old mode 100755 new mode 100644 index 003ec2d58..b4f9ebddf --- a/compliance/controls/aws/aws_cloudfront_distribution_sni_enabled.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_sni_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks if AWS CloudFront distributions are using a custom SSL/TLS certificate and are configured to use SNI to serve HTTPS requests. This control fails if a custom SSL/TLS certificate is associated but the SSL/TLS support method is a dedicated IP address. ID: aws_cloudfront_distribution_sni_enabled -Title: "CloudFront distributions should use SNI to serve HTTPS requests" -Description: "This control checks if AWS CloudFront distributions are using a custom SSL/TLS certificate and are configured to use SNI to serve HTTPS requests. This control fails if a custom SSL/TLS certificate is associated but the SSL/TLS support method is a dedicated IP address." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when viewer_certificate ->> 'SSLSupportMethod' = 'sni-only' then 'ok'\n else 'alarm'\n end as status,\n case\n when viewer_certificate ->> 'SSLSupportMethod' = 'sni-only' then title || ' SNI enabled.'\n else title || ' SNI disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudfront_distribution;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN viewer_certificate ->> 'SSLSupportMethod' = 'sni-only' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN viewer_certificate ->> 'SSLSupportMethod' = 'sni-only' THEN title || ' SNI enabled.' + ELSE title || ' SNI disabled.' + END AS reason, + region, + account_id + FROM + aws_cloudfront_distribution; Severity: low Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should use SNI to serve HTTPS requests \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_use_custom_ssl_certificate.yaml b/compliance/controls/aws/aws_cloudfront_distribution_use_custom_ssl_certificate.yaml old mode 100755 new mode 100644 index ef9a86170..ba3cc33dc --- a/compliance/controls/aws/aws_cloudfront_distribution_use_custom_ssl_certificate.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_use_custom_ssl_certificate.yaml @@ -1,13 +1,32 @@ +Description: This control checks whether CloudFront distributions are using the default SSL/TLS certificate CloudFront provides. This control passes if the CloudFront distribution uses a custom SSL/TLS certificate. This control fails if the CloudFront distribution uses the default SSL/TLS certificate. ID: aws_cloudfront_distribution_use_custom_ssl_certificate -Title: "CloudFront distributions should use custom SSL/TLS certificates" -Description: "This control checks whether CloudFront distributions are using the default SSL/TLS certificate CloudFront provides. This control passes if the CloudFront distribution uses a custom SSL/TLS certificate. This control fails if the CloudFront distribution uses the default SSL/TLS certificate." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when viewer_certificate ->> 'ACMCertificateArn' is not null and viewer_certificate ->> 'Certificate' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when viewer_certificate ->> 'ACMCertificateArn' is not null and viewer_certificate ->> 'Certificate' is not null then title || ' uses custom SSL certificate.'\n else title || ' does not use custom SSL certificate.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudfront_distribution;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN viewer_certificate ->> 'ACMCertificateArn' IS NOT NULL + AND viewer_certificate ->> 'Certificate' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN viewer_certificate ->> 'ACMCertificateArn' IS NOT NULL + AND viewer_certificate ->> 'Certificate' IS NOT NULL THEN title || ' uses custom SSL certificate.' + ELSE title || ' does not use custom SSL certificate.' + END AS reason, + region, + account_id + FROM + aws_cloudfront_distribution; Severity: medium Tags: aws_foundational_security: @@ -22,5 +41,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should use custom SSL/TLS certificates \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_use_secure_cipher.yaml b/compliance/controls/aws/aws_cloudfront_distribution_use_secure_cipher.yaml old mode 100755 new mode 100644 index ca1fc4fd5..e39a9575a --- a/compliance/controls/aws/aws_cloudfront_distribution_use_secure_cipher.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_use_secure_cipher.yaml @@ -1,39 +1,39 @@ +Description: Ensure that CloudFront distributions do not have any insecure SSL ciphers. Using insecure and deprecated ciphers could make the SSL connection between the CloudFront and the origins vulnerable to exploits. ID: aws_cloudfront_distribution_use_secure_cipher -Title: "CloudFront distributions should use secure SSL cipher" -Description: "Ensure that CloudFront distributions do not have any insecure SSL ciphers. Using insecure and deprecated ciphers could make the SSL connection between the CloudFront and the origins vulnerable to exploits." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with origin_protocols as ( - select - distinct arn, - o -> 'CustomOriginConfig' ->> 'OriginSslProtocols' as origin_ssl_policy - from - aws_cloudfront_distribution, - jsonb_array_elements(origins) as o - where - o -> 'CustomOriginConfig' -> 'OriginSslProtocols' -> 'Items' @> '["TLSv1.2%", "TLSv1.1%"]' - ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when o.arn is not null then 'ok' - else 'alarm' - end as status, - case - when o.arn is not null then title || ' use secure cipher.' - else title || ' does not use secure cipher.' - end as reason - from - aws_cloudfront_distribution as b - left join origin_protocols as o on b.arn = o.arn; - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + WITH origin_protocols AS ( + SELECT + DISTINCT arn, + o -> 'CustomOriginConfig' ->> 'OriginSslProtocols' AS origin_ssl_policy + FROM + aws_cloudfront_distribution, + jsonb_array_elements(origins) AS o + WHERE + o -> 'CustomOriginConfig' -> 'OriginSslProtocols' -> 'Items' @> '["TLSv1.2%", "TLSv1.1%"]' + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN o.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN o.arn IS NOT NULL THEN title || ' use secure cipher.' + ELSE title || ' does not use secure cipher.' + END AS reason + FROM + aws_cloudfront_distribution AS b + LEFT JOIN origin_protocols AS o ON b.arn = o.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should use secure SSL cipher \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudfront_distribution_waf_enabled.yaml b/compliance/controls/aws/aws_cloudfront_distribution_waf_enabled.yaml old mode 100755 new mode 100644 index d1f919ada..c68ffc33b --- a/compliance/controls/aws/aws_cloudfront_distribution_waf_enabled.yaml +++ b/compliance/controls/aws/aws_cloudfront_distribution_waf_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether CloudFront distributions are associated with either AWS WAF or AWS WAFv2 web ACLs. The control fails if the distribution is not associated with a web ACL. ID: aws_cloudfront_distribution_waf_enabled -Title: "CloudFront distributions should have AWS WAF enabled" -Description: "This control checks whether CloudFront distributions are associated with either AWS WAF or AWS WAFv2 web ACLs. The control fails if the distribution is not associated with a web ACL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when web_acl_id <> '' then 'ok'\n else 'alarm'\n end as status,\n case\n when web_acl_id <> '' then title || ' associated with WAF.'\n else title || ' not associated with WAF.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudfront_distribution;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN web_acl_id <> '' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN web_acl_id <> '' THEN title || ' associated with WAF.' + ELSE title || ' not associated with WAF.' + END AS reason, + region, + account_id + FROM + aws_cloudfront_distribution; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/CloudFront -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should have AWS WAF enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_bucket_not_public.yaml b/compliance/controls/aws/aws_cloudtrail_bucket_not_public.yaml old mode 100755 new mode 100644 index 8b9e6439f..455bdf960 --- a/compliance/controls/aws/aws_cloudtrail_bucket_not_public.yaml +++ b/compliance/controls/aws/aws_cloudtrail_bucket_not_public.yaml @@ -1,69 +1,69 @@ +Description: CloudTrail logs a record of every API call made in your account. These log files are stored in an S3 bucket. Security Hub recommends that the S3 bucket policy, or access control list (ACL), be applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs. ID: aws_cloudtrail_bucket_not_public -Title: "Ensure the S3 bucket CloudTrail logs to is not publicly accessible" -Description: "CloudTrail logs a record of every API call made in your account. These log files are stored in an S3 bucket. Security Hub recommends that the S3 bucket policy, or access control list (ACL), be applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with public_bucket_data as ( - -- note the counts are not exactly CORRECT because of the jsonb_array_elements joins, - -- but will be non-zero if any matches are found - select - t.s3_bucket_name as name, - b.arn, - t.region, - t.account_id, - t.tags, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - t._ctx, - count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AllUsers') as all_user_grants, - count(acl_grant) filter (where acl_grant -> 'Grantee' ->> 'URI' like '%acs.amazonaws.com/groups/global/AuthenticatedUsers') as auth_user_grants, - count(s) filter (where s ->> 'Effect' = 'Allow' and p = '*' ) as anon_statements - from - aws_cloudtrail_trail as t - left join aws_s3_bucket as b on t.s3_bucket_name = b.name - left join jsonb_array_elements(acl -> 'Grants') as acl_grant on true - left join jsonb_array_elements(policy_std -> 'Statement') as s on true - left join jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p on true - group by - t.s3_bucket_name, - b.arn, - t.region, - t.account_id, - t.tags, - t.og_account_id, - t.og_resource_id, - t._ctx - ) - select - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when arn is null then 'arn:aws:s3::' || name - else arn - end as resource, - case - when arn is null then 'skip' - when all_user_grants > 0 then 'alarm' - when auth_user_grants > 0 then 'alarm' - when anon_statements > 0 then 'alarm' - else 'ok' - end as status, - case - when arn is null then name || ' not found in account ' || account_id || '.' - when all_user_grants > 0 then name || ' grants access to AllUsers in ACL.' - when auth_user_grants > 0 then name || ' grants access to AuthenticatedUsers in ACL.' - when anon_statements > 0 then name || ' grants access to AWS:*" in bucket policy.' - else name || ' does not grant anonymous access in ACL or bucket policy.' - end as reason - , region, account_id - from - public_bucket_data; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH public_bucket_data AS ( + SELECT + t.s3_bucket_name AS name, + b.arn, + t.region, + t.account_id, + t.tags, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + t._ctx, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AllUsers') AS all_user_grants, + COUNT(acl_grant) FILTER (WHERE acl_grant -> 'Grantee' ->> 'URI' LIKE '%acs.amazonaws.com/groups/global/AuthenticatedUsers') AS auth_user_grants, + COUNT(s) FILTER (WHERE s ->> 'Effect' = 'Allow' AND p = '*') AS anon_statements + FROM + aws_cloudtrail_trail AS t + LEFT JOIN aws_s3_bucket AS b ON t.s3_bucket_name = b.name + LEFT JOIN jsonb_array_elements(acl -> 'Grants') AS acl_grant ON TRUE + LEFT JOIN jsonb_array_elements(policy_std -> 'Statement') AS s ON TRUE + LEFT JOIN jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p ON TRUE + GROUP BY + t.s3_bucket_name, + b.arn, + t.region, + t.account_id, + t.tags, + t.og_account_id, + t.og_resource_id, + t._ctx + ) + SELECT + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN arn IS NULL THEN 'arn:aws:s3::' || name + ELSE arn + END AS resource, + CASE + WHEN arn IS NULL THEN 'skip' + WHEN all_user_grants > 0 THEN 'alarm' + WHEN auth_user_grants > 0 THEN 'alarm' + WHEN anon_statements > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN arn IS NULL THEN name || ' not found in account ' || account_id || '.' + WHEN all_user_grants > 0 THEN name || ' grants access to AllUsers in ACL.' + WHEN auth_user_grants > 0 THEN name || ' grants access to AuthenticatedUsers in ACL.' + WHEN anon_statements > 0 THEN name || ' grants access to AWS:* in bucket policy.' + ELSE name || ' does not grant anonymous access in ACL or bucket policy.' + END AS reason, + region, + account_id + FROM + public_bucket_data; Severity: high Tags: category: @@ -84,5 +84,4 @@ Tags: - aws service: - AWS/CloudTrail -IntegrationType: - - aws_cloud_account +Title: Ensure the S3 bucket CloudTrail logs to is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_multi_region_read_write_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_multi_region_read_write_enabled.yaml old mode 100755 new mode 100644 index 7a87f8b13..941d3bb80 --- a/compliance/controls/aws/aws_cloudtrail_multi_region_read_write_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_multi_region_read_write_enabled.yaml @@ -1,51 +1,47 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation). ID: aws_cloudtrail_multi_region_read_write_enabled -Title: "CloudTrail trails should be enabled in all regions" -Description: "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with event_selectors_trail_details as ( - select - distinct account_id - from - aws_cloudtrail_trail, - jsonb_array_elements(event_selectors) as e - where - (is_logging and is_multi_region_trail and e ->> 'ReadWriteType' = 'All') - ), - advanced_event_selectors_trail_details as ( - select - distinct account_id - from - aws_cloudtrail_trail, - jsonb_array_elements_text(advanced_event_selectors) as a - where - -- when readOnly = true, then it is readOnly, when readOnly = false then it is writeOnly, if advanced_event_selectors is not null then it is both ReadWriteType - (is_logging and is_multi_region_trail and advanced_event_selectors is not null and (not a like '%readOnly%')) - ) - select - a.title as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when d.account_id is null and ad.account_id is null then 'alarm' - else 'ok' - end as status, - case - when d.account_id is null and ad.account_id is null then 'cloudtrail disabled.' - else 'cloudtrail enabled.' - end as reason - - , a.account_id - from - aws_account as a - left join event_selectors_trail_details as d on d.account_id = a.account_id - left join advanced_event_selectors_trail_details as ad on ad.account_id = a.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH event_selectors_trail_details AS ( + SELECT DISTINCT account_id + FROM aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS e + WHERE is_logging + AND is_multi_region_trail + AND e ->> 'ReadWriteType' = 'All' + ), + advanced_event_selectors_trail_details AS ( + SELECT DISTINCT account_id + FROM aws_cloudtrail_trail, + jsonb_array_elements_text(advanced_event_selectors) AS a + WHERE is_logging + AND is_multi_region_trail + AND advanced_event_selectors IS NOT NULL + AND (NOT a LIKE '%readOnly%') + ) + SELECT a.title AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN d.account_id IS NULL AND ad.account_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.account_id IS NULL AND ad.account_id IS NULL THEN 'cloudtrail disabled.' + ELSE 'cloudtrail enabled.' + END AS reason, + a.account_id + FROM aws_account AS a + LEFT JOIN event_selectors_trail_details AS d ON d.account_id = a.account_id + LEFT JOIN advanced_event_selectors_trail_details AS ad ON ad.account_id = a.account_id; Severity: high Tags: category: @@ -66,5 +62,4 @@ Tags: - aws service: - AWS/CloudTrail -IntegrationType: - - aws_cloud_account +Title: CloudTrail trails should be enabled in all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_multi_region_trail_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_multi_region_trail_enabled.yaml old mode 100755 new mode 100644 index 9189885bc..e9fdce494 --- a/compliance/controls/aws/aws_cloudtrail_multi_region_trail_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_multi_region_trail_enabled.yaml @@ -1,59 +1,60 @@ +Description: AWS CloudTrail records AWS Management Console actions and API calls. You can identify which users and accounts called AWS, the source IP address from where the calls were made, and when the calls occurred. CloudTrail will deliver log files from all AWS Regions to your S3 bucket if MULTI_REGION_CLOUD_TRAIL_ENABLED is enabled. ID: aws_cloudtrail_multi_region_trail_enabled -Title: "At least one multi-region AWS CloudTrail should be present in an account" -Description: "AWS CloudTrail records AWS Management Console actions and API calls. You can identify which users and accounts called AWS, the source IP address from where the calls were made, and when the calls occurred. CloudTrail will deliver log files from all AWS Regions to your S3 bucket if MULTI_REGION_CLOUD_TRAIL_ENABLED is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_account + - aws_cloudtrail_trail + Parameters: [] + PrimaryTable: aws_account QueryToExecute: | - with multi_region_trails as ( - select + WITH multi_region_trails AS ( + SELECT account_id, - count(account_id) as num_multregion_trails - from + COUNT(account_id) AS num_multregion_trails + FROM aws_cloudtrail_trail - where - is_multi_region_trail and region = home_region - and is_logging - group by + WHERE + is_multi_region_trail + AND region = home_region + AND is_logging + GROUP BY account_id, is_multi_region_trail - ), organization_trails as ( - select + ), organization_trails AS ( + SELECT is_organization_trail, is_logging, is_multi_region_trail, account_id - from + FROM aws_cloudtrail_trail - where + WHERE is_organization_trail ) - select - distinct a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when coalesce(num_multregion_trails, 0) >= 1 then 'ok' - when o.is_organization_trail and o.is_logging and o.is_multi_region_trail then 'ok' - when o.is_organization_trail and o.is_multi_region_trail and o.is_logging is null then 'info' - else 'alarm' - end as status, - case - when coalesce(num_multregion_trails, 0) >= 1 then a.title || ' has ' || coalesce(num_multregion_trails, 0) || ' multi-region trail(s).' - when o.is_organization_trail and o.is_logging and o.is_multi_region_trail then a.title || ' has multi-region trail(s).' - when o.is_organization_trail and o.is_multi_region_trail and o.is_logging is null then a.title || ' has organization trail, check organization account for cloudtrail logging status.' - else a.title || ' does not have multi-region trail(s).' - end as reason - - , a.account_id - from - aws_account as a - left join multi_region_trails as b on a.account_id = b.account_id - left join organization_trails as o on a.account_id = o.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_account - - aws_cloudtrail_trail - Parameters: [] + SELECT + DISTINCT a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN COALESCE(num_multregion_trails, 0) >= 1 THEN 'ok' + WHEN o.is_organization_trail AND o.is_logging AND o.is_multi_region_trail THEN 'ok' + WHEN o.is_organization_trail AND o.is_multi_region_trail AND o.is_logging IS NULL THEN 'info' + ELSE 'alarm' + END AS status, + CASE + WHEN COALESCE(num_multregion_trails, 0) >= 1 THEN a.title || ' has ' || COALESCE(num_multregion_trails, 0) || ' multi-region trail(s).' + WHEN o.is_organization_trail AND o.is_logging AND o.is_multi_region_trail THEN a.title || ' has multi-region trail(s).' + WHEN o.is_organization_trail AND o.is_multi_region_trail AND o.is_logging IS NULL THEN a.title || ' has organization trail, check organization account for cloudtrail logging status.' + ELSE a.title || ' does not have multi-region trail(s).' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN multi_region_trails AS b ON a.account_id = b.account_id + LEFT JOIN organization_trails AS o ON a.account_id = o.account_id; Severity: high Tags: category: @@ -76,12 +77,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -94,5 +95,4 @@ Tags: - AWS/CloudTrail soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: At least one multi-region AWS CloudTrail should be present in an account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_multi_region_trail_integrated_with_logs.yaml b/compliance/controls/aws/aws_cloudtrail_multi_region_trail_integrated_with_logs.yaml old mode 100755 new mode 100644 index 5d959f746..35ee47c98 --- a/compliance/controls/aws/aws_cloudtrail_multi_region_trail_integrated_with_logs.yaml +++ b/compliance/controls/aws/aws_cloudtrail_multi_region_trail_integrated_with_logs.yaml @@ -1,31 +1,31 @@ +Description: Ensure that CloudTrail multi region trail is integrated with CloudWatch logs. ID: aws_cloudtrail_multi_region_trail_integrated_with_logs -Title: "CloudTrail multi region trails should be integrated with CloudWatch logs" -Description: "Ensure that CloudTrail multi region trail is itegrated with CloudWatch logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then 'ok' - else 'alarm' - end as status, - case - when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then title || ' multi region trail integrated with CloudWatch logs.' - else title || ' multi region trail not integrated with CloudWatch logs.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region - and is_multi_region_trail; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_group_arn != 'null' AND ((latest_delivery_time) > CURRENT_DATE - 1) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_group_arn != 'null' AND ((latest_delivery_time) > CURRENT_DATE - 1) THEN title || ' multi region trail integrated with CloudWatch logs.' + ELSE title || ' multi region trail not integrated with CloudWatch logs.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region + AND is_multi_region_trail; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudTrail multi region trails should be integrated with CloudWatch logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_s3_data_events_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_s3_data_events_enabled.yaml old mode 100755 new mode 100644 index 5fa4e0f37..d0e43711a --- a/compliance/controls/aws/aws_cloudtrail_s3_data_events_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_s3_data_events_enabled.yaml @@ -1,14 +1,59 @@ +Description: The collection of Simple Storage Service (AWS S3) data events helps in detecting any anomalous activity. The details include AWS account information that accessed an AWS S3 bucket, IP address, and time of event. ID: aws_cloudtrail_s3_data_events_enabled -Title: "All S3 buckets should log S3 data events in CloudTrail" -Description: "The collection of Simple Storage Service (AWS S3) data events helps in detecting any anomalous activity. The details include AWS account information that accessed an AWS S3 bucket, IP address, and time of event." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with s3_selectors as (\n select\n name as trail_name,\n is_multi_region_trail,\n bucket_selector\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as event_selector,\n jsonb_array_elements(event_selector -> 'DataResources') as data_resource,\n jsonb_array_elements_text(data_resource -> 'Values') as bucket_selector\n where\n is_multi_region_trail\n and data_resource ->> 'Type' = 'AWS::S3::Object'\n and event_selector ->> 'ReadWriteType' = 'All'\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when count(bucket_selector) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(bucket_selector) > 0 then b.name || ' object-level data events logging enabled.'\n else b.name || ' object-level data events logging disabled.'\n end as reason\n \n , b.region, b.account_id\nfrom\n aws_s3_bucket as b\n left join s3_selectors on bucket_selector like (b.arn || '%') or bucket_selector = 'arn:aws:s3'\ngroup by\n b.account_id, b.region, b.arn, b.name, b.tags, b.og_account_id, b.og_resource_id, b._ctx;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( + SELECT + name AS trail_name, + is_multi_region_trail, + bucket_selector + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(event_selector -> 'DataResources') AS data_resource, + jsonb_array_elements_text(data_resource -> 'Values') AS bucket_selector + WHERE + is_multi_region_trail + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' = 'All' + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 + THEN b.name || ' object-level data events logging enabled.' + ELSE b.name || ' object-level data events logging disabled.' + END AS reason, + b.region, + b.account_id + FROM + aws_s3_bucket AS b + LEFT JOIN s3_selectors + ON bucket_selector LIKE (b.arn || '%') + OR bucket_selector = 'arn:aws:s3' + GROUP BY + b.account_id, + b.region, + b.arn, + b.name, + b.tags, + b.og_account_id, + b.og_resource_id, + b._ctx; Severity: medium Tags: category: @@ -33,12 +78,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -51,5 +96,4 @@ Tags: - AWS/CloudTrail soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: All S3 buckets should log S3 data events in CloudTrail \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_s3_logging_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_s3_logging_enabled.yaml old mode 100755 new mode 100644 index 56d565d16..7acda7e05 --- a/compliance/controls/aws/aws_cloudtrail_s3_logging_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_s3_logging_enabled.yaml @@ -1,14 +1,39 @@ +Description: S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket. ID: aws_cloudtrail_s3_logging_enabled -Title: "Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket" -Description: "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n t.arn as resource,\n t.og_account_id as og_account_id,\n t.og_resource_id as og_resource_id,\n case\n when b.logging is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.logging is not null then t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.'\n else t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.'\n end as reason\n \n , t.region, t.account_id\nfrom\n aws_cloudtrail_trail t\n inner join aws_s3_bucket b on t.s3_bucket_name = b.name\nwhere\n t.region = t.home_region;\n" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN b.logging IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.logging IS NOT NULL THEN + t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging enabled.' + ELSE + t.title || '''s logging bucket ' || t.s3_bucket_name || ' has access logging disabled.' + END AS reason, + t.region, + t.account_id + FROM + aws_cloudtrail_trail t + INNER JOIN + aws_s3_bucket b + ON + t.s3_bucket_name = b.name + WHERE + t.region = t.home_region; Severity: medium Tags: category: @@ -29,5 +54,4 @@ Tags: - aws service: - AWS/CloudTrail -IntegrationType: - - aws_cloud_account +Title: Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_s3_object_read_events_audit_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_s3_object_read_events_audit_enabled.yaml old mode 100755 new mode 100644 index 709e9ccda..5c27a6f98 --- a/compliance/controls/aws/aws_cloudtrail_s3_object_read_events_audit_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_s3_object_read_events_audit_enabled.yaml @@ -1,14 +1,69 @@ +Description: This rule enables object-level logging for read events for S3 buckets. Object-level logging for read events helps in identifying the requestor who performed the read operation on the S3 bucket objects. ID: aws_cloudtrail_s3_object_read_events_audit_enabled -Title: "Ensure that Object-level logging for read events is enabled for S3 bucket" -Description: "This rule enables object-level logging for read events for S3 buckets. Object-level logging for read events helps in identifying the requestor who performed the read operation on the S3 bucket objects." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with s3_selectors as\n(\n select\n name as trail_name,\n is_multi_region_trail,\n bucket_selector\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as event_selector,\n jsonb_array_elements(case jsonb_typeof(event_selector -> 'DataResources') \n when 'array' then event_selector -> 'DataResources'\n else '[]' end) as data_resource,\n jsonb_array_elements(case jsonb_typeof(data_resource -> 'Values') \n when 'array' then data_resource -> 'Values'\n else '[]' end) as bucket_selector\n where\n is_multi_region_trail\n and data_resource ->> 'Type' = 'AWS::S3::Object'\n and event_selector ->> 'ReadWriteType' in\n (\n 'ReadOnly',\n 'All'\n )\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when count(bucket_selector) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(bucket_selector) > 0 then b.name || ' object-level read events logging enabled.'\n else b.name || ' object-level read events logging disabled.'\n end as reason\n , region, account_id\nfrom\n aws_s3_bucket as b\n left join\n s3_selectors\n on bucket_selector::json::text like ('%' || b.arn || '%')\n or bucket_selector::json::text = '\"arn:aws:s3\"'\ngroup by\n b.og_account_id, b.og_resource_id,b.account_id, b.region, b.arn, b.name, b.tags, b._ctx;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS ( + SELECT + name AS trail_name, + is_multi_region_trail, + bucket_selector + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements( + CASE jsonb_typeof(event_selector -> 'DataResources') + WHEN 'array' THEN event_selector -> 'DataResources' + ELSE '[]' + END + ) AS data_resource, + jsonb_array_elements( + CASE jsonb_typeof(data_resource -> 'Values') + WHEN 'array' THEN data_resource -> 'Values' + ELSE '[]' + END + ) AS bucket_selector + WHERE + is_multi_region_trail + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN ('ReadOnly', 'All') + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level read events logging enabled.' + ELSE b.name || ' object-level read events logging disabled.' + END AS reason, + region, + account_id + FROM + aws_s3_bucket AS b + LEFT JOIN + s3_selectors + ON bucket_selector::json::text LIKE ('%' || b.arn || '%') + OR bucket_selector::json::text = '\"arn:aws:s3\"' + GROUP BY + b.og_account_id, + b.og_resource_id, + b.account_id, + b.region, + b.arn, + b.name, + b.tags, + b._ctx; Severity: high Tags: category: @@ -29,5 +84,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: Ensure that Object-level logging for read events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_s3_object_write_events_audit_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_s3_object_write_events_audit_enabled.yaml old mode 100755 new mode 100644 index d9e719f23..0c269c0b6 --- a/compliance/controls/aws/aws_cloudtrail_s3_object_write_events_audit_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_s3_object_write_events_audit_enabled.yaml @@ -1,14 +1,60 @@ +Description: This rule enables object-level logging for write events for S3 buckets. Object-level logging for write events helps in identifying the requestor who performed the write operation on the S3 bucket objects. ID: aws_cloudtrail_s3_object_write_events_audit_enabled -Title: "Ensure that Object-level logging for write events is enabled for S3 bucket" -Description: "This rule enables object-level logging for write events for S3 buckets. Object-level logging for write events helps in identifying the requestor who performed the write operation on the S3 bucket objects." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with s3_selectors as\n(\n select\n name as trail_name,\n is_multi_region_trail,\n bucket_selector\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as event_selector,\n jsonb_array_elements(case jsonb_typeof(event_selector -> 'DataResources') \n when 'array' then event_selector -> 'DataResources'\n else '[]' end) as data_resource,\n jsonb_array_elements(case jsonb_typeof(data_resource -> 'Values') \n when 'array' then data_resource -> 'Values'\n else '[]' end) as bucket_selector\n where\n is_multi_region_trail\n and data_resource ->> 'Type' = 'AWS::S3::Object'\n and event_selector ->> 'ReadWriteType' in\n (\n 'WriteOnly',\n 'All'\n )\n)\nselect\n b.arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when count(bucket_selector) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(bucket_selector) > 0 then b.name || ' object-level write events logging enabled.'\n else b.name || ' object-level write events logging disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_s3_bucket as b\n left join\n s3_selectors\n on bucket_selector::json::text like ('%' || b.arn || '%')\n or bucket_selector::json::text = '\"arn:aws:s3\"'\ngroup by\n b.og_account_id, b.og_resource_id, b.account_id, b.region, b.arn, b.name, b.tags, b._ctx;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH s3_selectors AS + ( + SELECT + name AS trail_name, + is_multi_region_trail, + bucket_selector + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS event_selector, + jsonb_array_elements(CASE jsonb_typeof(event_selector -> 'DataResources') + WHEN 'array' THEN event_selector -> 'DataResources' + ELSE '[]' END) AS data_resource, + jsonb_array_elements(CASE jsonb_typeof(data_resource -> 'Values') + WHEN 'array' THEN data_resource -> 'Values' + ELSE '[]' END) AS bucket_selector + WHERE + is_multi_region_trail + AND data_resource ->> 'Type' = 'AWS::S3::Object' + AND event_selector ->> 'ReadWriteType' IN + ( + 'WriteOnly', + 'All' + ) + ) + SELECT + b.arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN COUNT(bucket_selector) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(bucket_selector) > 0 THEN b.name || ' object-level write events logging enabled.' + ELSE b.name || ' object-level write events logging disabled.' + END AS reason, + region, account_id + FROM + aws_s3_bucket AS b + LEFT JOIN + s3_selectors + ON bucket_selector::json::text LIKE ('%' || b.arn || '%') + OR bucket_selector::json::text = '\"arn:aws:s3\"' + GROUP BY + b.og_account_id, b.og_resource_id, b.account_id, b.region, b.arn, b.name, b.tags, b._ctx; Severity: high Tags: category: @@ -29,5 +75,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: Ensure that Object-level logging for write events is enabled for S3 bucket \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_security_trail_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_security_trail_enabled.yaml old mode 100755 new mode 100644 index 111a470ae..52a53b03d --- a/compliance/controls/aws/aws_cloudtrail_security_trail_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_security_trail_enabled.yaml @@ -1,13 +1,87 @@ +Description: This rule helps ensure the use of AWS recommended security best practices for AWS CloudTrail, by checking for the enablement of multiple settings. These include the use of log encryption, log validation, and enabling AWS CloudTrail in multiple regions. ID: aws_cloudtrail_security_trail_enabled -Title: "At least one trail should be enabled with security best practices" -Description: "This rule helps ensure the use of AWS recommended security best practices for AWS CloudTrail, by checking for the enablement of multiple settings. These include the use of log encryption, log validation, and enabling AWS CloudTrail in multiple regions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails_enabled as (\n select\n distinct arn,\n is_logging,\n event_selectors,\n coalesce(\n jsonb_agg(g) filter ( where not (g = 'null') ),\n $$[]$$::jsonb\n ) as excludeManagementEventSources\n from\n aws_cloudtrail_trail\n left join jsonb_array_elements(event_selectors) as e on true\n left join jsonb_array_elements_text(e -> 'ExcludeManagementEventSources') as g on true\n where\n home_region = region\n group by arn, is_logging, event_selectors\n ),\n all_trails as (\n select\n a.arn as arn,\n tags,\n _ctx,\n case\n when a.is_logging is null then b.is_logging\n else a.is_logging\n end as is_logging,\n case\n when a.event_selectors is null then b.event_selectors\n else a.event_selectors\n end as event_selectors,\n b.excludeManagementEventSources,\n a.include_global_service_events,\n a.is_multi_region_trail,\n a.log_file_validation_enabled,\n a.kms_key_id,\n a.region,\n a.account_id,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n a.title\n from\n aws_cloudtrail_trail as a\n left join trails_enabled as b on a.arn = b.arn\n )\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when not is_logging then 'alarm'\n when not include_global_service_events then 'alarm'\n when not is_multi_region_trail then 'alarm'\n when not log_file_validation_enabled then 'alarm'\n when kms_key_id is null then 'alarm'\n when not (jsonb_array_length(event_selectors) = 1 and event_selectors @> '[{\"ReadWriteType\":\"All\"}]') then 'alarm'\n when not (event_selectors @> '[{\"IncludeManagementEvents\":true}]') then 'alarm'\n when jsonb_array_length(excludeManagementEventSources) > 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when not is_logging then title || ' disabled.'\n when not include_global_service_events then title || ' not recording global service events.'\n when not is_multi_region_trail then title || ' not a muti-region trail.'\n when not log_file_validation_enabled then title || ' log file validation disabled.'\n when kms_key_id is null then title || ' not encrypted with a KMS key.'\n when not (jsonb_array_length(event_selectors) = 1 and event_selectors @> '[{\"ReadWriteType\":\"All\"}]') then title || ' not recording events for both reads and writes.'\n when not (event_selectors @> '[{\"IncludeManagementEvents\":true}]') then title || ' not recording management events.'\n when jsonb_array_length(excludeManagementEventSources) > 0 then title || ' excludes management events for ' || trim(excludeManagementEventSources::text, '[]') || '.'\n else title || ' meets all security best practices.'\n end as reason\n\n \n , region, account_id\nfrom\n all_trails;\n" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails_enabled AS ( + SELECT + DISTINCT arn, + is_logging, + event_selectors, + COALESCE( + jsonb_agg(g) FILTER (WHERE NOT (g = 'null')), + $$[]$$::jsonb + ) AS excludeManagementEventSources + FROM + aws_cloudtrail_trail + LEFT JOIN jsonb_array_elements(event_selectors) AS e ON TRUE + LEFT JOIN jsonb_array_elements_text(e -> 'ExcludeManagementEventSources') AS g ON TRUE + WHERE + home_region = region + GROUP BY arn, is_logging, event_selectors + ), + all_trails AS ( + SELECT + a.arn AS arn, + tags, + _ctx, + CASE + WHEN a.is_logging IS NULL THEN b.is_logging + ELSE a.is_logging + END AS is_logging, + CASE + WHEN a.event_selectors IS NULL THEN b.event_selectors + ELSE a.event_selectors + END AS event_selectors, + b.excludeManagementEventSources, + a.include_global_service_events, + a.is_multi_region_trail, + a.log_file_validation_enabled, + a.kms_key_id, + a.region, + a.account_id, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + a.title + FROM + aws_cloudtrail_trail AS a + LEFT JOIN trails_enabled AS b ON a.arn = b.arn + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT is_logging THEN 'alarm' + WHEN NOT include_global_service_events THEN 'alarm' + WHEN NOT is_multi_region_trail THEN 'alarm' + WHEN NOT log_file_validation_enabled THEN 'alarm' + WHEN kms_key_id IS NULL THEN 'alarm' + WHEN NOT (jsonb_array_length(event_selectors) = 1 AND event_selectors @> '[{"ReadWriteType":"All"}]') THEN 'alarm' + WHEN NOT (event_selectors @> '[{"IncludeManagementEvents":true}]') THEN 'alarm' + WHEN jsonb_array_length(excludeManagementEventSources) > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT is_logging THEN title || ' disabled.' + WHEN NOT include_global_service_events THEN title || ' not recording global service events.' + WHEN NOT is_multi_region_trail THEN title || ' not a muti-region trail.' + WHEN NOT log_file_validation_enabled THEN title || ' log file validation disabled.' + WHEN kms_key_id IS NULL THEN title || ' not encrypted with a KMS key.' + WHEN NOT (jsonb_array_length(event_selectors) = 1 AND event_selectors @> '[{"ReadWriteType":"All"}]') THEN title || ' not recording events for both reads and writes.' + WHEN NOT (event_selectors @> '[{"IncludeManagementEvents":true}]') THEN title || ' not recording management events.' + WHEN jsonb_array_length(excludeManagementEventSources) > 0 THEN title || ' excludes management events for ' || TRIM(excludeManagementEventSources::text, '[]') || '.' + ELSE title || ' meets all security best practices.' + END AS reason, + region, account_id + FROM + all_trails; Severity: high Tags: category: @@ -20,10 +94,10 @@ Tags: - "true" gxp_eu_annex_11: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -32,5 +106,4 @@ Tags: - AWS/CloudTrail soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: At least one trail should be enabled with security best practices \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_trail_bucket_mfa_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_trail_bucket_mfa_enabled.yaml old mode 100755 new mode 100644 index 53af3c03b..06ec9422d --- a/compliance/controls/aws/aws_cloudtrail_trail_bucket_mfa_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_trail_bucket_mfa_enabled.yaml @@ -1,34 +1,35 @@ +Description: Ensure that CloudTrail trail S3 buckets should have MFA delete enabled. MFA delete helps prevent accidental bucket deletions by requiring the user who initiates the delete action to prove physical possession of an MFA device with an MFA code and adding an extra layer of friction and security to the delete action. ID: aws_cloudtrail_trail_bucket_mfa_enabled -Title: "CloudTrail trail S3 buckets MFA delete should be enabled" -Description: "Ensure that CloudTrail trail S3 buckets should have MFA delete enabled. MFA delete helps prevent accidental bucket deletions by requiring the user who initiates the delete action to prove physical possession of an MFA device with an MFA code and adding an extra layer of friction and security to the delete action." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - t.arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when t.s3_bucket_name is null then 'alarm' - when b.versioning_mfa_delete then 'ok' - else 'alarm' - end as status, - case - when t.s3_bucket_name is null then t.title || ' logging disabled.' - when b.versioning_mfa_delete then t.title || t.s3_bucket_name || ' MFA enabled.' - else t.title || t.s3_bucket_name || ' MFA disabled.' - end as reason - from - aws_cloudtrail_trail t - left join aws_s3_bucket b on t.s3_bucket_name = b.name - where - t.region = t.home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN t.s3_bucket_name IS NULL THEN 'alarm' + WHEN b.versioning_mfa_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN t.s3_bucket_name IS NULL THEN t.title || ' logging disabled.' + WHEN b.versioning_mfa_delete THEN t.title || t.s3_bucket_name || ' MFA enabled.' + ELSE t.title || t.s3_bucket_name || ' MFA disabled.' + END AS reason + FROM + aws_cloudtrail_trail t + LEFT JOIN + aws_s3_bucket b ON t.s3_bucket_name = b.name + WHERE + t.region = t.home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudTrail trail S3 buckets MFA delete should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_trail_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_trail_enabled.yaml old mode 100755 new mode 100644 index a8e767965..5305e86fc --- a/compliance/controls/aws/aws_cloudtrail_trail_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_trail_enabled.yaml @@ -1,13 +1,42 @@ +Description: AWS CloudTrail can help in non-repudiation by recording AWS Management Console actions and API calls. You can identify the users and AWS accounts that called an AWS service, the source IP address where the calls generated, and the timings of the calls. Details of captured data are seen within AWS CloudTrail Record Contents. ID: aws_cloudtrail_trail_enabled -Title: "At least one enabled trail should be present in a region" -Description: "AWS CloudTrail can help in non-repudiation by recording AWS Management Console actions and API calls. You can identify the users and AWS accounts that called an AWS service, the source IP address where the calls generated, and the timings of the calls. Details of captured data are seen within AWS CloudTrail Record Contents." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails_enabled as (\n select\n arn,\n is_logging\n from\n aws_cloudtrail_trail\n where\n home_region = region\n)\nselect\n a.arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.is_logging is null and a.is_logging then 'ok'\n when b.is_logging then 'ok'\n else 'alarm'\n end as status,\n case\n when b.is_logging is null and a.is_logging then a.title || ' enabled.'\n when b.is_logging then a.title || ' enabled.'\n else a.title || ' disabled.'\n end as reason\n \n , a.region, a.account_id\nfrom\n aws_cloudtrail_trail as a\nleft join trails_enabled b on a.arn = b.arn;\n" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH trails_enabled AS ( + SELECT + arn, + is_logging + FROM + aws_cloudtrail_trail + WHERE + home_region = region + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.is_logging IS NULL AND a.is_logging THEN 'ok' + WHEN b.is_logging THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.is_logging IS NULL AND a.is_logging THEN a.title || ' enabled.' + WHEN b.is_logging THEN a.title || ' enabled.' + ELSE a.title || ' disabled.' + END AS reason, + a.region, + a.account_id + FROM + aws_cloudtrail_trail AS a + LEFT JOIN trails_enabled b ON a.arn = b.arn; Severity: high Tags: category: @@ -30,12 +59,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +77,4 @@ Tags: - AWS/CloudTrail soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: At least one enabled trail should be present in a region \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_trail_enabled_account.yaml b/compliance/controls/aws/aws_cloudtrail_trail_enabled_account.yaml old mode 100755 new mode 100644 index a58cbf8ba..97418db08 --- a/compliance/controls/aws/aws_cloudtrail_trail_enabled_account.yaml +++ b/compliance/controls/aws/aws_cloudtrail_trail_enabled_account.yaml @@ -1,42 +1,42 @@ +Description: Ensure that at least one CloudTrail trail is enabled in the AWS account. ID: aws_cloudtrail_trail_enabled_account -Title: "At least one CloudTrail trail should be enabled in the AWS account" -Description: "Ensure that at least one CloudTrail trail is enabled in the AWS account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with trails_enabled_account as ( - select + ListOfTables: + - aws_cloudtrail_trail + - aws_account + Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH trails_enabled_account AS ( + SELECT account_id, - count(*) as num - from + COUNT(*) AS num + FROM aws_cloudtrail_trail - where + WHERE home_region = region - and is_logging - group by + AND is_logging + GROUP BY account_id ) - select - a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.num > 0 then 'ok' - else 'alarm' - end as status, - case - when b.num > 0 then a.title || ' has ' || b.num || ' trails enabled.' - else a.title || ' has no trail enabled.' - end as reason - from - aws_account as a - left join trails_enabled_account b on a.account_id = b.account_id; - PrimaryTable: aws_account - ListOfTables: - - aws_cloudtrail_trail - - aws_account - Parameters: [] + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.num > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.num > 0 THEN a.title || ' has ' || b.num || ' trails enabled.' + ELSE a.title || ' has no trail enabled.' + END AS reason + FROM + aws_account AS a + LEFT JOIN trails_enabled_account b ON a.account_id = b.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: At least one CloudTrail trail should be enabled in the AWS account \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_trail_insight_selectors_and_logging_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_trail_insight_selectors_and_logging_enabled.yaml old mode 100755 new mode 100644 index 3f3fea39f..9405a668f --- a/compliance/controls/aws/aws_cloudtrail_trail_insight_selectors_and_logging_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_trail_insight_selectors_and_logging_enabled.yaml @@ -1,32 +1,32 @@ +Description: CloudTrail Insights provides a powerful way to search and analyze CloudTrail log data using pre-built queries and machine learning algorithms. This can help to identify potential security threats and suspicious activity in near real-time, such as unauthorized access attempts, policy changes, or resource modifications. ID: aws_cloudtrail_trail_insight_selectors_and_logging_enabled -Title: "CloudTrail trails should have insight selectors and logging enabled" -Description: "CloudTrail Insights provides a powerful way to search and analyze CloudTrail log data using pre-built queries and machine learning algorithms. This can help to identify potential security threats and suspicious activity in near real-time, such as unauthorized access attempts, policy changes, or resource modifications." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not is_logging then 'alarm' - when is_logging and has_insight_selectors then 'ok' - else 'alarm' - end as status, - case - when not is_logging then title || ' logging is disabled.' - when is_logging and has_insight_selectors then title || ' has insight selectors and logging enabled.' - else title || ' does not has insight selectors enabled.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT is_logging THEN 'alarm' + WHEN is_logging AND has_insight_selectors THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT is_logging THEN title || ' logging is disabled.' + WHEN is_logging AND has_insight_selectors THEN title || ' has insight selectors and logging enabled.' + ELSE title || ' does not have insight selectors enabled.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudTrail trails should have insight selectors and logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_trail_integrated_with_logs.yaml b/compliance/controls/aws/aws_cloudtrail_trail_integrated_with_logs.yaml old mode 100755 new mode 100644 index b648ab1ef..ec3f8405d --- a/compliance/controls/aws/aws_cloudtrail_trail_integrated_with_logs.yaml +++ b/compliance/controls/aws/aws_cloudtrail_trail_integrated_with_logs.yaml @@ -1,13 +1,33 @@ +Description: Use AWS CloudWatch to centrally collect and manage log event activity. Inclusion of AWS CloudTrail data provides details of API call activity within your AWS account. ID: aws_cloudtrail_trail_integrated_with_logs -Title: "CloudTrail trails should be integrated with CloudWatch logs" -Description: "Use AWS CloudWatch to centrally collect and manage log event activity. Inclusion of AWS CloudTrail data provides details of API call activity within your AWS account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then 'ok'\n else 'alarm'\n end as status,\n case\n when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then title || ' integrated with CloudWatch logs.'\n else title || ' not integrated with CloudWatch logs.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;\n" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > current_date - 1) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > current_date - 1) + THEN title || ' integrated with CloudWatch logs.' + ELSE title || ' not integrated with CloudWatch logs.' + END AS reason, + region, + account_id + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: category: @@ -30,12 +50,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +68,4 @@ Tags: - AWS/CloudTrail soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: CloudTrail trails should be integrated with CloudWatch logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_trail_logs_encrypted_with_kms_cmk.yaml b/compliance/controls/aws/aws_cloudtrail_trail_logs_encrypted_with_kms_cmk.yaml old mode 100755 new mode 100644 index 27199723f..d89d76fa0 --- a/compliance/controls/aws/aws_cloudtrail_trail_logs_encrypted_with_kms_cmk.yaml +++ b/compliance/controls/aws/aws_cloudtrail_trail_logs_encrypted_with_kms_cmk.yaml @@ -1,30 +1,32 @@ +Description: To help protect sensitive data at rest, ensure encryption is enabled for your AWS CloudWatch Log Groups. ID: aws_cloudtrail_trail_logs_encrypted_with_kms_cmk -Title: "CloudTrail trail logs should be encrypted with KMS CMK" -Description: "To help protect sensitive data at rest, ensure encryption is enabled for your AWS CloudWatch Log Groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when kms_key_id is null then 'alarm' - else 'ok' - end as status, - case - when kms_key_id is null then title || ' logs are not encrypted at rest.' - else title || ' logs are encrypted at rest.' - end as reason - , region, account_id - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' logs are not encrypted at rest.' + ELSE title || ' logs are encrypted at rest.' + END AS reason, + region, + account_id + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: medium Tags: category: @@ -47,12 +49,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -65,5 +67,4 @@ Tags: - AWS/CloudTrail soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: CloudTrail trail logs should be encrypted with KMS CMK \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudtrail_trail_validation_enabled.yaml b/compliance/controls/aws/aws_cloudtrail_trail_validation_enabled.yaml old mode 100755 new mode 100644 index 516fbf20d..d37ec3671 --- a/compliance/controls/aws/aws_cloudtrail_trail_validation_enabled.yaml +++ b/compliance/controls/aws/aws_cloudtrail_trail_validation_enabled.yaml @@ -1,30 +1,32 @@ +Description: 'Utilize AWS CloudTrail log file validation to check the integrity of CloudTrail logs. Log file validation helps determine if a log file was modified or deleted or unchanged after CloudTrail delivered it. This feature is built using industry standard algorithms: SHA-256 for hashing and SHA-256 with RSA for digital signing. This makes it computationally infeasible to modify, delete or forge CloudTrail log files without detection.' ID: aws_cloudtrail_trail_validation_enabled -Title: "CloudTrail trail log file validation should be enabled" -Description: "Utilize AWS CloudTrail log file validation to check the integrity of CloudTrail logs. Log file validation helps determine if a log file was modified or deleted or unchanged after CloudTrail delivered it. This feature is built using industry standard algorithms: SHA-256 for hashing and SHA-256 with RSA for digital signing. This makes it computationally infeasible to modify, delete or forge CloudTrail log files without detection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_file_validation_enabled then 'ok' - else 'alarm' - end as status, - case - when log_file_validation_enabled then title || ' log file validation enabled.' - else title || ' log file validation disabled.' - end as reason - , region, account_id - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_file_validation_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_file_validation_enabled THEN title || ' log file validation enabled.' + ELSE title || ' log file validation disabled.' + END AS reason, + region, + account_id + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: high Tags: category: @@ -45,12 +47,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -61,5 +63,4 @@ Tags: - AWS/CloudTrail soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: CloudTrail trail log file validation should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudwatch_alarm_action_enabled.yaml b/compliance/controls/aws/aws_cloudwatch_alarm_action_enabled.yaml old mode 100755 new mode 100644 index 474650ed3..6c6186e1f --- a/compliance/controls/aws/aws_cloudwatch_alarm_action_enabled.yaml +++ b/compliance/controls/aws/aws_cloudwatch_alarm_action_enabled.yaml @@ -1,13 +1,37 @@ +Description: Checks if CloudWatch alarms have an action configured for the ALARM, INSUFFICIENT_DATA, or OK state. Optionally checks if any actions match a named ARN. The rule is non-compliant if there is no action specified for the alarm or optional parameter. ID: aws_cloudwatch_alarm_action_enabled -Title: "CloudWatch alarm should have an action configured" -Description: "Checks if CloudWatch alarms have an action configured for the ALARM, INSUFFICIENT_DATA, or OK state. Optionally checks if any actions match a named ARN. The rule is non-compliant if there is no action specified for the alarm or optional parameter." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(alarm_actions) = 0\n and jsonb_array_length(insufficient_data_actions) = 0\n and jsonb_array_length(ok_actions) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when jsonb_array_length(alarm_actions) = 0\n and jsonb_array_length(insufficient_data_actions) = 0\n and jsonb_array_length(ok_actions) = 0 then title || ' no action enabled.'\n when jsonb_array_length(alarm_actions) != 0 then title || ' alarm action enabled.'\n when jsonb_array_length(insufficient_data_actions) != 0 then title || ' insufficient data action enabled.'\n when jsonb_array_length(ok_actions) != 0 then title || ' ok action enabled.'\n else 'ok'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudwatch_alarm;\n" - PrimaryTable: aws_cloudwatch_alarm ListOfTables: - aws_cloudwatch_alarm Parameters: [] + PrimaryTable: aws_cloudwatch_alarm + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(alarm_actions) = 0 + AND jsonb_array_length(insufficient_data_actions) = 0 + AND jsonb_array_length(ok_actions) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN jsonb_array_length(alarm_actions) = 0 + AND jsonb_array_length(insufficient_data_actions) = 0 + AND jsonb_array_length(ok_actions) = 0 THEN title || ' no action enabled.' + WHEN jsonb_array_length(alarm_actions) != 0 THEN title || ' alarm action enabled.' + WHEN jsonb_array_length(insufficient_data_actions) != 0 THEN title || ' insufficient data action enabled.' + WHEN jsonb_array_length(ok_actions) != 0 THEN title || ' ok action enabled.' + ELSE 'ok' + END AS reason, + region, + account_id + FROM + aws_cloudwatch_alarm; Severity: medium Tags: category: @@ -24,12 +48,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -38,5 +62,4 @@ Tags: - AWS/CloudWatch soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: CloudWatch alarm should have an action configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudwatch_alarm_action_enabled_check.yaml b/compliance/controls/aws/aws_cloudwatch_alarm_action_enabled_check.yaml old mode 100755 new mode 100644 index f512a44c5..4366a1203 --- a/compliance/controls/aws/aws_cloudwatch_alarm_action_enabled_check.yaml +++ b/compliance/controls/aws/aws_cloudwatch_alarm_action_enabled_check.yaml @@ -1,13 +1,30 @@ +Description: Checks if AWS CloudWatch alarm actions are in enabled state. The rule is non-compliant if the CloudWatch alarm actions are not in enabled state. ID: aws_cloudwatch_alarm_action_enabled_check -Title: "CloudWatch alarm action should be enabled" -Description: "Checks if AWS CloudWatch alarm actions are in enabled state. The rule is non-compliant if the CloudWatch alarm actions are not in enabled state." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when actions_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when actions_enabled then title || ' alarm actions enabled.'\n else title || ' alarm actions disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudwatch_alarm;\n" - PrimaryTable: aws_cloudwatch_alarm ListOfTables: - aws_cloudwatch_alarm Parameters: [] + PrimaryTable: aws_cloudwatch_alarm + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN actions_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN actions_enabled THEN title || ' alarm actions enabled.' + ELSE title || ' alarm actions disabled.' + END AS reason, + region, + account_id + FROM + aws_cloudwatch_alarm; Severity: medium Tags: category: @@ -22,5 +39,4 @@ Tags: - AWS/CloudWatch soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: CloudWatch alarm action should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudwatch_cross_account_sharing.yaml b/compliance/controls/aws/aws_cloudwatch_cross_account_sharing.yaml old mode 100755 new mode 100644 index c3d4d2d3d..dd3f5e91d --- a/compliance/controls/aws/aws_cloudwatch_cross_account_sharing.yaml +++ b/compliance/controls/aws/aws_cloudwatch_cross_account_sharing.yaml @@ -1,41 +1,42 @@ +Description: Ensure that your AWS CloudWatch is configured to allow access only to friendly AWS accounts in order to prevent unauthorized users from sharing their CloudWatch events. ID: aws_cloudwatch_cross_account_sharing -Title: "CloudWatch should not allow cross-account sharing" -Description: "Ensure that your AWS CloudWatch is configured to allow access only to friendly AWS accounts in order to prevent unauthorized users from sharing their CloudWatch events." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_role_cross_account_sharing_count as ( - select + ListOfTables: + - aws_iam_role + - aws_account + Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH iam_role_cross_account_sharing_count AS ( + SELECT arn, - replace(replace(replace((a -> 'Principal' ->> 'AWS'), '[',''), ']', ''), '"', '') as cross_account_details, + REPLACE(REPLACE(REPLACE((a -> 'Principal' ->> 'AWS'), '[', ''), ']', ''), '"', '') AS cross_account_details, account_id - from + FROM aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as a - where + JSONB_ARRAY_ELEMENTS(assume_role_policy_std -> 'Statement') AS a + WHERE name = 'CloudWatch-CrossAccountSharingRole' ) - select - a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when c.arn is null then 'ok' - else 'info' - end as status, - case - when c.arn is null then 'CloudWatch does not allow cross-account sharing.' - else 'CloudWatch allow cross-account sharing with '|| cross_account_details || '.' - end as reason - from - aws_account as a - left join iam_role_cross_account_sharing_count as c on c.account_id = a.account_id; - PrimaryTable: aws_iam_role - ListOfTables: - - aws_iam_role - - aws_account - Parameters: [] + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.arn IS NULL THEN 'ok' + ELSE 'info' + END AS status, + CASE + WHEN c.arn IS NULL THEN 'CloudWatch does not allow cross-account sharing.' + ELSE 'CloudWatch allows cross-account sharing with ' || cross_account_details || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN iam_role_cross_account_sharing_count AS c + ON c.account_id = a.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudWatch should not allow cross-account sharing \ No newline at end of file diff --git a/compliance/controls/aws/aws_cloudwatch_log_group_retention_period_365.yaml b/compliance/controls/aws/aws_cloudwatch_log_group_retention_period_365.yaml old mode 100755 new mode 100644 index af07a9104..03e85e9e8 --- a/compliance/controls/aws/aws_cloudwatch_log_group_retention_period_365.yaml +++ b/compliance/controls/aws/aws_cloudwatch_log_group_retention_period_365.yaml @@ -1,13 +1,31 @@ +Description: Ensure a minimum duration of event log data is retained for your log groups to help with troubleshooting and forensics investigations. ID: aws_cloudwatch_log_group_retention_period_365 -Title: "Log group retention period should be at least 365 days" -Description: "Ensure a minimum duration of event log data is retained for your log groups to help with troubleshooting and forensics investigations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when retention_in_days is null or retention_in_days < 365 then 'alarm'\n else 'ok'\n end as status,\n case\n when retention_in_days is null then title || ' retention period not set.'\n when retention_in_days < 365 then title || ' retention period less than 365 days.'\n else title || ' retention period 365 days or above.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudwatch_log_group;\n" - PrimaryTable: aws_cloudwatch_log_group ListOfTables: - aws_cloudwatch_log_group Parameters: [] + PrimaryTable: aws_cloudwatch_log_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN retention_in_days IS NULL OR retention_in_days < 365 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN retention_in_days IS NULL THEN title || ' retention period not set.' + WHEN retention_in_days < 365 THEN title || ' retention period less than 365 days.' + ELSE title || ' retention period 365 days or above.' + END AS reason, + region, + account_id + FROM + aws_cloudwatch_log_group; Severity: high Tags: category: @@ -26,12 +44,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -44,5 +62,4 @@ Tags: - AWS/CloudWatch soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Log group retention period should be at least 365 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_codebuild_project_artifact_encryption_enabled.yaml b/compliance/controls/aws/aws_codebuild_project_artifact_encryption_enabled.yaml old mode 100755 new mode 100644 index 68463bda4..54c4405be --- a/compliance/controls/aws/aws_codebuild_project_artifact_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_codebuild_project_artifact_encryption_enabled.yaml @@ -1,13 +1,44 @@ +Description: This control checks if a CodeBuild project has encryption enabled for all of its artifacts. The rule is non-compliant if 'encryptionDisabled' is set to 'true' for any primary or secondary (if present) artifact configurations. ID: aws_codebuild_project_artifact_encryption_enabled -Title: "CodeBuild project artifact encryption should be enabled" -Description: "This control checks if a CodeBuild project has encryption enabled for all of its artifacts. The rule is non-compliant if 'encryptionDisabled' is set to 'true' for any primary or secondary (if present) artifact configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with secondary_artifact as (\n select\n distinct arn\n from\n aws_codebuild_project,\n jsonb_array_elements(secondary_artifacts) as a\n where\n a -> 'EncryptionDisabled' = 'true'\n)\nselect\n a.arn as resource,\n p.og_account_id as og_account_id,\n p.og_resource_id as og_resource_id,\n case\n when p.artifacts ->> 'EncryptionDisabled' = 'false'\n and (p.secondary_artifacts is null or a.arn is null) then 'ok'\n else 'alarm'\n end as status,\n case\n when p.artifacts ->> 'EncryptionDisabled' = 'false'\n and (p.secondary_artifacts is null or a.arn is null) then p.title || ' all artifacts encryption enabled.'\n else p.title || ' all artifacts encryption not enabled.'\n end as reason\n \n , p.region, p.account_id\nfrom\n aws_codebuild_project as p\n left join secondary_artifact as a on a.arn = p.arn;\n" - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + WITH secondary_artifact AS ( + SELECT + DISTINCT arn + FROM + aws_codebuild_project, + jsonb_array_elements(secondary_artifacts) AS a + WHERE + a -> 'EncryptionDisabled' = 'true' + ) + SELECT + a.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.artifacts ->> 'EncryptionDisabled' = 'false' + AND (p.secondary_artifacts IS NULL OR a.arn IS NULL) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.artifacts ->> 'EncryptionDisabled' = 'false' + AND (p.secondary_artifacts IS NULL OR a.arn IS NULL) + THEN p.title || ' all artifacts encryption enabled.' + ELSE p.title || ' all artifacts encryption not enabled.' + END AS reason, + p.region, + p.account_id + FROM + aws_codebuild_project AS p + LEFT JOIN secondary_artifact AS a ON a.arn = p.arn; Severity: high Tags: category: @@ -24,5 +55,4 @@ Tags: - aws service: - AWS/CodeBuild -IntegrationType: - - aws_cloud_account +Title: CodeBuild project artifact encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_codebuild_project_build_greater_then_90_days.yaml b/compliance/controls/aws/aws_codebuild_project_build_greater_then_90_days.yaml old mode 100755 new mode 100644 index cb5e68a8b..256e87690 --- a/compliance/controls/aws/aws_codebuild_project_build_greater_then_90_days.yaml +++ b/compliance/controls/aws/aws_codebuild_project_build_greater_then_90_days.yaml @@ -1,24 +1,30 @@ +Description: Ensure CodeBuild projects are currently in use. It is recommended to remove the stale ones. ID: aws_codebuild_project_build_greater_then_90_days -Title: "CodeBuild projects should not be unused for 90 days or greater" -Description: "Ensure CodeBuild projects are curently in use. It is recommended to remove the stale ones." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with latest_codebuild_build as ( - select + ListOfTables: + - aws_codebuild_build + - aws_codebuild_project + Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + WITH latest_codebuild_build AS ( + SELECT project_name, region, account_id, - min(date_part('day', now() - end_time)) as build_time - from + MIN(DATE_PART('day', NOW() - end_time)) AS build_time + FROM aws_codebuild_build - group by + GROUP BY project_name, region, account_id ), - codebuild_projects as ( - select + codebuild_projects AS ( + SELECT arn, name, region, @@ -28,9 +34,9 @@ Query: _ctx, og_account_id, og_resource_id - from + FROM aws_codebuild_project - group by + GROUP BY name, tags, arn, @@ -41,28 +47,25 @@ Query: og_account_id, og_resource_id ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when b.build_time is null then 'alarm' - when b.build_time < 90 then 'ok' - else 'alarm' - end as status, - case - when b.build_time is null then p.title || ' has no builds.' - else p.title || ' was build ' || build_time || ' day(s) before.' - end as reason - from - codebuild_projects as p - left join latest_codebuild_build as b on p.name = b.project_name and p.region = b.region and p.account_id = b.account_id; - PrimaryTable: aws_codebuild_project - ListOfTables: - - aws_codebuild_build - - aws_codebuild_project - Parameters: [] + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN b.build_time IS NULL THEN 'alarm' + WHEN b.build_time < 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.build_time IS NULL THEN p.title || ' has no builds.' + ELSE p.title || ' was built ' || build_time || ' day(s) before.' + END AS reason + FROM + codebuild_projects AS p + LEFT JOIN latest_codebuild_build AS b + ON p.name = b.project_name + AND p.region = b.region + AND p.account_id = b.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CodeBuild projects should not be unused for 90 days or greater \ No newline at end of file diff --git a/compliance/controls/aws/aws_codebuild_project_environment_privileged_mode_disabled.yaml b/compliance/controls/aws/aws_codebuild_project_environment_privileged_mode_disabled.yaml old mode 100755 new mode 100644 index 68d54ca59..e89a3e19e --- a/compliance/controls/aws/aws_codebuild_project_environment_privileged_mode_disabled.yaml +++ b/compliance/controls/aws/aws_codebuild_project_environment_privileged_mode_disabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks if an AWS CodeBuild project environment has privileged mode enabled. This control fails when an AWS CodeBuild project environment has privileged mode enabled. ID: aws_codebuild_project_environment_privileged_mode_disabled -Title: "CodeBuild project environments should not have privileged mode enabled" -Description: "This control checks if an AWS CodeBuild project environment has privileged mode enabled. This control fails when an AWS CodeBuild project environment has privileged mode enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when environment ->> 'PrivilegedMode' = 'true' then 'alarm'\n else 'ok'\n end as status,\n case\n when environment ->> 'PrivilegedMode' = 'true' then title || ' environment privileged mode enabled.'\n else title || ' environment privileged mode disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_codebuild_project;\n" - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN environment ->> 'PrivilegedMode' = 'true' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN environment ->> 'PrivilegedMode' = 'true' THEN title || ' environment privileged mode enabled.' + ELSE title || ' environment privileged mode disabled.' + END AS reason, + region, + account_id + FROM + aws_codebuild_project; Severity: high Tags: category: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/CodeBuild -IntegrationType: - - aws_cloud_account +Title: CodeBuild project environments should not have privileged mode enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_codebuild_project_logging_enabled.yaml b/compliance/controls/aws/aws_codebuild_project_logging_enabled.yaml old mode 100755 new mode 100644 index 7ff838393..d20464d77 --- a/compliance/controls/aws/aws_codebuild_project_logging_enabled.yaml +++ b/compliance/controls/aws/aws_codebuild_project_logging_enabled.yaml @@ -1,13 +1,32 @@ +Description: This control checks if an AWS CodeBuild project environment has at least one log option enabled. The rule is non-compliant if the status of all present log configurations is set to 'DISABLED'. ID: aws_codebuild_project_logging_enabled -Title: "CodeBuild projects should have logging enabled" -Description: "This control checks if an AWS CodeBuild project environment has at least one log option enabled. The rule is non-compliant if the status of all present log configurations is set to 'DISABLED'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when logs_config -> 'CloudWatchLogs' ->> 'Status' = 'ENABLED' or logs_config -> 'S3Logs' ->> 'Status' = 'ENABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when logs_config -> 'CloudWatchLogs' ->> 'Status' = 'ENABLED' or logs_config -> 'S3Logs' ->> 'Status' = 'ENABLED' then title || ' logging enabled.'\n else title || ' logging disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_codebuild_project;\n" - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logs_config -> 'CloudWatchLogs' ->> 'Status' = 'ENABLED' + OR logs_config -> 'S3Logs' ->> 'Status' = 'ENABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN logs_config -> 'CloudWatchLogs' ->> 'Status' = 'ENABLED' + OR logs_config -> 'S3Logs' ->> 'Status' = 'ENABLED' THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason, + region, + account_id + FROM + aws_codebuild_project; Severity: medium Tags: category: @@ -24,5 +43,4 @@ Tags: - aws service: - AWS/CodeBuild -IntegrationType: - - aws_cloud_account +Title: CodeBuild projects should have logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_codebuild_project_plaintext_env_variables_no_sensitive_aws_values.yaml b/compliance/controls/aws/aws_codebuild_project_plaintext_env_variables_no_sensitive_aws_values.yaml old mode 100755 new mode 100644 index a0a76e958..fca78fa3c --- a/compliance/controls/aws/aws_codebuild_project_plaintext_env_variables_no_sensitive_aws_values.yaml +++ b/compliance/controls/aws/aws_codebuild_project_plaintext_env_variables_no_sensitive_aws_values.yaml @@ -1,13 +1,42 @@ +Description: Ensure authentication credentials AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY do not exist within AWS CodeBuild project environments. Do not store these variables in clear text. Storing these variables in clear text leads to unintended data exposure and unauthorized access. ID: aws_codebuild_project_plaintext_env_variables_no_sensitive_aws_values -Title: "CodeBuild project plaintext environment variables should not contain sensitive AWS values" -Description: "Ensure authentication credentials AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY do not exist within AWS CodeBuild project environments. Do not store these variables in clear text. Storing these variables in clear text leads to unintended data exposure and unauthorized access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with invalid_key_name as (\n select\n distinct arn,\n name\n from\n aws_codebuild_project,\n jsonb_array_elements(environment -> 'EnvironmentVariables') as env\n where\n env ->> 'Name' ilike any(array['%AWS_ACCESS_KEY_ID%', '%AWS_SECRET_ACCESS_KEY%', '%PASSWORD%'])\n and env ->> 'Type' = 'PLAINTEXT'\n)\nselect\n a.arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is null then a.title || ' has no plaintext environment variables with sensitive AWS values.'\n else a.title || ' has plaintext environment variables with sensitive AWS values.'\n end as reason\n \n , a.region, a.account_id\nfrom\n aws_codebuild_project as a\n left join invalid_key_name b on a.arn = b.arn;\n" - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + WITH invalid_key_name AS ( + SELECT DISTINCT + arn, + name + FROM + aws_codebuild_project, + jsonb_array_elements(environment -> 'EnvironmentVariables') AS env + WHERE + env ->> 'Name' ILIKE ANY(ARRAY['%AWS_ACCESS_KEY_ID%', '%AWS_SECRET_ACCESS_KEY%', '%PASSWORD%']) + AND env ->> 'Type' = 'PLAINTEXT' + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NULL THEN a.title || ' has no plaintext environment variables with sensitive AWS values.' + ELSE a.title || ' has plaintext environment variables with sensitive AWS values.' + END AS reason, + a.region, + a.account_id + FROM + aws_codebuild_project AS a + LEFT JOIN invalid_key_name b ON a.arn = b.arn; Severity: high Tags: category: @@ -38,5 +67,4 @@ Tags: - AWS/CodeBuild soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: CodeBuild project plaintext environment variables should not contain sensitive AWS values \ No newline at end of file diff --git a/compliance/controls/aws/aws_codebuild_project_s3_logs_encryption_enabled.yaml b/compliance/controls/aws/aws_codebuild_project_s3_logs_encryption_enabled.yaml old mode 100755 new mode 100644 index a786b7cd0..e768bfda3 --- a/compliance/controls/aws/aws_codebuild_project_s3_logs_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_codebuild_project_s3_logs_encryption_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks if S3 logs for a CodeBuild project are encrypted. The control fails if encryption is deactivated for S3 logs for a CodeBuild project. ID: aws_codebuild_project_s3_logs_encryption_enabled -Title: "CodeBuild project S3 logs should be encrypted" -Description: "This control checks if S3 logs for a CodeBuild project are encrypted. The control fails if encryption is deactivated for S3 logs for a CodeBuild project." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when not (logs_config -> 'S3Logs' ->> 'EncryptionDisabled')::bool then 'ok'\n else 'alarm'\n end as status,\n case\n when not (logs_config -> 'S3Logs' ->> 'EncryptionDisabled')::bool then title || ' S3Logs encryption enabled.'\n else title || ' S3Logs encryption disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_codebuild_project;\n" - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT (logs_config -> 'S3Logs' ->> 'EncryptionDisabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT (logs_config -> 'S3Logs' ->> 'EncryptionDisabled')::bool THEN title || ' S3Logs encryption enabled.' + ELSE title || ' S3Logs encryption disabled.' + END AS reason, + region, + account_id + FROM + aws_codebuild_project; Severity: low Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/CodeBuild -IntegrationType: - - aws_cloud_account +Title: CodeBuild project S3 logs should be encrypted \ No newline at end of file diff --git a/compliance/controls/aws/aws_codebuild_project_source_repo_oauth_configured.yaml b/compliance/controls/aws/aws_codebuild_project_source_repo_oauth_configured.yaml old mode 100755 new mode 100644 index 3534deb33..db9e70850 --- a/compliance/controls/aws/aws_codebuild_project_source_repo_oauth_configured.yaml +++ b/compliance/controls/aws/aws_codebuild_project_source_repo_oauth_configured.yaml @@ -1,14 +1,36 @@ +Description: Ensure the GitHub or Bitbucket source repository URL does not contain personal access tokens, user name and password within AWS Codebuild project environments. ID: aws_codebuild_project_source_repo_oauth_configured -Title: "CodeBuild GitHub or Bitbucket source repository URLs should use OAuth" -Description: "Ensure the GitHub or Bitbucket source repository URL does not contain personal access tokens, user name and password within AWS Codebuild project environments." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n p.arn as resource,\n p.og_account_id as og_account_id,\n p.og_resource_id as og_resource_id,\n case\n when p.source ->> 'Type' not in ('GITHUB', 'BITBUCKET') then 'skip'\n when c.auth_type = 'OAUTH' then 'ok'\n else 'alarm'\n end as status,\n case\n when p.source ->> 'Type' = 'NO_SOURCE' then p.title || ' doesn''t have input source code.'\n when p.source ->> 'Type' not in ('GITHUB', 'BITBUCKET') then p.title || ' source code isn''t in GitHub/Bitbucket repository.'\n when c.auth_type = 'OAUTH' then p.title || ' using OAuth to connect source repository.'\n else p.title || ' not using OAuth to connect source repository.'\n end as reason\n \n , p.region, p.account_id\nfrom\n aws_codebuild_project as p\n left join aws_codebuild_source_credential as c on (p.region = c.region and p.source ->> 'Type' = c.server_type);\n" - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project - aws_codebuild_source_credential Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.source ->> 'Type' NOT IN ('GITHUB', 'BITBUCKET') THEN 'skip' + WHEN c.auth_type = 'OAUTH' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.source ->> 'Type' = 'NO_SOURCE' THEN p.title || ' doesn''t have input source code.' + WHEN p.source ->> 'Type' NOT IN ('GITHUB', 'BITBUCKET') THEN p.title || ' source code isn''t in GitHub/Bitbucket repository.' + WHEN c.auth_type = 'OAUTH' THEN p.title || ' using OAuth to connect source repository.' + ELSE p.title || ' not using OAuth to connect source repository.' + END AS reason, + p.region, + p.account_id + FROM + aws_codebuild_project AS p + LEFT JOIN aws_codebuild_source_credential AS c + ON (p.region = c.region AND p.source ->> 'Type' = c.server_type); Severity: high Tags: category: @@ -39,5 +61,4 @@ Tags: - AWS/CodeBuild soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: CodeBuild GitHub or Bitbucket source repository URLs should use OAuth \ No newline at end of file diff --git a/compliance/controls/aws/aws_codebuild_project_with_user_controlled_buildspec.yaml b/compliance/controls/aws/aws_codebuild_project_with_user_controlled_buildspec.yaml old mode 100755 new mode 100644 index 08c20e2c6..d26d868fb --- a/compliance/controls/aws/aws_codebuild_project_with_user_controlled_buildspec.yaml +++ b/compliance/controls/aws/aws_codebuild_project_with_user_controlled_buildspec.yaml @@ -1,14 +1,28 @@ +Description: This control checks if buildspec.yml is used from a trusted source which user cant interfere with. ID: aws_codebuild_project_with_user_controlled_buildspec -Title: "CodeBuild projects should not use an user controlled buildspec" -Description: "This control checks if buildspec.yml is used from a trusted source which user cant interfere with." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when split_part(source ->> 'Buildspec', '.', -1) = 'yml' then 'alarm'\n else 'ok'\n end as status,\n case\n when split_part(source ->> 'Buildspec', '.', -1) = 'yml' then title || ' uses a user controlled buildspec.'\n else title || ' does not uses a user controlled buildspec.'\n end as reason\n \n \nfrom\n aws_codebuild_project;" - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN split_part(source ->> 'Buildspec', '.', -1) = 'yml' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN split_part(source ->> 'Buildspec', '.', -1) = 'yml' THEN title || ' uses a user controlled buildspec.' + ELSE title || ' does not use a user controlled buildspec.' + END AS reason + FROM + aws_codebuild_project; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CodeBuild projects should not use an user controlled buildspec \ No newline at end of file diff --git a/compliance/controls/aws/aws_config_configuration_recorder_no_failed_deliver_logs.yaml b/compliance/controls/aws/aws_config_configuration_recorder_no_failed_deliver_logs.yaml old mode 100755 new mode 100644 index 40ff31295..ec3d05757 --- a/compliance/controls/aws/aws_config_configuration_recorder_no_failed_deliver_logs.yaml +++ b/compliance/controls/aws/aws_config_configuration_recorder_no_failed_deliver_logs.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether Config configuration recorder fails to deliver logs. This control is non-compliant if Config configuration recorder fails to deliver logs. ID: aws_config_configuration_recorder_no_failed_deliver_logs -Title: "Config configuration recorder should not fail to deliver logs" -Description: "This control checks whether Config configuration recorder fails to deliver logs. This control is non-compliant if Config configuration recorder fails to deliver logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when status ->> 'LastStatus' = 'FAILURE' then 'alarm'\n else 'ok'\n end as status,\n case\n when status ->> 'LastStatus' = 'FAILURE' then title || ' has failed deliver logs.'\n else title || ' does not have failed deliver logs.'\n end as reason\n \nfrom\n aws_config_configuration_recorder;" - PrimaryTable: aws_config_configuration_recorder ListOfTables: - aws_config_configuration_recorder Parameters: [] + PrimaryTable: aws_config_configuration_recorder + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN status ->> 'LastStatus' = 'FAILURE' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status ->> 'LastStatus' = 'FAILURE' THEN title || ' has failed deliver logs.' + ELSE title || ' does not have failed deliver logs.' + END AS reason + FROM + aws_config_configuration_recorder; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Config configuration recorder should not fail to deliver logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_config_enabled_all_regions.yaml b/compliance/controls/aws/aws_config_enabled_all_regions.yaml old mode 100755 new mode 100644 index f789606c1..2aadbac21 --- a/compliance/controls/aws/aws_config_enabled_all_regions.yaml +++ b/compliance/controls/aws/aws_config_enabled_all_regions.yaml @@ -1,15 +1,73 @@ +Description: This control checks whether AWS Config is enabled in the account for the local Region and is recording all resources. ID: aws_config_enabled_all_regions -Title: "AWS Config should be enabled" -Description: "This control checks whether AWS Config is enabled in the account for the local Region and is recording all resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with global_recorders as (\n select\n count(*) as global_config_recorders\n from\n aws_config_configuration_recorder\n where\n recording_group -> 'IncludeGlobalResourceTypes' = 'true'\n and recording_group -> 'AllSupported' = 'true'\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n),\nregions as (\n select\n 'arn:aws::' || a.region || ':' || a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when\n g.global_config_recorders >= 1\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n then 0\n when a.opt_in_status = 'not-opted-in' then 1\n else 2\n end as status,\n a.region, a.account_id\n from\n global_recorders as g,\n aws_region as a\n left join aws_config_configuration_recorder as r on r.account_id = a.account_id and r.region = a.name\n),\nresults as (\n SELECT \n account_id AS resource,\n og_account_id as og_account_id,\n og_account_id as og_resource_id,\n case\n when max(status) = 2 then 'alarm'\n when max(status) = 1 then 'skip'\n when max(status) = 0 then 'ok'\n end as status,\n case\n when max(status) = 2 then 'AWS Config is not enabled for this account on regions: [' || string_agg(region, ',') || ']' \n when max(status) = 1 then 'Account is not opted in regions: [' || string_agg(region, ',') || ']'\n when max(status) = 0 then 'AWS Config is enabled for this account on regions: [' || string_agg(region, ',') || ']'\n end as reason\n FROM regions\n GROUP BY account_id, og_account_id\n)\nSELECT \n r.resource AS resource,\n r.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n r.status as status,\n r.reason as reason\nFROM results as r JOIN aws_account as a ON r.og_account_id = a.og_account_id\n" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_config_configuration_recorder - aws_region Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH global_recorders AS ( + SELECT + COUNT(*) AS global_config_recorders + FROM + aws_config_configuration_recorder + WHERE + recording_group -> 'IncludeGlobalResourceTypes' = 'true' + AND recording_group -> 'AllSupported' = 'true' + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + ), + regions AS ( + SELECT + 'arn:aws::' || a.region || ':' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN + g.global_config_recorders >= 1 + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + THEN 0 + WHEN a.opt_in_status = 'not-opted-in' THEN 1 + ELSE 2 + END AS status, + a.region, a.account_id + FROM + global_recorders AS g, + aws_region AS a + LEFT JOIN aws_config_configuration_recorder AS r ON r.account_id = a.account_id AND r.region = a.name + ), + results AS ( + SELECT + account_id AS resource, + og_account_id AS og_account_id, + og_account_id AS og_resource_id, + CASE + WHEN MAX(status) = 2 THEN 'alarm' + WHEN MAX(status) = 1 THEN 'skip' + WHEN MAX(status) = 0 THEN 'ok' + END AS status, + CASE + WHEN MAX(status) = 2 THEN 'AWS Config is not enabled for this account on regions: [' || STRING_AGG(region, ',') || ']' + WHEN MAX(status) = 1 THEN 'Account is not opted in regions: [' || STRING_AGG(region, ',') || ']' + WHEN MAX(status) = 0 THEN 'AWS Config is enabled for this account on regions: [' || STRING_AGG(region, ',') || ']' + END AS reason + FROM regions + GROUP BY account_id, og_account_id + ) + SELECT + r.resource AS resource, + r.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + r.status AS status, + r.reason AS reason + FROM results AS r + JOIN aws_account AS a ON r.og_account_id = a.og_account_id Severity: high Tags: category: @@ -30,5 +88,4 @@ Tags: - aws service: - AWS/Config -IntegrationType: - - aws_cloud_account +Title: AWS Config should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_dax_cluster_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_dax_cluster_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 68b3693ea..a68b41c66 --- a/compliance/controls/aws/aws_dax_cluster_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_dax_cluster_encryption_at_rest_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether a DAX cluster is encrypted at rest. Encrypting data at rest reduces the risk of data stored on disk being accessed by a user not authenticated to AWS. The encryption adds another set of access controls to limit the ability of unauthorized users to access to the data. For example, API permissions are required to decrypt the data before it can be read. ID: aws_dax_cluster_encryption_at_rest_enabled -Title: "DynamoDB Accelerator (DAX) clusters should be encrypted at rest" -Description: "This control checks whether a DAX cluster is encrypted at rest. Encrypting data at rest reduces the risk of data stored on disk being accessed by a user not authenticated to AWS. The encryption adds another set of access controls to limit the ability of unauthorized users to access to the data. For example, API permissions are required to decrypt the data before it can be read." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when sse_description ->> 'Status' = 'ENABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when sse_description ->> 'Status' = 'ENABLED' then title || ' encryption at rest enabled.'\n else title || ' encryption at rest not enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_dax_cluster;\n" - PrimaryTable: aws_dax_cluster ListOfTables: - aws_dax_cluster Parameters: [] + PrimaryTable: aws_dax_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN sse_description ->> 'Status' = 'ENABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sse_description ->> 'Status' = 'ENABLED' THEN title || ' encryption at rest enabled.' + ELSE title || ' encryption at rest not enabled.' + END AS reason, + region, + account_id + FROM + aws_dax_cluster; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/DynamoDB -IntegrationType: - - aws_cloud_account +Title: DynamoDB Accelerator (DAX) clusters should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_directory_service_certificate_expires_90_days.yaml b/compliance/controls/aws/aws_directory_service_certificate_expires_90_days.yaml old mode 100755 new mode 100644 index b0425029e..adb96cb3f --- a/compliance/controls/aws/aws_directory_service_certificate_expires_90_days.yaml +++ b/compliance/controls/aws/aws_directory_service_certificate_expires_90_days.yaml @@ -1,26 +1,26 @@ +Description: Is it recommended to monitor certificate expiration and implement automated alerts to notify the responsible team for timely certificate replacement or removal. ID: aws_directory_service_certificate_expires_90_days -Title: "Directory Service certificates should not expire within 90 days" -Description: "Is is recommended to monitor certificate expiration and implement automated alerts to notify the responsible team for timely certificate replacement or removal." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - certificate_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when date(expiry_date_time) - date(current_date) >= 90 then 'ok' - else 'alarm' - end as status, - title || ' expires ' || to_char(expiry_date_time, 'DD-Mon-YYYY') || - ' (' || extract(day from expiry_date_time - current_date) || ' days).' as reason - from - aws_directory_service_certificate; - PrimaryTable: aws_directory_service_certificate ListOfTables: - aws_directory_service_certificate Parameters: [] + PrimaryTable: aws_directory_service_certificate + QueryToExecute: | + SELECT + certificate_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN DATE(expiry_date_time) - DATE(CURRENT_DATE) >= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' expires ' || TO_CHAR(expiry_date_time, 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM expiry_date_time - CURRENT_DATE) || ' days).' AS reason + FROM + aws_directory_service_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Directory Service certificates should not expire within 90 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_directory_service_directory_snapshots_limit_2.yaml b/compliance/controls/aws/aws_directory_service_directory_snapshots_limit_2.yaml old mode 100755 new mode 100644 index 23a711a3d..a089aa62d --- a/compliance/controls/aws/aws_directory_service_directory_snapshots_limit_2.yaml +++ b/compliance/controls/aws/aws_directory_service_directory_snapshots_limit_2.yaml @@ -1,30 +1,30 @@ +Description: Ensure you keep track of the number of manual snapshots for your monitor to guarantee sufficient capacity when it becomes necessary. ID: aws_directory_service_directory_snapshots_limit_2 -Title: "Directory Service directories manual snapshots limit should not be less than 2" -Description: "Ensure you keep track of the number of manual snapshots for your monitor to guarantee sufficient capacity when it becomes necessary." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when snapshot_limit ->> 'ManualSnapshotsLimitReached' = 'true' then 'alarm' - when ((snapshot_limit ->> 'ManualSnapshotsLimit')::int - (snapshot_limit ->> 'ManualSnapshotsCurrentCount')::int) <= 2 then 'alarm' - else 'ok' - end as status, - case - when snapshot_limit ->> 'ManualSnapshotsLimitReached' = 'true' then title || ' has reached ' || (snapshot_limit ->> 'ManualSnapshotsLimit') || ' snapshots limit.' - when ((snapshot_limit ->> 'ManualSnapshotsLimit')::int - (snapshot_limit ->> 'ManualSnapshotsCurrentCount')::int) <= 2 then title || ' is about to reach its ' || (snapshot_limit ->> 'ManualSnapshotsLimit') || ' snapshot limit.' - else title || ' is using ' || (snapshot_limit ->> 'ManualSnapshotsCurrentCount') || ' out of ' || (snapshot_limit ->> 'ManualSnapshotsLimit') || ' snapshots limit.' - end as reason - from - aws_directory_service_directory; - PrimaryTable: aws_directory_service_directory ListOfTables: - aws_directory_service_directory Parameters: [] + PrimaryTable: aws_directory_service_directory + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN snapshot_limit ->> 'ManualSnapshotsLimitReached' = 'true' THEN 'alarm' + WHEN ( (snapshot_limit ->> 'ManualSnapshotsLimit')::int - (snapshot_limit ->> 'ManualSnapshotsCurrentCount')::int ) <= 2 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN snapshot_limit ->> 'ManualSnapshotsLimitReached' = 'true' THEN title || ' has reached ' || (snapshot_limit ->> 'ManualSnapshotsLimit') || ' snapshots limit.' + WHEN ( (snapshot_limit ->> 'ManualSnapshotsLimit')::int - (snapshot_limit ->> 'ManualSnapshotsCurrentCount')::int ) <= 2 THEN title || ' is about to reach its ' || (snapshot_limit ->> 'ManualSnapshotsLimit') || ' snapshot limit.' + ELSE title || ' is using ' || (snapshot_limit ->> 'ManualSnapshotsCurrentCount') || ' out of ' || (snapshot_limit ->> 'ManualSnapshotsLimit') || ' snapshots limit.' + END AS reason + FROM + aws_directory_service_directory; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Directory Service directories manual snapshots limit should not be less than 2 \ No newline at end of file diff --git a/compliance/controls/aws/aws_directory_service_directory_sns_notifications_enabled.yaml b/compliance/controls/aws/aws_directory_service_directory_sns_notifications_enabled.yaml old mode 100755 new mode 100644 index bcc6d05a7..f18842c08 --- a/compliance/controls/aws/aws_directory_service_directory_sns_notifications_enabled.yaml +++ b/compliance/controls/aws/aws_directory_service_directory_sns_notifications_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control verifies whether SNS messaging has been set up to receive email or text notifications for any changes in the directory's status. ID: aws_directory_service_directory_sns_notifications_enabled -Title: "Directory Service directories should have SNS notification enabled" -Description: "This control verifies whether SNS messaging has been set up to receive email or text notifications for any changes in the directory's status." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when jsonb_array_length(event_topics) > 0 then 'ok' - else 'alarm' - end as status, - case - when jsonb_array_length(event_topics) > 0 then title || ' SNS notifications enabled.' - else title || ' SNS notifications disabled.' - end as reason - from - aws_directory_service_directory; - PrimaryTable: aws_directory_service_directory ListOfTables: - aws_directory_service_directory Parameters: [] + PrimaryTable: aws_directory_service_directory + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(event_topics) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(event_topics) > 0 THEN title || ' SNS notifications enabled.' + ELSE title || ' SNS notifications disabled.' + END AS reason + FROM + aws_directory_service_directory; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Directory Service directories should have SNS notification enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_dlm_ebs_snapshot_lifecycle_policy_enabled.yaml b/compliance/controls/aws/aws_dlm_ebs_snapshot_lifecycle_policy_enabled.yaml old mode 100755 new mode 100644 index f1612332f..6edb6f9c6 --- a/compliance/controls/aws/aws_dlm_ebs_snapshot_lifecycle_policy_enabled.yaml +++ b/compliance/controls/aws/aws_dlm_ebs_snapshot_lifecycle_policy_enabled.yaml @@ -1,53 +1,55 @@ +Description: Ensure DLM EBS snapshot lifecycle policy is enabled in all the regions with EBS snapshots. ID: aws_dlm_ebs_snapshot_lifecycle_policy_enabled -Title: "DLM EBS snapshot lifecycle policy should be enabled" -Description: "Ensure DLM EBS snapshot lifecycle policy is enabled in all the regions with EBS snapshots." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with region_with_ebs_snapshots as( - select - distinct region, - partition, - account_id, - _ctx, - og_account_id as og_account_id, - og_resource_id as og_resource_id - from - aws_ebs_snapshot - ), dlm_ebs_lifecycle_policy as ( - select - region, - account_id, - count(*) - from - aws_dlm_lifecycle_policy - where - policy_details ->> 'PolicyType' like 'EBS_SNAPSHOT%' - group by - region, - account_id - ) - select - 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - when p.region is not null then 'ok' - else 'alarm' - end as status, - case - when p.region is not null then 'EBS snapshot DLM policy exist in region ' || r.region || '.' - else 'EBS snapshots DLM policy does not exist in region ' || r.region || '.' - end as reason - from - region_with_ebs_snapshots as r - left join dlm_ebs_lifecycle_policy as p on p.region = r.region and r.account_id = p.account_id; - PrimaryTable: aws_dlm_lifecycle_policy ListOfTables: - aws_ebs_snapshot - aws_dlm_lifecycle_policy Parameters: [] + PrimaryTable: aws_dlm_lifecycle_policy + QueryToExecute: | + WITH region_with_ebs_snapshots AS ( + SELECT + DISTINCT region, + partition, + account_id, + _ctx, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id + FROM + aws_ebs_snapshot + ), + dlm_ebs_lifecycle_policy AS ( + SELECT + region, + account_id, + COUNT(*) + FROM + aws_dlm_lifecycle_policy + WHERE + policy_details ->> 'PolicyType' LIKE 'EBS_SNAPSHOT%' + GROUP BY + region, + account_id + ) + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN p.region IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.region IS NOT NULL THEN 'EBS snapshot DLM policy exist in region ' || r.region || '.' + ELSE 'EBS snapshots DLM policy does not exist in region ' || r.region || '.' + END AS reason + FROM + region_with_ebs_snapshots AS r + LEFT JOIN dlm_ebs_lifecycle_policy AS p + ON p.region = r.region AND r.account_id = p.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: DLM EBS snapshot lifecycle policy should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_dms_certificate_not_expired.yaml b/compliance/controls/aws/aws_dms_certificate_not_expired.yaml old mode 100755 new mode 100644 index 6b4ed5f9a..43d2507f8 --- a/compliance/controls/aws/aws_dms_certificate_not_expired.yaml +++ b/compliance/controls/aws/aws_dms_certificate_not_expired.yaml @@ -1,14 +1,30 @@ +Description: This control ensures that all expired DMS certificates are removed from AWS account. ID: aws_dms_certificate_not_expired -Title: "Ensure that all the expired DMS certificates are removed" -Description: "This control ensures that all expired DMS certificates are removed from AWS account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when valid_to_date < (current_date - interval '1' second) then 'alarm'\n else 'ok'\n end as status,\n case\n when valid_to_date < (current_date - interval '1' second) then\n title || ' expired ' || to_char(valid_to_date, 'DD-Mon-YYYY') || '.'\n else\n title || ' valid until ' || to_char(valid_to_date, 'DD-Mon-YYYY') || '.'\n end as reason\n \n \nfrom\n aws_dms_certificate;" - PrimaryTable: aws_dms_certificate ListOfTables: - aws_dms_certificate Parameters: [] + PrimaryTable: aws_dms_certificate + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN valid_to_date < (current_date - INTERVAL '1' SECOND) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN valid_to_date < (current_date - INTERVAL '1' SECOND) THEN + title || ' expired ' || TO_CHAR(valid_to_date, 'DD-Mon-YYYY') || '.' + ELSE + title || ' valid until ' || TO_CHAR(valid_to_date, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_dms_certificate; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure that all the expired DMS certificates are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_dms_endpoint_ssl_configured.yaml b/compliance/controls/aws/aws_dms_endpoint_ssl_configured.yaml old mode 100755 new mode 100644 index 1ab9bd789..7a1d42603 --- a/compliance/controls/aws/aws_dms_endpoint_ssl_configured.yaml +++ b/compliance/controls/aws/aws_dms_endpoint_ssl_configured.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an AWS DMS endpoint uses an SSL connection. The control fails if the endpoint doesn't use SSL. ID: aws_dms_endpoint_ssl_configured -Title: "DMS endpoints should use SSL" -Description: "This control checks whether an AWS DMS endpoint uses an SSL connection. The control fails if the endpoint doesn't use SSL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when ssl_mode = 'none' then 'alarm'\n else 'ok'\n end as status,\n case\n when ssl_mode = 'none' then title || ' SSL not configured.'\n else title || ' SSL configured.'\n end as reason\n \n \nfrom\n aws_dms_endpoint;" - PrimaryTable: aws_dms_endpoint ListOfTables: - aws_dms_endpoint Parameters: [] + PrimaryTable: aws_dms_endpoint + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ssl_mode = 'none' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_mode = 'none' THEN title || ' SSL not configured.' + ELSE title || ' SSL configured.' + END AS reason + FROM + aws_dms_endpoint; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: DMS endpoints should use SSL \ No newline at end of file diff --git a/compliance/controls/aws/aws_dms_replication_instance_automatic_minor_version_upgrade_enabled.yaml b/compliance/controls/aws/aws_dms_replication_instance_automatic_minor_version_upgrade_enabled.yaml old mode 100755 new mode 100644 index ed8483b92..b823e717f --- a/compliance/controls/aws/aws_dms_replication_instance_automatic_minor_version_upgrade_enabled.yaml +++ b/compliance/controls/aws/aws_dms_replication_instance_automatic_minor_version_upgrade_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control checks if automatic minor version upgrade is enabled for an AWS DMS replication instance. The control fails if automatic minor version upgrade isn't enabled for a DMS replication instance. ID: aws_dms_replication_instance_automatic_minor_version_upgrade_enabled -Title: "DMS replication instances should have automatic minor version upgrade enabled" -Description: "This control checks if automatic minor version upgrade is enabled for an AWS DMS replication instance. The control fails if automatic minor version upgrade isn't enabled for a DMS replication instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when auto_minor_version_upgrade then 'ok' - else 'alarm' - end as status, - case - when auto_minor_version_upgrade then title || ' automatic minor version upgrade enabled.' - else title || ' automatic minor version upgrade disabled.' - end as reason - from - aws_dms_replication_instance; - PrimaryTable: aws_dms_replication_instance ListOfTables: - aws_dms_replication_instance Parameters: [] + PrimaryTable: aws_dms_replication_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrade enabled.' + ELSE title || ' automatic minor version upgrade disabled.' + END AS reason + FROM + aws_dms_replication_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: DMS replication instances should have automatic minor version upgrade enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_dms_replication_instance_not_publicly_accessible.yaml b/compliance/controls/aws/aws_dms_replication_instance_not_publicly_accessible.yaml old mode 100755 new mode 100644 index e1530bf40..5ecd595c4 --- a/compliance/controls/aws/aws_dms_replication_instance_not_publicly_accessible.yaml +++ b/compliance/controls/aws/aws_dms_replication_instance_not_publicly_accessible.yaml @@ -1,13 +1,30 @@ +Description: Manage access to the AWS Cloud by ensuring DMS replication instances cannot be publicly accessed. ID: aws_dms_replication_instance_not_publicly_accessible -Title: "DMS replication instances should not be publicly accessible" -Description: "Manage access to the AWS Cloud by ensuring DMS replication instances cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when publicly_accessible then 'alarm'\n else 'ok'\n end as status,\n case\n when publicly_accessible then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end as reason\n \n , region, account_id\nfrom\n aws_dms_replication_instance;\n" - PrimaryTable: aws_dms_replication_instance ListOfTables: - aws_dms_replication_instance Parameters: [] + PrimaryTable: aws_dms_replication_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason, + region, + account_id + FROM + aws_dms_replication_instance; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/DMS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: DMS replication instances should not be publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_dms_replication_task_source_database_logging_enabled.yaml b/compliance/controls/aws/aws_dms_replication_task_source_database_logging_enabled.yaml old mode 100755 new mode 100644 index 78a42d857..6e3f1c707 --- a/compliance/controls/aws/aws_dms_replication_task_source_database_logging_enabled.yaml +++ b/compliance/controls/aws/aws_dms_replication_task_source_database_logging_enabled.yaml @@ -1,45 +1,46 @@ +Description: This control checks whether logging is enabled with the minimum severity level of LOGGER_SEVERITY_DEFAULT for DMS replication tasks SOURCE_CAPTURE and SOURCE_UNLOAD. The control fails if logging isn't enabled for these tasks or if the minimum severity level is less than LOGGER_SEVERITY_DEFAULT. ID: aws_dms_replication_task_source_database_logging_enabled -Title: "DMS replication tasks for the source database should have logging enabled" -Description: "This control checks whether logging is enabled with the minimum severity level of LOGGER_SEVERITY_DEFAULT for DMS replication tasks SOURCE_CAPTURE and SOURCE_UNLOAD. The control fails if logging isn't enabled for these tasks or if the minimum severity level is less than LOGGER_SEVERITY_DEFAULT." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with replication_task_logging as ( - select + ListOfTables: + - aws_dms_replication_task + Parameters: [] + PrimaryTable: aws_dms_replication_task + QueryToExecute: | + WITH replication_task_logging AS ( + SELECT arn, og_account_id, og_resource_id, - bool_or(o ->> 'Id' = 'SOURCE_CAPTURE' and o ->> 'Severity' in ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')) as capture_logging_enabled, - bool_or(o ->> 'Id' = 'SOURCE_UNLOAD' and o ->> 'Severity' in ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')) as unload_logging_enabled - from + BOOL_OR(o ->> 'Id' = 'SOURCE_CAPTURE' AND o ->> 'Severity' IN ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')) AS capture_logging_enabled, + BOOL_OR(o ->> 'Id' = 'SOURCE_UNLOAD' AND o ->> 'Severity' IN ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')) AS unload_logging_enabled + FROM aws_dms_replication_task, - jsonb_array_elements(replication_task_settings -> 'Logging' -> 'LogComponents') as o - group by + JSONB_ARRAY_ELEMENTS(replication_task_settings -> 'Logging' -> 'LogComponents') AS o + GROUP BY arn, og_account_id, og_resource_id ) - select - t.arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool as logging_enabled, - case - when (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool and l.capture_logging_enabled and l.unload_logging_enabled then 'ok' - else 'alarm' - end as status, - case - when (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool and l.capture_logging_enabled and l.unload_logging_enabled then title || ' source database logging enabled.' - else title || ' source database logging disabled.' - end as reason - from - aws_dms_replication_task as t - left join replication_task_logging as l on l.arn = t.arn; - PrimaryTable: aws_dms_replication_task - ListOfTables: - - aws_dms_replication_task - Parameters: [] + + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + (replication_task_settings -> 'Logging' ->> 'EnableLogging')::BOOL AS logging_enabled, + CASE + WHEN (replication_task_settings -> 'Logging' ->> 'EnableLogging')::BOOL AND l.capture_logging_enabled AND l.unload_logging_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (replication_task_settings -> 'Logging' ->> 'EnableLogging')::BOOL AND l.capture_logging_enabled AND l.unload_logging_enabled THEN title || ' source database logging enabled.' + ELSE title || ' source database logging disabled.' + END AS reason + FROM + aws_dms_replication_task AS t + LEFT JOIN replication_task_logging AS l ON l.arn = t.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: DMS replication tasks for the source database should have logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_docdb_cluster_backup_retention_period_7_days.yaml b/compliance/controls/aws/aws_docdb_cluster_backup_retention_period_7_days.yaml old mode 100755 new mode 100644 index b98bc9a8f..fa3b738a0 --- a/compliance/controls/aws/aws_docdb_cluster_backup_retention_period_7_days.yaml +++ b/compliance/controls/aws/aws_docdb_cluster_backup_retention_period_7_days.yaml @@ -1,25 +1,25 @@ +Description: This control checks whether an AWS DocumentDB cluster has a backup retention period greater than or equal to 7 days. The control fails if the backup retention period is less than 7 days. ID: aws_docdb_cluster_backup_retention_period_7_days -Title: "AWS DocumentDB clusters should have an adequate backup retention period" -Description: "This control checks whether an AWS DocumentDB cluster has a backup retention period greater than or equal to 7 days. The control fails if the backup retention period is less than 7 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when backup_retention_period >= 7 then 'ok' - else 'alarm' - end as status, - title || ' backup retention period is ' || backup_retention_period || ' day(s).' as reason - from - aws_docdb_cluster; - PrimaryTable: aws_docdb_cluster ListOfTables: - aws_docdb_cluster Parameters: [] + PrimaryTable: aws_docdb_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN backup_retention_period >= 7 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' backup retention period is ' || backup_retention_period || ' day(s).' AS reason + FROM + aws_docdb_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: AWS DocumentDB clusters should have an adequate backup retention period \ No newline at end of file diff --git a/compliance/controls/aws/aws_docdb_cluster_deletion_protection_enabled.yaml b/compliance/controls/aws/aws_docdb_cluster_deletion_protection_enabled.yaml old mode 100755 new mode 100644 index f2e3b49fa..bbf2addbb --- a/compliance/controls/aws/aws_docdb_cluster_deletion_protection_enabled.yaml +++ b/compliance/controls/aws/aws_docdb_cluster_deletion_protection_enabled.yaml @@ -1,14 +1,28 @@ +Description: Ensure DocumentDB clusters have deletion protection enabled. ID: aws_docdb_cluster_deletion_protection_enabled -Title: "DocumentDB clusters should have deletion protection enabled" -Description: "Ensure DocumentDB clusters have deletion protection enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when deletion_protection then 'ok'\n else 'alarm'\n end status,\n case\n when deletion_protection then title || ' deletion protection enabled.'\n else title || ' deletion protection disabled.'\n end reason\n \n \nfrom\n aws_docdb_cluster;" - PrimaryTable: aws_docdb_cluster ListOfTables: - aws_docdb_cluster Parameters: [] + PrimaryTable: aws_docdb_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN deletion_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN deletion_protection THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection disabled.' + END AS reason + FROM + aws_docdb_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: DocumentDB clusters should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_docdb_cluster_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_docdb_cluster_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index a71bb98e6..37e45af9e --- a/compliance/controls/aws/aws_docdb_cluster_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_docdb_cluster_encryption_at_rest_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an AWS DocumentDB cluster is encrypted at rest. The control fails if an AWS DocumentDB cluster isn't encrypted at rest. ID: aws_docdb_cluster_encryption_at_rest_enabled -Title: "AWS DocumentDB clusters should be encrypted at rest" -Description: "This control checks whether an AWS DocumentDB cluster is encrypted at rest. The control fails if an AWS DocumentDB cluster isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_docdb_cluster;" - PrimaryTable: aws_docdb_cluster ListOfTables: - aws_docdb_cluster Parameters: [] + PrimaryTable: aws_docdb_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_docdb_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: AWS DocumentDB clusters should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_docdb_cluster_instance_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_docdb_cluster_instance_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index b79a28664..739160822 --- a/compliance/controls/aws/aws_docdb_cluster_instance_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_docdb_cluster_instance_encryption_at_rest_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an DocumentDB instance is encrypted at rest. The control fails if an DocumentDB instance isn't encrypted at rest. ID: aws_docdb_cluster_instance_encryption_at_rest_enabled -Title: "DocumentDB instance should be encrypted at rest" -Description: "This control checks whether an DocumentDB instance is encrypted at rest. The control fails if an DocumentDB instance isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n db_instance_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_docdb_cluster_instance;" - PrimaryTable: aws_docdb_cluster_instance ListOfTables: - aws_docdb_cluster_instance Parameters: [] + PrimaryTable: aws_docdb_cluster_instance + QueryToExecute: | + SELECT + db_instance_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_docdb_cluster_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: DocumentDB instance should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_docdb_cluster_instance_logging_enabled.yaml b/compliance/controls/aws/aws_docdb_cluster_instance_logging_enabled.yaml old mode 100755 new mode 100644 index 8d8271a74..67de09195 --- a/compliance/controls/aws/aws_docdb_cluster_instance_logging_enabled.yaml +++ b/compliance/controls/aws/aws_docdb_cluster_instance_logging_enabled.yaml @@ -1,14 +1,33 @@ +Description: To help with logging and monitoring within your environment, ensure AWS DocumentDB instance logging is enabled. ID: aws_docdb_cluster_instance_logging_enabled -Title: "DocumentDB instance logging should be enabled" -Description: "To help with logging and monitoring within your environment, ensure AWS DocumentDB instance logging is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n db_instance_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n engine,\n case\n when engine like 'docdb' and enabled_cloudwatch_logs_exports ?& array ['error', 'slowquery'] then 'ok'\n else 'alarm'\n end as status,\n case\n when engine like 'docdb' and enabled_cloudwatch_logs_exports ?& array ['error', 'slowquery']\n then title || ' ' || engine || ' logging enabled.'\n else title || ' logging not enabled.'\n end as reason\n \n \nfrom\n aws_docdb_cluster_instance;" - PrimaryTable: aws_docdb_cluster_instance ListOfTables: - aws_docdb_cluster_instance Parameters: [] + PrimaryTable: aws_docdb_cluster_instance + QueryToExecute: | + SELECT + db_instance_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + engine, + CASE + WHEN engine LIKE 'docdb' + AND enabled_cloudwatch_logs_exports ?& ARRAY['error', 'slowquery'] + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine LIKE 'docdb' + AND enabled_cloudwatch_logs_exports ?& ARRAY['error', 'slowquery'] + THEN title || ' ' || engine || ' logging enabled.' + ELSE title || ' logging not enabled.' + END AS reason + FROM + aws_docdb_cluster_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: DocumentDB instance logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_drs_job_enabled.yaml b/compliance/controls/aws/aws_drs_job_enabled.yaml old mode 100755 new mode 100644 index b6c09be1b..8cc796eda --- a/compliance/controls/aws/aws_drs_job_enabled.yaml +++ b/compliance/controls/aws/aws_drs_job_enabled.yaml @@ -1,15 +1,43 @@ +Description: Ensure that DRS is enabled with jobs. This rule is non-compliant if DRS is not enabled with jobs for a particular region. ID: aws_drs_job_enabled -Title: "DRS jobs should be enabled" -Description: "Ensure that DRS is enabled with jobs. This rule is non-compliant if DRS is not enabled with jobs for a particular region." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with drs_job_count as (\n select\n count(*) as count,\n region,\n account_id,\n _ctx\n from\n aws_drs_job\n group by\n region,\n account_id,\n _ctx\n)\nselect\n 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource,\nr.og_account_id as og_account_id,\nr.og_resource_id as og_resource_id,\n case\n when drs_job_count.count = 0 or drs_job_count.count is null then 'alarm'\n else 'ok'\n end as status,\n case\n when drs_job_count.count = 0 or drs_job_count.count is null then 'DRS job not enabled for region ' || r.region || '.'\n else 'DRS job enabled for region ' || r.region || '.'\n end as reason\n \nfrom\n aws_region as r\n left join drs_job_count on r.region = drs_job_count.region;" - PrimaryTable: aws_drs_job ListOfTables: - aws_drs_job - aws_region Parameters: [] + PrimaryTable: aws_drs_job + QueryToExecute: | + WITH drs_job_count AS ( + SELECT + COUNT(*) AS count, + region, + account_id, + _ctx + FROM + aws_drs_job + GROUP BY + region, + account_id, + _ctx + ) + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN drs_job_count.count = 0 OR drs_job_count.count IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN drs_job_count.count = 0 OR drs_job_count.count IS NULL THEN 'DRS job not enabled for region ' || r.region || '.' + ELSE 'DRS job enabled for region ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN drs_job_count ON r.region = drs_job_count.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: DRS jobs should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_dynamodb_table_auto_scaling_enabled.yaml b/compliance/controls/aws/aws_dynamodb_table_auto_scaling_enabled.yaml old mode 100755 new mode 100644 index 3e08f2405..b9aa72ee4 --- a/compliance/controls/aws/aws_dynamodb_table_auto_scaling_enabled.yaml +++ b/compliance/controls/aws/aws_dynamodb_table_auto_scaling_enabled.yaml @@ -1,14 +1,50 @@ +Description: AWS DynamoDB auto scaling uses the AWS Application Auto Scaling service to adjust provisioned throughput capacity that automatically responds to actual traffic patterns. ID: aws_dynamodb_table_auto_scaling_enabled -Title: "DynamoDB table auto scaling should be enabled" -Description: "AWS DynamoDB auto scaling uses the AWS Application Auto Scaling service to adjust provisioned throughput capacity that automatically responds to actual traffic patterns." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with table_with_autocaling as (\n select\n t.resource_id as resource_id,\n count(t.resource_id) as count\n from\n aws_appautoscaling_target as t where service_namespace = 'dynamodb'\n group by t.resource_id\n)\nselect\n d.arn as resource,\n d.og_account_id as og_account_id,\n d.og_resource_id as og_resource_id,\n case\n when d.billing_mode = 'PAY_PER_REQUEST' then 'ok'\n when t.resource_id is null then 'alarm'\n when t.count < 2 then 'alarm'\n else 'ok'\n end as status,\n case\n when d.billing_mode = 'PAY_PER_REQUEST' then d.title || ' on-demand mode enabled.'\n when t.resource_id is null then d.title || ' autoscaling not enabled.'\n when t.count < 2 then d.title || ' auto scaling not enabled for both read and write capacity.'\n else d.title || ' autoscaling enabled for both read and write capacity.'\n end as reason\n \n , d.region, d.account_id\nfrom\n aws_dynamodb_table as d\n left join table_with_autocaling as t on concat('table/', d.name) = t.resource_id;\n" - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_appautoscaling_target - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + WITH table_with_autocaling AS ( + SELECT + t.resource_id AS resource_id, + COUNT(t.resource_id) AS count + FROM + aws_appautoscaling_target AS t + WHERE + service_namespace = 'dynamodb' + GROUP BY + t.resource_id + ) + SELECT + d.arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN d.billing_mode = 'PAY_PER_REQUEST' THEN 'ok' + WHEN t.resource_id IS NULL THEN 'alarm' + WHEN t.count < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.billing_mode = 'PAY_PER_REQUEST' THEN d.title || ' on-demand mode enabled.' + WHEN t.resource_id IS NULL THEN d.title || ' autoscaling not enabled.' + WHEN t.count < 2 THEN d.title || ' auto scaling not enabled for both read and write capacity.' + ELSE d.title || ' autoscaling enabled for both read and write capacity.' + END AS reason, + d.region, + d.account_id + FROM + aws_dynamodb_table AS d + LEFT JOIN + table_with_autocaling AS t + ON + CONCAT('table/', d.name) = t.resource_id Severity: low Tags: category: @@ -27,17 +63,16 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: - aws service: - AWS/DynamoDB -IntegrationType: - - aws_cloud_account +Title: DynamoDB table auto scaling should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_dynamodb_table_deletion_protection_enabled.yaml b/compliance/controls/aws/aws_dynamodb_table_deletion_protection_enabled.yaml old mode 100755 new mode 100644 index 5165457b7..008d0634f --- a/compliance/controls/aws/aws_dynamodb_table_deletion_protection_enabled.yaml +++ b/compliance/controls/aws/aws_dynamodb_table_deletion_protection_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an Amazon DynamoDB table has deletion protection enabled. The control fails if a DynamoDB table doesn't have deletion protection enabled. ID: aws_dynamodb_table_deletion_protection_enabled -Title: "DynamoDB table should have deletion protection enabled" -Description: "This control checks whether an Amazon DynamoDB table has deletion protection enabled. The control fails if a DynamoDB table doesn't have deletion protection enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when deletion_protection_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when deletion_protection_enabled then title || ' deletion protection enabled.'\n else title || ' deletion protection disabled.'\n end as reason\n \n \nfrom\n aws_dynamodb_table;" - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN deletion_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN deletion_protection_enabled THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection disabled.' + END AS reason + FROM + aws_dynamodb_table; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: DynamoDB table should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_dynamodb_table_encrypted_with_kms.yaml b/compliance/controls/aws/aws_dynamodb_table_encrypted_with_kms.yaml old mode 100755 new mode 100644 index ee951c8aa..3d547e990 --- a/compliance/controls/aws/aws_dynamodb_table_encrypted_with_kms.yaml +++ b/compliance/controls/aws/aws_dynamodb_table_encrypted_with_kms.yaml @@ -1,13 +1,30 @@ +Description: Ensure that encryption is enabled for your AWS DynamoDB tables. Because sensitive data can exist at rest in these tables, enable encryption at rest to help protect that data. ID: aws_dynamodb_table_encrypted_with_kms -Title: "DynamoDB table should be encrypted with AWS KMS" -Description: "Ensure that encryption is enabled for your AWS DynamoDB tables. Because sensitive data can exist at rest in these tables, enable encryption at rest to help protect that data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when sse_description is null then 'alarm'\n else 'ok'\n end as status,\n case\n when sse_description is null then title || ' not encrypted with KMS.'\n else title || ' encrypted with KMS.'\n end as reason\n \n , region, account_id\nfrom\n aws_dynamodb_table;\n" - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN sse_description IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sse_description IS NULL THEN title || ' not encrypted with KMS.' + ELSE title || ' encrypted with KMS.' + END AS reason, + region, + account_id + FROM + aws_dynamodb_table; Severity: high Tags: category: @@ -24,12 +41,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -40,5 +57,4 @@ Tags: - "true" service: - AWS/DynamoDB -IntegrationType: - - aws_cloud_account +Title: DynamoDB table should be encrypted with AWS KMS \ No newline at end of file diff --git a/compliance/controls/aws/aws_dynamodb_table_encryption_enabled.yaml b/compliance/controls/aws/aws_dynamodb_table_encryption_enabled.yaml old mode 100755 new mode 100644 index a08dd0e1f..7233366db --- a/compliance/controls/aws/aws_dynamodb_table_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_dynamodb_table_encryption_enabled.yaml @@ -1,13 +1,32 @@ +Description: Ensure that encryption is enabled for your AWS DynamoDB tables. Because sensitive data can exist at rest in these tables, enable encryption at rest to help protect that data. ID: aws_dynamodb_table_encryption_enabled -Title: "DynamoDB table should have encryption enabled" -Description: "Ensure that encryption is enabled for your AWS DynamoDB tables. Because sensitive data can exist at rest in these tables, enable encryption at rest to help protect that data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when sse_description is not null and sse_description ->> 'SSEType' = 'KMS' then 'ok'\n when sse_description is null then 'ok'\n else 'alarm'\n end as status,\n case\n when sse_description is not null and sse_description ->> 'SSEType' = 'KMS'\n then title || ' encrypted with AWS KMS.'\n when sse_description is null then title || ' encrypted with DynamoDB managed CMK.'\n else title || ' not encrypted with CMK.'\n end as reason\n \n , region, account_id\nfrom\n aws_dynamodb_table;\n" - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN sse_description IS NOT NULL AND sse_description ->> 'SSEType' = 'KMS' THEN 'ok' + WHEN sse_description IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sse_description IS NOT NULL AND sse_description ->> 'SSEType' = 'KMS' + THEN title || ' encrypted with AWS KMS.' + WHEN sse_description IS NULL THEN title || ' encrypted with DynamoDB managed CMK.' + ELSE title || ' not encrypted with CMK.' + END AS reason, + region, account_id + FROM + aws_dynamodb_table; Severity: high Tags: category: @@ -28,5 +47,4 @@ Tags: - aws service: - AWS/DynamoDB -IntegrationType: - - aws_cloud_account +Title: DynamoDB table should have encryption enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_dynamodb_table_in_backup_plan.yaml b/compliance/controls/aws/aws_dynamodb_table_in_backup_plan.yaml old mode 100755 new mode 100644 index 07f277af6..bcd2da0df --- a/compliance/controls/aws/aws_dynamodb_table_in_backup_plan.yaml +++ b/compliance/controls/aws/aws_dynamodb_table_in_backup_plan.yaml @@ -1,14 +1,63 @@ +Description: To help with data back-up processes, ensure your AWS DynamoDB tables are a part of an AWS Backup plan. ID: aws_dynamodb_table_in_backup_plan -Title: "DynamoDB tables should be in a backup plan" -Description: "To help with data back-up processes, ensure your AWS DynamoDB tables are a part of an AWS Backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with mapped_with_id as (\n select\n jsonb_agg(elems) as mapped_ids\n from\n aws_backup_selection,\n jsonb_array_elements(resources) as elems\n group by backup_plan_id\n),\nmapped_with_tags as (\n select\n jsonb_agg(elems ->> 'ConditionKey') as mapped_tags\n from\n aws_backup_selection,\n jsonb_array_elements(list_of_tags) as elems\n group by backup_plan_id\n),\nbacked_up_table as (\n select\n t.name\n from\n aws_dynamodb_table as t\n join mapped_with_id as m on m.mapped_ids ?| array[t.arn]\n union\n select\n t.name\n from\n aws_dynamodb_table as t\n join mapped_with_tags as m on m.mapped_tags ?| array(select jsonb_object_keys(tags))\n)\nselect\n t.arn as resource,\n t.og_account_id as og_account_id,\n t.og_resource_id as og_resource_id,\n case\n when b.name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when b.name is null then t.title || ' not in backup plan.'\n else t.title || ' in backup plan.'\n end as reason\n \n , t.region, t.account_id\nfrom\n aws_dynamodb_table as t\n left join backed_up_table as b on t.name = b.name;\n" - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_backup_selection - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + WITH mapped_with_id AS ( + SELECT + jsonb_agg(elems) AS mapped_ids + FROM + aws_backup_selection, + jsonb_array_elements(resources) AS elems + GROUP BY + backup_plan_id + ), + mapped_with_tags AS ( + SELECT + jsonb_agg(elems ->> 'ConditionKey') AS mapped_tags + FROM + aws_backup_selection, + jsonb_array_elements(list_of_tags) AS elems + GROUP BY + backup_plan_id + ), + backed_up_table AS ( + SELECT + t.name + FROM + aws_dynamodb_table AS t + JOIN mapped_with_id AS m ON m.mapped_ids ?| array[t.arn] + UNION + SELECT + t.name + FROM + aws_dynamodb_table AS t + JOIN mapped_with_tags AS m ON m.mapped_tags ?| array(SELECT jsonb_object_keys(tags)) + ) + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN b.name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.name IS NULL THEN t.title || ' not in backup plan.' + ELSE t.title || ' in backup plan.' + END AS reason, + t.region, + t.account_id + FROM + aws_dynamodb_table AS t + LEFT JOIN backed_up_table AS b ON t.name = b.name; Severity: medium Tags: category: @@ -27,12 +76,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -45,5 +94,4 @@ Tags: - AWS/DynamoDB soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: DynamoDB tables should be in a backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_dynamodb_table_point_in_time_recovery_enabled.yaml b/compliance/controls/aws/aws_dynamodb_table_point_in_time_recovery_enabled.yaml old mode 100755 new mode 100644 index d4239efe4..df60b6d11 --- a/compliance/controls/aws/aws_dynamodb_table_point_in_time_recovery_enabled.yaml +++ b/compliance/controls/aws/aws_dynamodb_table_point_in_time_recovery_enabled.yaml @@ -1,13 +1,30 @@ +Description: Enable this rule to check that information has been backed up. It also maintains the backups by ensuring that point-in-time recovery is enabled in AWS DynamoDB. ID: aws_dynamodb_table_point_in_time_recovery_enabled -Title: "DynamoDB table point-in-time recovery should be enabled" -Description: "Enable this rule to check that information has been backed up. It also maintains the backups by ensuring that point-in-time recovery is enabled in AWS DynamoDB." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when lower( point_in_time_recovery_description ->> 'PointInTimeRecoveryStatus' ) = 'disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower( point_in_time_recovery_description ->> 'PointInTimeRecoveryStatus' ) = 'disabled' then title || ' point-in-time recovery not enabled.'\n else title || ' point-in-time recovery enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_dynamodb_table;\n" - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN LOWER(point_in_time_recovery_description ->> 'PointInTimeRecoveryStatus') = 'disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(point_in_time_recovery_description ->> 'PointInTimeRecoveryStatus') = 'disabled' THEN title || ' point-in-time recovery not enabled.' + ELSE title || ' point-in-time recovery enabled.' + END AS reason, + region, + account_id + FROM + aws_dynamodb_table; Severity: high Tags: category: @@ -30,12 +47,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +65,4 @@ Tags: - AWS/DynamoDB soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: DynamoDB table point-in-time recovery should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_dynamodb_table_protected_by_backup_plan.yaml b/compliance/controls/aws/aws_dynamodb_table_protected_by_backup_plan.yaml old mode 100755 new mode 100644 index 07bcc95a6..1703204eb --- a/compliance/controls/aws/aws_dynamodb_table_protected_by_backup_plan.yaml +++ b/compliance/controls/aws/aws_dynamodb_table_protected_by_backup_plan.yaml @@ -1,14 +1,41 @@ +Description: Ensure that AWS DynamoDB tables are protected by a backup plan. The rule is non-compliant if the DynamoDB Table is not covered by a backup plan. ID: aws_dynamodb_table_protected_by_backup_plan -Title: "DynamoDB table should be protected by backup plan" -Description: "Ensure that AWS DynamoDB tables are protected by a backup plan. The rule is non-compliant if the DynamoDB Table is not covered by a backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with backup_protected_table as (\n select\n resource_arn as arn\n from\n aws_backup_protected_resource as b\n where\n resource_type = 'DynamoDB'\n)\nselect\n t.arn as resource,\n t.og_account_id as og_account_id,\n t.og_resource_id as og_resource_id,\n case\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is not null then t.title || ' is protected by backup plan.'\n else t.title || ' is not protected by backup plan.'\n end as reason\n \n , t.region, t.account_id\nfrom\n aws_dynamodb_table as t\n left join backup_protected_table as b on t.arn = b.arn;\n" - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_backup_protected_resource - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + WITH backup_protected_table AS ( + SELECT + resource_arn AS arn + FROM + aws_backup_protected_resource AS b + WHERE + resource_type = 'DynamoDB' + ) + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NOT NULL THEN t.title || ' is protected by backup plan.' + ELSE t.title || ' is not protected by backup plan.' + END AS reason, + t.region, + t.account_id + FROM + aws_dynamodb_table AS t + LEFT JOIN backup_protected_table AS b + ON t.arn = b.arn; Severity: high Tags: category: @@ -39,5 +66,4 @@ Tags: - AWS/DynamoDB soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: DynamoDB table should be protected by backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_ebs_attached_volume_delete_on_termination_enabled.yaml b/compliance/controls/aws/aws_ebs_attached_volume_delete_on_termination_enabled.yaml old mode 100755 new mode 100644 index f71455353..e84c83905 --- a/compliance/controls/aws/aws_ebs_attached_volume_delete_on_termination_enabled.yaml +++ b/compliance/controls/aws/aws_ebs_attached_volume_delete_on_termination_enabled.yaml @@ -1,13 +1,34 @@ +Description: This rule ensures that AWS Elastic Block Store volumes that are attached to AWS Elastic Compute Cloud (AWS EC2) instances are marked for deletion when an instance is terminated. ID: aws_ebs_attached_volume_delete_on_termination_enabled -Title: "Attached EBS volumes should have delete on termination enabled" -Description: "This rule ensures that AWS Elastic Block Store volumes that are attached to AWS Elastic Compute Cloud (AWS EC2) instances are marked for deletion when an instance is terminated." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when state != 'in-use' then 'skip'\n when attachment ->> 'DeleteOnTermination' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when state != 'in-use' then title || ' not attached to EC2 instance.'\n when attachment ->> 'DeleteOnTermination' = 'true' then title || ' attached to ' || (attachment ->> 'InstanceId') || ', delete on termination enabled.'\n else title || ' attached to ' || (attachment ->> 'InstanceId') || ', delete on termination disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ebs_volume\n left join jsonb_array_elements(attachments) as attachment on true;\n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN state != 'in-use' THEN 'skip' + WHEN attachment ->> 'DeleteOnTermination' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN state != 'in-use' THEN title || ' not attached to EC2 instance.' + WHEN attachment ->> 'DeleteOnTermination' = 'true' THEN title || ' attached to ' || (attachment ->> 'InstanceId') || ', delete on termination enabled.' + ELSE title || ' attached to ' || (attachment ->> 'InstanceId') || ', delete on termination disabled.' + END AS reason, + region, + account_id + FROM + aws_ebs_volume + LEFT JOIN + jsonb_array_elements(attachments) AS attachment ON true; Severity: medium Tags: audit_manager_control_tower: @@ -24,5 +45,4 @@ Tags: - aws service: - AWS/EBS -IntegrationType: - - aws_cloud_account +Title: Attached EBS volumes should have delete on termination enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ebs_attached_volume_encryption_enabled.yaml b/compliance/controls/aws/aws_ebs_attached_volume_encryption_enabled.yaml old mode 100755 new mode 100644 index 83b4494aa..ea6066f1e --- a/compliance/controls/aws/aws_ebs_attached_volume_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_ebs_attached_volume_encryption_enabled.yaml @@ -1,13 +1,32 @@ +Description: Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your AWS Elastic Block Store (AWS EBS) volumes. ID: aws_ebs_attached_volume_encryption_enabled -Title: "Attached EBS volumes should have encryption enabled" -Description: "Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your AWS Elastic Block Store (AWS EBS) volumes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when state != 'in-use' then 'skip'\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when state != 'in-use' then volume_id || ' not attached.'\n when encrypted then volume_id || ' encrypted.'\n else volume_id || ' not encrypted.'\n end as reason\n \n , region, account_id\nfrom\n aws_ebs_volume;\n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN state != 'in-use' THEN 'skip' + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN state != 'in-use' THEN volume_id || ' not attached.' + WHEN encrypted THEN volume_id || ' encrypted.' + ELSE volume_id || ' not encrypted.' + END AS reason, + region, + account_id + FROM + aws_ebs_volume; Severity: high Tags: audit_manager_control_tower: @@ -30,12 +49,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +67,4 @@ Tags: - AWS/EBS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Attached EBS volumes should have encryption enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ebs_snapshot_encryption_enabled.yaml b/compliance/controls/aws/aws_ebs_snapshot_encryption_enabled.yaml old mode 100755 new mode 100644 index 3c4523d1f..4eecd2039 --- a/compliance/controls/aws/aws_ebs_snapshot_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_ebs_snapshot_encryption_enabled.yaml @@ -1,14 +1,28 @@ +Description: Ensure that EBS snapshots are encrypted. This rule is non-compliant if the EBS snapshot is not encrypted. ID: aws_ebs_snapshot_encryption_enabled -Title: "EBS snapshots should be encrypted" -Description: "Ensure that EBS snapshots are encrypted. This rule is non-compliant if the EBS snapshot is not encrypted." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then title || ' encryption enabled.'\n else title || ' encryption disabled.'\n end as reason\n \n \nfrom\n aws_ebs_snapshot;" - PrimaryTable: aws_ebs_snapshot ListOfTables: - aws_ebs_snapshot Parameters: [] + PrimaryTable: aws_ebs_snapshot + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN title || ' encryption enabled.' + ELSE title || ' encryption disabled.' + END AS reason + FROM + aws_ebs_snapshot; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EBS snapshots should be encrypted \ No newline at end of file diff --git a/compliance/controls/aws/aws_ebs_snapshot_not_publicly_restorable.yaml b/compliance/controls/aws/aws_ebs_snapshot_not_publicly_restorable.yaml old mode 100755 new mode 100644 index 24b5afb8b..45b78b5f4 --- a/compliance/controls/aws/aws_ebs_snapshot_not_publicly_restorable.yaml +++ b/compliance/controls/aws/aws_ebs_snapshot_not_publicly_restorable.yaml @@ -1,13 +1,30 @@ +Description: '"Manage access to the AWS Cloud by ensuring EBS snapshots are not publicly restorable.' ID: aws_ebs_snapshot_not_publicly_restorable -Title: "EBS snapshots should not be publicly restorable" -Description: "\"Manage access to the AWS Cloud by ensuring EBS snapshots are not publicly restorable." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':snapshot/' || snapshot_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when create_volume_permissions @> '[{\"Group\": \"all\", \"UserId\": null}]' then 'alarm'\n else 'ok'\n end as status,\n case\n when create_volume_permissions @> '[{\"Group\": \"all\", \"UserId\": null}]' then title || ' is publicly restorable.'\n else title || ' is not publicly restorable.'\n end as reason\n \n , region, account_id\nfrom\n aws_ebs_snapshot;\n" - PrimaryTable: aws_ebs_snapshot ListOfTables: - aws_ebs_snapshot Parameters: [] + PrimaryTable: aws_ebs_snapshot + QueryToExecute: | + SELECT + 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':snapshot/' || snapshot_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_volume_permissions @> '[{"Group": "all", "UserId": null}]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN create_volume_permissions @> '[{"Group": "all", "UserId": null}]' THEN title || ' is publicly restorable.' + ELSE title || ' is not publicly restorable.' + END AS reason, + region, + account_id + FROM + aws_ebs_snapshot; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/EBS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EBS snapshots should not be publicly restorable \ No newline at end of file diff --git a/compliance/controls/aws/aws_ebs_volume_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_ebs_volume_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 3dd9f2f36..86855ab31 --- a/compliance/controls/aws/aws_ebs_volume_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_ebs_volume_encryption_at_rest_enabled.yaml @@ -1,13 +1,30 @@ +Description: Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your AWS Elastic Block Store (AWS EBS) volumes. ID: aws_ebs_volume_encryption_at_rest_enabled -Title: "EBS volume encryption at rest should be enabled" -Description: "Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your AWS Elastic Block Store (AWS EBS) volumes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then volume_id || ' encrypted.'\n else volume_id || ' not encrypted.'\n end as reason\n \n , region, account_id\nfrom\n aws_ebs_volume;\n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN volume_id || ' encrypted.' + ELSE volume_id || ' not encrypted.' + END AS reason, + region, + account_id + FROM + aws_ebs_volume; Severity: high Tags: category: @@ -26,5 +43,4 @@ Tags: - "true" service: - AWS/EBS -IntegrationType: - - aws_cloud_account +Title: EBS volume encryption at rest should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ebs_volume_in_backup_plan.yaml b/compliance/controls/aws/aws_ebs_volume_in_backup_plan.yaml old mode 100755 new mode 100644 index fe0fb8cd6..8ae400908 --- a/compliance/controls/aws/aws_ebs_volume_in_backup_plan.yaml +++ b/compliance/controls/aws/aws_ebs_volume_in_backup_plan.yaml @@ -1,14 +1,72 @@ +Description: To help with data back-up processes, ensure your AWS Elastic Block Store (AWS EBS) volumes are a part of an AWS Backup plan. ID: aws_ebs_volume_in_backup_plan -Title: "EBS volumes should be in a backup plan" -Description: "To help with data back-up processes, ensure your AWS Elastic Block Store (AWS EBS) volumes are a part of an AWS Backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with mapped_with_id as (\n select\n jsonb_agg(elems) as mapped_ids\n from\n aws_backup_selection,\n jsonb_array_elements(resources) as elems\n group by backup_plan_id\n),\nmapped_with_tags as (\n select\n jsonb_agg(elems ->> 'ConditionKey') as mapped_tags\n from\n aws_backup_selection,\n jsonb_array_elements(list_of_tags) as elems\n group by backup_plan_id\n),\nbacked_up_volume as (\n select\n v.volume_id\n from\n aws_ebs_volume as v\n join mapped_with_id as t on t.mapped_ids ?| array[v.arn]\n union\n select\n v.volume_id\n from\n aws_ebs_volume as v\n join mapped_with_tags as t on t.mapped_tags ?| array(select jsonb_object_keys(tags))\n)\nselect\n v.arn as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when b.volume_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when b.volume_id is null then v.title || ' not in backup plan.'\n else v.title || ' in backup plan.'\n end as reason\n \n , v.region, v.account_id\nfrom\n aws_ebs_volume as v\n left join backed_up_volume as b on v.volume_id = b.volume_id;\n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_backup_selection - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + WITH mapped_with_id AS ( + SELECT + jsonb_agg(elems) AS mapped_ids + FROM + aws_backup_selection, + jsonb_array_elements(resources) AS elems + GROUP BY + backup_plan_id + ), + mapped_with_tags AS ( + SELECT + jsonb_agg(elems ->> 'ConditionKey') AS mapped_tags + FROM + aws_backup_selection, + jsonb_array_elements(list_of_tags) AS elems + GROUP BY + backup_plan_id + ), + backed_up_volume AS ( + SELECT + v.volume_id + FROM + aws_ebs_volume AS v + JOIN + mapped_with_id AS t + ON + t.mapped_ids ?| array[v.arn] + UNION + SELECT + v.volume_id + FROM + aws_ebs_volume AS v + JOIN + mapped_with_tags AS t + ON + t.mapped_tags ?| array(SELECT jsonb_object_keys(tags)) + ) + SELECT + v.arn AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN b.volume_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.volume_id IS NULL THEN v.title || ' not in backup plan.' + ELSE v.title || ' in backup plan.' + END AS reason, + v.region, + v.account_id + FROM + aws_ebs_volume AS v + LEFT JOIN + backed_up_volume AS b + ON + v.volume_id = b.volume_id Severity: high Tags: category: @@ -27,12 +85,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -45,5 +103,4 @@ Tags: - AWS/EBS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EBS volumes should be in a backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_ebs_volume_protected_by_backup_plan.yaml b/compliance/controls/aws/aws_ebs_volume_protected_by_backup_plan.yaml old mode 100755 new mode 100644 index 4b947d2bf..7620cab9c --- a/compliance/controls/aws/aws_ebs_volume_protected_by_backup_plan.yaml +++ b/compliance/controls/aws/aws_ebs_volume_protected_by_backup_plan.yaml @@ -1,14 +1,40 @@ +Description: Ensure that AWS Elastic Block Store (AWS EBS) volumes are protected by a backup plan. The rule is non-compliant if the AWS EBS volume is not covered by a backup plan. ID: aws_ebs_volume_protected_by_backup_plan -Title: "EBS volumes should be protected by a backup plan" -Description: "Ensure that AWS Elastic Block Store (AWS EBS) volumes are protected by a backup plan. The rule is non-compliant if the AWS EBS volume is not covered by a backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with backup_protected_volume as (\n select\n resource_arn as arn\n from\n aws_backup_protected_resource as b\n where\n resource_type = 'EBS'\n)\nselect\n v.arn as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is not null then v.title || ' is protected by backup plan.'\n else v.title || ' is not protected by backup plan.'\n end as reason\n \n , v.region, v.account_id\nfrom\n aws_ebs_volume as v\n left join backup_protected_volume as b on v.arn = b.arn;\n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_backup_protected_resource - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + WITH backup_protected_volume AS ( + SELECT + resource_arn AS arn + FROM + aws_backup_protected_resource AS b + WHERE + resource_type = 'EBS' + ) + SELECT + v.arn AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NOT NULL THEN v.title || ' is protected by backup plan.' + ELSE v.title || ' is not protected by backup plan.' + END AS reason, + v.region, + v.account_id + FROM + aws_ebs_volume AS v + LEFT JOIN backup_protected_volume AS b ON v.arn = b.arn; Severity: high Tags: category: @@ -39,5 +65,4 @@ Tags: - AWS/EBS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EBS volumes should be protected by a backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_ebs_volume_snapshot_exists.yaml b/compliance/controls/aws/aws_ebs_volume_snapshot_exists.yaml old mode 100755 new mode 100644 index 06e7afac1..cbd1064ae --- a/compliance/controls/aws/aws_ebs_volume_snapshot_exists.yaml +++ b/compliance/controls/aws/aws_ebs_volume_snapshot_exists.yaml @@ -1,39 +1,39 @@ +Description: Ensure that EBS volume snapshots exist. This rule is non-compliant if the EBS volume does not have any snapshot. ID: aws_ebs_volume_snapshot_exists -Title: "EBS volume snapshots should exist" -Description: "Ensure that EBS volume snapshots exist. This rule is non-compliant if the EBS volume does not have any snapshot." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ebs_snapshot + - aws_ebs_volume + Parameters: [] + PrimaryTable: aws_ebs_volume QueryToExecute: | - with volume_with_snapshots as ( - select + WITH volume_with_snapshots AS ( + SELECT volume_id, - count(*) as snap_count - from + COUNT(*) AS snap_count + FROM aws_ebs_snapshot - group by + GROUP BY volume_id ) - select - v.arn as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when s.volume_id is not null then 'ok' - else 'alarm' - end as status, - case - when s.volume_id is not null then v.title || ' has ' || s.snap_count || ' snapshot(s).' - else v.title || ' does not have snapshot.' - end as reason - from - aws_ebs_volume as v - left join volume_with_snapshots as s on s.volume_id = v.volume_id; - PrimaryTable: aws_ebs_volume - ListOfTables: - - aws_ebs_snapshot - - aws_ebs_volume - Parameters: [] + SELECT + v.arn AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN s.volume_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.volume_id IS NOT NULL THEN v.title || ' has ' || s.snap_count || ' snapshot(s).' + ELSE v.title || ' does not have snapshot.' + END AS reason + FROM + aws_ebs_volume AS v + LEFT JOIN volume_with_snapshots AS s ON s.volume_id = v.volume_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EBS volume snapshots should exist \ No newline at end of file diff --git a/compliance/controls/aws/aws_ebs_volume_unused.yaml b/compliance/controls/aws/aws_ebs_volume_unused.yaml old mode 100755 new mode 100644 index b48f7f81c..a8d69afe2 --- a/compliance/controls/aws/aws_ebs_volume_unused.yaml +++ b/compliance/controls/aws/aws_ebs_volume_unused.yaml @@ -1,13 +1,30 @@ +Description: Checks if EBS volumes are attached to EC2 instances. ID: aws_ebs_volume_unused -Title: "EBS volumes should be attached to EC2 instances" -Description: "Checks if EBS volumes are attached to EC2 instances." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when state = 'in-use' then 'ok'\n else 'alarm'\n end as status,\n case\n when state = 'in-use' then title || ' attached to EC2 instance.'\n else title || ' not attached to EC2 instance.'\n end as reason\n \n , region, account_id\nfrom\n aws_ebs_volume;\n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN state = 'in-use' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN state = 'in-use' THEN title || ' attached to EC2 instance.' + ELSE title || ' not attached to EC2 instance.' + END AS reason, + region, + account_id + FROM + aws_ebs_volume; Severity: low Tags: category: @@ -24,10 +41,10 @@ Tags: - "true" gxp_21_cfr_part_11: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -36,5 +53,4 @@ Tags: - Optimization service: - AWS/EBS -IntegrationType: - - aws_cloud_account +Title: EBS volumes should be attached to EC2 instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_ami_ebs_encryption_enabled.yaml b/compliance/controls/aws/aws_ec2_ami_ebs_encryption_enabled.yaml old mode 100755 new mode 100644 index e41cb45ec..757deea4d --- a/compliance/controls/aws/aws_ec2_ami_ebs_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_ec2_ami_ebs_encryption_enabled.yaml @@ -1,46 +1,47 @@ +Description: Amazon Machine Images should utilize EBS Encrypted snapshots. ID: aws_ec2_ami_ebs_encryption_enabled -Title: "Ensure Images (AMI's) are encrypted" -Description: "Amazon Machine Images should utilize EBS Encrypted snapshots." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with encryption_status as ( - select - image_id as resource, + ListOfTables: + - aws_ec2_ami + Parameters: [] + PrimaryTable: aws_ec2_ami + QueryToExecute: | + WITH encryption_status AS ( + SELECT + image_id AS resource, region, account_id, tags, _ctx, - bool_and(coalesce((mapping -> 'Ebs' ->> 'Encrypted')::text = 'true', false)) as all_encrypted - from + BOOL_AND(COALESCE((mapping -> 'Ebs' ->> 'Encrypted')::text = 'true', FALSE)) AS all_encrypted + FROM aws_ec2_ami - cross join jsonb_array_elements(block_device_mappings) as mapping - group by + CROSS JOIN + jsonb_array_elements(block_device_mappings) AS mapping + GROUP BY image_id, region, account_id, tags, _ctx ) - select + SELECT resource, - e.account_id as og_account_id, - e.resource as og_resource_id, - case - when all_encrypted then 'ok' - else 'alarm' - end as status, - case - when all_encrypted then resource || ' all EBS volumes are encrypted.' - else resource || ' all EBS volumes are not encrypted.' - end as reason - from + e.account_id AS og_account_id, + e.resource AS og_resource_id, + CASE + WHEN all_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN all_encrypted THEN resource || ' all EBS volumes are encrypted.' + ELSE resource || ' all EBS volumes are not encrypted.' + END AS reason + FROM encryption_status e; - PrimaryTable: aws_ec2_ami - ListOfTables: - - aws_ec2_ami - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure Images (AMI's) are encrypted \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_ami_not_older_than_90_days.yaml b/compliance/controls/aws/aws_ec2_ami_not_older_than_90_days.yaml old mode 100755 new mode 100644 index 5082898a6..82ba880ec --- a/compliance/controls/aws/aws_ec2_ami_not_older_than_90_days.yaml +++ b/compliance/controls/aws/aws_ec2_ami_not_older_than_90_days.yaml @@ -1,14 +1,25 @@ +Description: Ensure that your AMIs are not older than 90 days. ID: aws_ec2_ami_not_older_than_90_days -Title: "Ensure Images (AMI) are not older than 90 days" -Description: "Ensure that your AMIs are not older than 90 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n image_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when creation_date >= (current_date - interval '90 days') then 'ok'\n else 'alarm'\n end as status,\n title || ' created ' || to_char(creation_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - creation_date) || ' days).' as reason\n \n \nfrom\n aws_ec2_ami;" - PrimaryTable: aws_ec2_ami ListOfTables: - aws_ec2_ami Parameters: [] + PrimaryTable: aws_ec2_ami + QueryToExecute: | + SELECT + image_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN creation_date >= (current_date - INTERVAL '90 days') THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' created ' || TO_CHAR(creation_date, 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM current_timestamp - creation_date) || ' days).' AS reason + FROM + aws_ec2_ami; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure Images (AMI) are not older than 90 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_ami_restrict_public_access.yaml b/compliance/controls/aws/aws_ec2_ami_restrict_public_access.yaml old mode 100755 new mode 100644 index c3dd89ff9..0a9392076 --- a/compliance/controls/aws/aws_ec2_ami_restrict_public_access.yaml +++ b/compliance/controls/aws/aws_ec2_ami_restrict_public_access.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether EC2 AMIs are set as private or not. The control fails if the EC2 AMIs are set as public. ID: aws_ec2_ami_restrict_public_access -Title: "EC2 AMIs should restrict public access" -Description: "This control checks whether EC2 AMIs are set as private or not. The control fails if the EC2 AMIs are set as public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':image/' || image_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when public then 'alarm'\n else 'ok'\n end status,\n case\n when public then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end reason\n \n \nfrom\n aws_ec2_ami;" - PrimaryTable: aws_ec2_ami ListOfTables: - aws_ec2_ami Parameters: [] + PrimaryTable: aws_ec2_ami + QueryToExecute: | + SELECT + 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':image/' || image_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN public THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_ec2_ami; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 AMIs should restrict public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_classic_lb_connection_draining_enabled.yaml b/compliance/controls/aws/aws_ec2_classic_lb_connection_draining_enabled.yaml old mode 100755 new mode 100644 index 9beda52d8..8e8591feb --- a/compliance/controls/aws/aws_ec2_classic_lb_connection_draining_enabled.yaml +++ b/compliance/controls/aws/aws_ec2_classic_lb_connection_draining_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether Classic Load Balancers have connection draining enabled. ID: aws_ec2_classic_lb_connection_draining_enabled -Title: "Classic Load Balancers should have connection draining enabled" -Description: "This control checks whether Classic Load Balancers have connection draining enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when connection_draining_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when connection_draining_enabled then title || ' connection draining enabled.'\n else title || ' connection draining disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_classic_load_balancer;\n" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN connection_draining_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN connection_draining_enabled THEN title || ' connection draining enabled.' + ELSE title || ' connection draining disabled.' + END AS reason, + region, + account_id + FROM + aws_ec2_classic_load_balancer; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/ELB -IntegrationType: - - aws_cloud_account +Title: Classic Load Balancers should have connection draining enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_client_vpn_endpoint_client_connection_logging_enabled.yaml b/compliance/controls/aws/aws_ec2_client_vpn_endpoint_client_connection_logging_enabled.yaml old mode 100755 new mode 100644 index baf864003..4f5275046 --- a/compliance/controls/aws/aws_ec2_client_vpn_endpoint_client_connection_logging_enabled.yaml +++ b/compliance/controls/aws/aws_ec2_client_vpn_endpoint_client_connection_logging_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an AWS Client VPN endpoint has client connection logging enabled. The control fails if the endpoint doesn't have client connection logging enabled. ID: aws_ec2_client_vpn_endpoint_client_connection_logging_enabled -Title: "EC2 Client VPN endpoints should have client connection logging enabled" -Description: "This control checks whether an AWS Client VPN endpoint has client connection logging enabled. The control fails if the endpoint doesn't have client connection logging enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n client_vpn_endpoint_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when (connection_log_options ->> 'Enabled')::bool then 'ok'\n else 'alarm'\n end as status,\n case\n when (connection_log_options ->> 'Enabled')::bool then title || ' client connection logging enabled.'\n else title || ' client connection logging disabled.'\n end as reason\n \n \nfrom\n aws_ec2_client_vpn_endpoint;" - PrimaryTable: aws_ec2_client_vpn_endpoint ListOfTables: - aws_ec2_client_vpn_endpoint Parameters: [] + PrimaryTable: aws_ec2_client_vpn_endpoint + QueryToExecute: | + SELECT + client_vpn_endpoint_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (connection_log_options ->> 'Enabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (connection_log_options ->> 'Enabled')::bool THEN title || ' client connection logging enabled.' + ELSE title || ' client connection logging disabled.' + END AS reason + FROM + aws_ec2_client_vpn_endpoint; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 Client VPN endpoints should have client connection logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_ebs_default_encryption_enabled.yaml b/compliance/controls/aws/aws_ec2_ebs_default_encryption_enabled.yaml old mode 100755 new mode 100644 index 0e98db681..27f14044d --- a/compliance/controls/aws/aws_ec2_ebs_default_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_ec2_ebs_default_encryption_enabled.yaml @@ -1,28 +1,30 @@ +Description: To help protect data at rest, ensure that encryption is enabled for your AWS Elastic Block Store (AWS EBS) volumes. ID: aws_ec2_ebs_default_encryption_enabled -Title: "EBS default encryption should be enabled" -Description: "To help protect data at rest, ensure that encryption is enabled for your AWS Elastic Block Store (AWS EBS) volumes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || partition || '::' || region || ':' || account_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not default_ebs_encryption_enabled then 'alarm' - else 'ok' - end as status, - case - when not default_ebs_encryption_enabled then region || ' default EBS encryption disabled.' - else region || ' default EBS encryption enabled.' - end as reason - , region, account_id - from - aws_ec2_regional_settings; - PrimaryTable: aws_ec2_regional_settings ListOfTables: - aws_ec2_regional_settings Parameters: [] + PrimaryTable: aws_ec2_regional_settings + QueryToExecute: | + SELECT + 'arn:' || partition || '::' || region || ':' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT default_ebs_encryption_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT default_ebs_encryption_enabled THEN region || ' default EBS encryption disabled.' + ELSE region || ' default EBS encryption enabled.' + END AS reason, + region, + account_id + FROM + aws_ec2_regional_settings; Severity: high Tags: category: @@ -41,12 +43,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -57,5 +59,4 @@ Tags: - AWS/EC2 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EBS default encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_attached_ebs_volume_delete_on_termination_enabled.yaml b/compliance/controls/aws/aws_ec2_instance_attached_ebs_volume_delete_on_termination_enabled.yaml old mode 100755 new mode 100644 index 8df06eb68..4b11bb401 --- a/compliance/controls/aws/aws_ec2_instance_attached_ebs_volume_delete_on_termination_enabled.yaml +++ b/compliance/controls/aws/aws_ec2_instance_attached_ebs_volume_delete_on_termination_enabled.yaml @@ -1,41 +1,42 @@ +Description: This rule ensures that Amazon Elastic Block Store volumes that are attached to Amazon Elastic Compute Cloud (Amazon EC2) instances are marked for deletion when an instance is terminated. If an Amazon EBS volume isn't deleted when the instance that it's attached to is terminated, it may violate the concept of least functionality. ID: aws_ec2_instance_attached_ebs_volume_delete_on_termination_enabled -Title: "Ensure EBS volumes attached to an EC2 instance is marked for deletion upon instance termination" -Description: "This rule ensures that Amazon Elastic Block Store volumes that are attached to Amazon Elastic Compute Cloud (Amazon EC2) instances are marked for deletion when an instance is terminated. If an Amazon EBS volume isn't deleted when the instance that it's attached to is terminated, it may violate the concept of least functionality." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ebs_volume_with_delete_on_termination_enabled as ( - select - count(*) as count, + ListOfTables: + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH ebs_volume_with_delete_on_termination_enabled AS ( + SELECT + COUNT(*) AS count, arn - from + FROM aws_ec2_instance, - jsonb_array_elements(block_device_mappings) as p - where + jsonb_array_elements(block_device_mappings) AS p + WHERE p -> 'Ebs' ->> 'DeleteOnTermination' = 'false' - group by + GROUP BY arn ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when e.count > 0 then 'alarm' - else 'ok' - end as status, - case - when e.count > 0 then ' EBS volume(s) attached to ' || title || ' has delete on termination disabled.' - else ' EBS volume(s) attached to ' || title || ' has delete on termination enabled.' - end as reason - from - aws_ec2_instance as i - left join ebs_volume_with_delete_on_termination_enabled as e on e.arn = i.arn; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - Parameters: [] + + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN e.count > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN e.count > 0 THEN ' EBS volume(s) attached to ' || title || ' has delete on termination disabled.' + ELSE ' EBS volume(s) attached to ' || title || ' has delete on termination enabled.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN ebs_volume_with_delete_on_termination_enabled AS e ON e.arn = i.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure EBS volumes attached to an EC2 instance is marked for deletion upon instance termination \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_detailed_monitoring_enabled.yaml b/compliance/controls/aws/aws_ec2_instance_detailed_monitoring_enabled.yaml old mode 100755 new mode 100644 index 85999df1a..2034252b9 --- a/compliance/controls/aws/aws_ec2_instance_detailed_monitoring_enabled.yaml +++ b/compliance/controls/aws/aws_ec2_instance_detailed_monitoring_enabled.yaml @@ -1,13 +1,30 @@ +Description: Enable this rule to help improve AWS Elastic Compute Cloud (AWS EC2) instance monitoring on the AWS EC2 console, which displays monitoring graphs with a 1-minute period for the instance. ID: aws_ec2_instance_detailed_monitoring_enabled -Title: "EC2 instance detailed monitoring should be enabled" -Description: "Enable this rule to help improve AWS Elastic Compute Cloud (AWS EC2) instance monitoring on the AWS EC2 console, which displays monitoring graphs with a 1-minute period for the instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when monitoring_state = 'enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when monitoring_state = 'enabled' then instance_id || ' detailed monitoring enabled.'\n else instance_id || ' detailed monitoring disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_instance;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN monitoring_state = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN monitoring_state = 'enabled' THEN instance_id || ' detailed monitoring enabled.' + ELSE instance_id || ' detailed monitoring disabled.' + END AS reason, + region, + account_id + FROM + aws_ec2_instance; Severity: low Tags: category: @@ -18,10 +35,10 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -30,5 +47,4 @@ Tags: - AWS/EC2 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EC2 instance detailed monitoring should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_ebs_optimized.yaml b/compliance/controls/aws/aws_ec2_instance_ebs_optimized.yaml old mode 100755 new mode 100644 index 3c9e17651..28e0f4729 --- a/compliance/controls/aws/aws_ec2_instance_ebs_optimized.yaml +++ b/compliance/controls/aws/aws_ec2_instance_ebs_optimized.yaml @@ -1,13 +1,30 @@ +Description: An optimized instance in AWS Elastic Block Store (AWS EBS) provides additional, dedicated capacity for AWS EBS I/O operations. ID: aws_ec2_instance_ebs_optimized -Title: "EC2 instance should have EBS optimization enabled" -Description: "An optimized instance in AWS Elastic Block Store (AWS EBS) provides additional, dedicated capacity for AWS EBS I/O operations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when ebs_optimized then 'ok'\n else 'alarm'\n end as status,\n case\n when ebs_optimized then title || ' EBS optimization enabled.'\n else title || ' EBS optimization disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_instance;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ebs_optimized THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ebs_optimized THEN title || ' EBS optimization enabled.' + ELSE title || ' EBS optimization disabled.' + END AS reason, + region, + account_id + FROM + aws_ec2_instance; Severity: medium Tags: audit_manager_control_tower: @@ -30,10 +47,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -44,5 +61,4 @@ Tags: - AWS/EC2 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EC2 instance should have EBS optimization enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_iam_profile_attached.yaml b/compliance/controls/aws/aws_ec2_instance_iam_profile_attached.yaml old mode 100755 new mode 100644 index 0b7fd2bbc..a67f6610e --- a/compliance/controls/aws/aws_ec2_instance_iam_profile_attached.yaml +++ b/compliance/controls/aws/aws_ec2_instance_iam_profile_attached.yaml @@ -1,13 +1,30 @@ +Description: Ensure that an AWS Elastic Compute Cloud (AWS EC2) instance has an Identity and Access Management (IAM) profile attached to it. This rule is non-compliant if no IAM profile is attached to the AWS EC2 instance. ID: aws_ec2_instance_iam_profile_attached -Title: "EC2 instances should have IAM profile attached" -Description: "Ensure that an AWS Elastic Compute Cloud (AWS EC2) instance has an Identity and Access Management (IAM) profile attached to it. This rule is non-compliant if no IAM profile is attached to the AWS EC2 instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when iam_instance_profile_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when iam_instance_profile_id is not null then title || ' IAM profile attached.'\n else title || ' IAM profile not attached.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_instance;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN iam_instance_profile_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN iam_instance_profile_id IS NOT NULL THEN title || ' IAM profile attached.' + ELSE title || ' IAM profile not attached.' + END AS reason, + region, + account_id + FROM + aws_ec2_instance; Severity: medium Tags: category: @@ -20,15 +37,14 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: EC2 instances should have IAM profile attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_in_vpc.yaml b/compliance/controls/aws/aws_ec2_instance_in_vpc.yaml old mode 100755 new mode 100644 index c428b54d3..02d5fd61b --- a/compliance/controls/aws/aws_ec2_instance_in_vpc.yaml +++ b/compliance/controls/aws/aws_ec2_instance_in_vpc.yaml @@ -1,13 +1,30 @@ +Description: Deploy AWS Elastic Compute Cloud (AWS EC2) instances within an AWS Virtual Private Cloud (AWS VPC) to enable secure communication between an instance and other services within the amazon VPC, without requiring an internet gateway, NAT device, or VPN connection. ID: aws_ec2_instance_in_vpc -Title: "EC2 instances should be in a VPC" -Description: "Deploy AWS Elastic Compute Cloud (AWS EC2) instances within an AWS Virtual Private Cloud (AWS VPC) to enable secure communication between an instance and other services within the amazon VPC, without requiring an internet gateway, NAT device, or VPN connection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when vpc_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when vpc_id is null then title || ' not in VPC.'\n else title || ' in VPC.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_instance;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vpc_id IS NULL THEN title || ' not in VPC.' + ELSE title || ' in VPC.' + END AS reason, + region, + account_id + FROM + aws_ec2_instance; Severity: medium Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +65,4 @@ Tags: - AWS/EC2 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EC2 instances should be in a VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_amazon_key_pair.yaml b/compliance/controls/aws/aws_ec2_instance_no_amazon_key_pair.yaml old mode 100755 new mode 100644 index 925589fd3..a7f3927f9 --- a/compliance/controls/aws/aws_ec2_instance_no_amazon_key_pair.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_amazon_key_pair.yaml @@ -1,13 +1,32 @@ +Description: This control checks whether running EC2 instances are using key pairs. The control fails if a running EC2 instance uses a key pair. ID: aws_ec2_instance_no_amazon_key_pair -Title: "EC2 instances should not use key pairs in running state" -Description: "This control checks whether running EC2 instances are using key pairs. The control fails if a running EC2 instance uses a key pair." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when instance_state <> 'running' then 'skip'\n when key_name is null then 'ok'\n else 'alarm'\n end as status,\n case\n when instance_state <> 'running' then title || ' is in ' || instance_state || ' state.'\n when key_name is null then title || ' not launched using amazon key pairs.'\n else title || ' launched using amazon key pairs.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_instance;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN instance_state <> 'running' THEN 'skip' + WHEN key_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN instance_state <> 'running' THEN title || ' is in ' || instance_state || ' state.' + WHEN key_name IS NULL THEN title || ' not launched using amazon key pairs.' + ELSE title || ' launched using amazon key pairs.' + END AS reason, + region, + account_id + FROM + aws_ec2_instance; Severity: low Tags: category: @@ -18,5 +37,4 @@ Tags: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: EC2 instances should not use key pairs in running state \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_passrole_and_lambda_invoke_function_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_passrole_and_lambda_invoke_function_access.yaml old mode 100755 new mode 100644 index 54efc6a24..37ec5b2a1 --- a/compliance/controls/aws/aws_ec2_instance_no_iam_passrole_and_lambda_invoke_function_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_passrole_and_lambda_invoke_function_access.yaml @@ -1,15 +1,55 @@ +Description: This control ensures that EC2 instance IAM role does not allow pass role and lambda invoke function access. ID: aws_ec2_instance_no_iam_passrole_and_lambda_invoke_function_access -Title: "EC2 instance IAM should not allow pass role and lambda invoke function access." -Description: "This control ensures that EC2 instance IAM role does not allow pass role and lambda invoke function access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with iam_roles as (\n select\n r.arn as role_arn,\n i.arn as intance_arn\n from\n aws_iam_role as r,\n jsonb_array_elements_text(instance_profile_arns) as p\n left join aws_ec2_instance as i on p = i.iam_instance_profile_arn\n where\n i.arn is not null\n), iam_role_with_permission as (\n select\n arn\n from\n aws_iam_role,\n jsonb_array_elements(assume_role_policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n arn in (select role_arn from iam_roles)\n and s ->> 'Effect' = 'Allow'\n and service = 'ec2.amazonaws.com'\n and action in ( 'iam:passrole','lambda:createfunction', 'lambda:invokefunction', '*:*')\n)\nselect\n i.arn as resource,\n i.og_account_id as og_account_id,\n i.og_resource_id as og_resource_id,\n case\n when p.arn is null then 'ok'\n else 'alarm'\n end status,\n case\n when p.arn is null then title || ' has no IAM pass role and lambda invoke function access.'\n else title || ' has IAM pass role and lambda invoke function access.'\n end as reason\n \n \nfrom\n aws_ec2_instance as i\n left join iam_roles as r on r.intance_arn = i.arn\n left join iam_role_with_permission as p on p.arn = r.role_arn;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_iam_role - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ('iam:passrole', 'lambda:createfunction', 'lambda:invokefunction', '*:*') + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM pass role and lambda invoke function access.' + ELSE title || ' has IAM pass role and lambda invoke function access.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.intance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM should not allow pass role and lambda invoke function access. \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_attached_with_credentials_exposure_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_attached_with_credentials_exposure_access.yaml old mode 100755 new mode 100644 index a6598c0ea..0f8435eca --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_attached_with_credentials_exposure_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_attached_with_credentials_exposure_access.yaml @@ -1,57 +1,87 @@ +Description: This control ensures that EC2 instance IAM role should not be attached with credentials exposure access. ID: aws_ec2_instance_no_iam_role_attached_with_credentials_exposure_access -Title: "EC2 instance IAM role should not be attached with credentials exposure access" -Description: "This control ensures that EC2 instance IAM role should not be attached with credentials exposure access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), iam_role_with_permission as ( - select - arn - from - aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in (select role_arn from iam_roles) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and action in ( - 'chime:createapikey', 'codepipeline:pollforjobs', 'cognito-identity:getopenidtoken', 'cognito-identity:getopenidtokenfordeveloperidentity', 'cognito-identity:getcredentialsforidentity', 'connect:getfederationtoken', 'connect:getfederationtokens', 'ec2:getpassworddata', 'ecr:getauthorizationtoken', 'gamelift:requestuploadcredentials', 'iam:createaccesskey', 'iam:createloginprofile', 'iam:createservicespecificcredential', 'iam:resetservicespecificcredential', 'iam:updateaccesskey', 'lightsail:getinstanceaccessdetails', 'lightsail:getrelationaldatabasemasteruserpassword', 'rds-db:connect', 'redshift:getclustercredentials', 'sso:getrolecredentials', 'mediapackage:rotatechannelcredentials', 'mediapackage:rotateingestendpointcredentials', 'sts:assumerole', 'sts:assumerolewithsaml', 'sts:assumerolewithwebidentity', 'sts:getfederationtoken', 'sts:getsessiontoken','*:*' - ) - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no IAM role attached with credentials exposure permissions.' - else title || ' has IAM role attached with credentials exposure permissions.' - end as reason - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_iam_role - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN + aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ( + 'chime:createapikey', + 'codepipeline:pollforjobs', + 'cognito-identity:getopenidtoken', + 'cognito-identity:getopenidtokenfordeveloperidentity', + 'cognito-identity:getcredentialsforidentity', + 'connect:getfederationtoken', + 'connect:getfederationtokens', + 'ec2:getpassworddata', + 'ecr:getauthorizationtoken', + 'gamelift:requestuploadcredentials', + 'iam:createaccesskey', + 'iam:createloginprofile', + 'iam:createservicespecificcredential', + 'iam:resetservicespecificcredential', + 'iam:updateaccesskey', + 'lightsail:getinstanceaccessdetails', + 'lightsail:getrelationaldatabasemasteruserpassword', + 'rds-db:connect', + 'redshift:getclustercredentials', + 'sso:getrolecredentials', + 'mediapackage:rotatechannelcredentials', + 'mediapackage:rotateingestendpointcredentials', + 'sts:assumerole', + 'sts:assumerolewithsaml', + 'sts:assumerolewithwebidentity', + 'sts:getfederationtoken', + 'sts:getsessiontoken', + '*:*' + ) + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM role attached with credentials exposure permissions.' + ELSE title || ' has IAM role attached with credentials exposure permissions.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN + iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN + iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not be attached with credentials exposure access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_alter_critical_s3_permissions_configuration.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_alter_critical_s3_permissions_configuration.yaml old mode 100755 new mode 100644 index 0e5722f53..c29d5e592 --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_alter_critical_s3_permissions_configuration.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_alter_critical_s3_permissions_configuration.yaml @@ -1,57 +1,57 @@ +Description: This control ensures that EC2 instance IAM role does not allow to alter critical s3 permissions configuration. ID: aws_ec2_instance_no_iam_role_with_alter_critical_s3_permissions_configuration -Title: "EC2 instance IAM role should not allow to alter critical s3 permissions configuration" -Description: "This control ensures that EC2 instance IAM role does not allow to alter critical s3 permissions configuration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), iam_role_with_permission as ( - select - arn - from - aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in (select role_arn from iam_roles) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and action in ( - 's3:putobjectretention','s3:putlifecycleconfiguration','s3:putbucketpolicy','s3:putbucketversioning','*:*' - ) - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no IAM role with alter critical s3 permissions configuration.' - else title || ' has IAM role with alter critical s3 permissions configuration.' - end as reason - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_iam_role - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + JSONB_ARRAY_ELEMENTS_TEXT(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + JSONB_ARRAY_ELEMENTS(assume_role_policy_std -> 'Statement') AS s, + JSONB_ARRAY_ELEMENTS_TEXT(s -> 'Principal' -> 'Service') AS service, + JSONB_ARRAY_ELEMENTS_TEXT(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ( + 's3:PutObjectRetention', 's3:PutLifecycleConfiguration', 's3:PutBucketPolicy', 's3:PutBucketVersioning', '*:*' + ) + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM role with alter critical S3 permissions configuration.' + ELSE title || ' has IAM role with alter critical S3 permissions configuration.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow to alter critical S3 permissions configuration \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_cloud_log_tampering_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_cloud_log_tampering_access.yaml old mode 100755 new mode 100644 index 3c7c68fa1..f42ebf913 --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_cloud_log_tampering_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_cloud_log_tampering_access.yaml @@ -1,38 +1,45 @@ +Description: This control ensures that EC2 instance IAM roles do not allow cloud log tampering access. ID: aws_ec2_instance_no_iam_role_with_cloud_log_tampering_access -Title: "EC2 instance IAM role should not allow cloud log tampering access" -Description: "This control ensures that EC2 instance IAM roles do not allow cloud log tampering access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), - iam_role_with_permission as ( - select + ListOfTables: + - aws_ec2_instance + - iam_roles + - iam_role_with_permission + Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), + iam_role_with_permission AS ( + SELECT arn - from + FROM aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in ( - select + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN ( + SELECT role_arn - from + FROM iam_roles - ) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and action in ( + ) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ( 'chime:createapikey', 'codepipeline:pollforjobs', 'cognito-identity:getopenidtoken', @@ -62,31 +69,24 @@ Query: 'sts:getsessiontoken', '*:*' ) - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no IAM role attached with credentials exposure permissions.' - else title || ' has IAM role attached with credentials exposure permissions.' - end as reason, - i.account_id - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - - iam_roles - - iam_role_with_permission - Parameters: [] + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM role attached with credentials exposure permissions.' + ELSE title || ' has IAM role attached with credentials exposure permissions.' + END AS reason, + i.account_id + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow cloud log tampering access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_data_destruction_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_data_destruction_access.yaml old mode 100755 new mode 100644 index 3781dd546..618715a6b --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_data_destruction_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_data_destruction_access.yaml @@ -1,58 +1,67 @@ +Description: This control ensures that EC2 instance IAM role does not allow data destruction access. ID: aws_ec2_instance_no_iam_role_with_data_destruction_access -Title: "EC2 instance IAM role should not allow data destruction access" -Description: "This control ensures that EC2 instance IAM role does not allow data destruction access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), iam_role_with_permission as ( - select + ListOfTables: + - aws_iam_role + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT arn - from + FROM aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in (select role_arn from iam_roles) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and ( - (action in ('s3:deletebucket', 'rds:deletedbcluster', 'rds:deletedbinstance', 'rds:deleteDBSnapshot', 'rds:deletedbclustersnapshot', 'rds:deleteglobalcluster', 'ec2:deletesnapshot', 'ec2:deletevolume', '*:*') + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND ( + action IN ( + 's3:deletebucket', + 'rds:deletedbcluster', + 'rds:deletedbinstance', + 'rds:deleteDBSnapshot', + 'rds:deletedbclustersnapshot', + 'rds:deleteglobalcluster', + 'ec2:deletesnapshot', + 'ec2:deletevolume', + '*:*' ) ) ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no data destruction access.' - else title || ' has data destruction access.' - end as reason - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_iam_role - - aws_ec2_instance - Parameters: [] + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' has no data destruction access.' + ELSE title || ' has data destruction access.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow data destruction access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_destruction_kms_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_destruction_kms_access.yaml old mode 100755 new mode 100644 index a73c12642..128ef98dc --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_destruction_kms_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_destruction_kms_access.yaml @@ -1,55 +1,55 @@ +Description: This control ensures that EC2 instance IAM roles do not allow destruction KMS access. ID: aws_ec2_instance_no_iam_role_with_destruction_kms_access -Title: "EC2 instance IAM role should not allow destruction KMS access" -Description: "This control ensures that EC2 instance IAM roles do not allow destruction KMS access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), iam_role_with_permission as ( - select - arn - from - aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in (select role_arn from iam_roles) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and action in ('secretsmanager:getsecretvalue', 'kms:decrypt', '*:*') - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no IAM role with destruction KMS permission.' - else title || ' has IAM role with destruction KMS permission.' - end as reason - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_iam_role - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ('secretsmanager:getsecretvalue', 'kms:decrypt', '*:*') + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM role with destruction KMS permission.' + ELSE title || ' has IAM role with destruction KMS permission.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow destruction KMS access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_destruction_rds_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_destruction_rds_access.yaml old mode 100755 new mode 100644 index 880e2c246..5db22aa46 --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_destruction_rds_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_destruction_rds_access.yaml @@ -1,15 +1,55 @@ +Description: This control ensures that EC2 instance IAM roles do not allow destruction RDS access. ID: aws_ec2_instance_no_iam_role_with_destruction_rds_access -Title: "EC2 instance IAM role should not allow destruction RDS access" -Description: "This control ensures that EC2 instance IAM roles do not allow destruction RDS access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with iam_roles as (\n select\n r.arn as role_arn,\n i.arn as intance_arn\n from\n aws_iam_role as r,\n jsonb_array_elements_text(instance_profile_arns) as p\n left join aws_ec2_instance as i on p = i.iam_instance_profile_arn\n where\n i.arn is not null\n), iam_role_with_permission as (\n select\n arn\n from\n aws_iam_role,\n jsonb_array_elements(assume_role_policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n arn in (select role_arn from iam_roles)\n and s ->> 'Effect' = 'Allow'\n and service = 'ec2.amazonaws.com'\n and action in ( 'srds-data:ExecuteStatement', 'rds-data:BatchExecuteStatement', '*:*')\n)\nselect\n i.arn as resource,\n i.og_account_id as og_account_id,\n i.og_resource_id as og_resource_id,\n case\n when p.arn is null then 'ok'\n else 'alarm'\n end status,\n case\n when p.arn is null then title || ' has no IAM role with destruction RDS permission.'\n else title || ' has IAM role with destruction RDS permission.'\n end as reason\n \n \nfrom\n aws_ec2_instance as i\n left join iam_roles as r on r.intance_arn = i.arn\n left join iam_role_with_permission as p on p.arn = r.role_arn;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_iam_role - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ('rds-data:ExecuteStatement', 'rds-data:BatchExecuteStatement', '*:*') + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM role with destruction RDS permission.' + ELSE title || ' has IAM role with destruction RDS permission.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow destruction RDS access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_elastic_ip_hijacking_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_elastic_ip_hijacking_access.yaml old mode 100755 new mode 100644 index 4f3d36ba5..a3eadb460 --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_elastic_ip_hijacking_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_elastic_ip_hijacking_access.yaml @@ -1,38 +1,45 @@ +Description: This control ensures that EC2 instance IAM role does not allow elastic IP hijacking access. ID: aws_ec2_instance_no_iam_role_with_elastic_ip_hijacking_access -Title: "EC2 instance IAM role should not allow elastic IP hijacking access." -Description: "This control ensures that EC2 instance IAM role does not allow elastic IP hijacking access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), - iam_role_with_permission as ( - select + ListOfTables: + - aws_ec2_instance + - iam_roles + - iam_role_with_permission + Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), + iam_role_with_permission AS ( + SELECT arn - from + FROM aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in ( - select + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN ( + SELECT role_arn - from + FROM iam_roles ) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and action in ( + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ( 'chime:createapikey', 'codepipeline:pollforjobs', 'cognito-identity:getopenidtoken', @@ -62,31 +69,24 @@ Query: 'sts:getsessiontoken', '*:*' ) - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no IAM role attached with credentials exposure permissions.' - else title || ' has IAM role attached with credentials exposure permissions.' - end as reason, + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM role attached with credentials exposure permissions.' + ELSE title || ' has IAM role attached with credentials exposure permissions.' + END AS reason, i.account_id - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - - iam_roles - - iam_role_with_permission - Parameters: [] + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow elastic IP hijacking access. \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_management_level_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_management_level_access.yaml old mode 100755 new mode 100644 index e1ce8d411..9678e6332 --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_management_level_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_management_level_access.yaml @@ -1,58 +1,82 @@ +Description: This control ensures that EC2 instance IAM role does not allow management level access. ID: aws_ec2_instance_no_iam_role_with_management_level_access -Title: "EC2 instance IAM role should not allow management level access" -Description: "This control ensures that EC2 instance IAM role does not allow management level access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), iam_role_with_permission as ( - select + ListOfTables: + - aws_iam_role + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT arn - from + FROM aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in (select role_arn from iam_roles) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and ( - (action in ('iam:attachgrouppolicy', 'iam:attachrolepolicy', 'iam:attachuserpolicy', 'iam:createpolicy', 'iam:createpolicyversion', 'iam:deleteaccountpasswordpolicy', 'iam:deletegrouppolicy', 'iam:deletepolicy', 'iam:deletepolicyversion', 'iam:deleterolepermissionsboundary', 'iam:deleterolepolicy', 'iam:deleteuserpermissionsboundary', 'iam:deleteuserpolicy', 'iam:detachgrouppolicy', 'iam:detachrolepolicy', 'iam:detachuserpolicy', 'iam:putgrouppolicy', 'iam:putrolepermissionsboundary', 'iam:putrolepolicy', 'iam:putuserpermissionsboundary', 'iam:putuserpolicy','iam:setdefaultpolicyversion','iam:updateassumerolerolicy', '*:*') + jsonb_array_elements(assume_role_policy_std->'Statement') AS s, + jsonb_array_elements_text(s->'Principal'->'Service') AS service, + jsonb_array_elements_text(s->'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s->>'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND ( + action IN ( + 'iam:attachgrouppolicy', + 'iam:attachrolepolicy', + 'iam:attachuserpolicy', + 'iam:createpolicy', + 'iam:createpolicyversion', + 'iam:deleteaccountpasswordpolicy', + 'iam:deletegrouppolicy', + 'iam:deletepolicy', + 'iam:deletepolicyversion', + 'iam:deleterolepermissionsboundary', + 'iam:deleterolepolicy', + 'iam:deleteuserpermissionsboundary', + 'iam:deleteuserpolicy', + 'iam:detachgrouppolicy', + 'iam:detachrolepolicy', + 'iam:detachuserpolicy', + 'iam:putgrouppolicy', + 'iam:putrolepermissionsboundary', + 'iam:putrolepolicy', + 'iam:putuserpermissionsboundary', + 'iam:putuserpolicy', + 'iam:setdefaultpolicyversion', + 'iam:updateassumerolerolicy', + '*:*' ) ) ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no management level access.' - else title || ' has management level access.' - end as reason - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_iam_role - - aws_ec2_instance - Parameters: [] + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN p.arn IS NULL THEN title || ' has no management level access.' + ELSE title || ' has management level access.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow management level access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_new_group_creation_with_attached_policy_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_new_group_creation_with_attached_policy_access.yaml old mode 100755 new mode 100644 index 58b78b7cc..93e08d916 --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_new_group_creation_with_attached_policy_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_new_group_creation_with_attached_policy_access.yaml @@ -1,56 +1,59 @@ +Description: This control ensures that EC2 instance IAM role does not allow new group creation with attached policy access. ID: aws_ec2_instance_no_iam_role_with_new_group_creation_with_attached_policy_access -Title: "EC2 instance IAM role should not allow new group creation with attached policy access" -Description: "This control ensures that EC2 instance IAM role does not allow new group creation with attached policy access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), iam_role_with_permission as ( - select - arn - from - aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in (select role_arn from iam_roles) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and action = 'iam:creategroup' - and action = 'iam:attachgrouppolicy' - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no new group creation access with attached policy.' - else title || ' has new group creation access with attached policy.' - end as reason - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_iam_role - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i + ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action = 'iam:creategroup' + AND action = 'iam:attachgrouppolicy' + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' has no new group creation access with attached policy.' + ELSE title || ' has new group creation access with attached policy.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r + ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p + ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow new group creation with attached policy access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_new_role_creation_with_attached_policy_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_new_role_creation_with_attached_policy_access.yaml old mode 100755 new mode 100644 index 76f38b99e..060ad2706 --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_new_role_creation_with_attached_policy_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_new_role_creation_with_attached_policy_access.yaml @@ -1,56 +1,57 @@ +Description: This control ensures that EC2 instance IAM role does not allow new role creation with attached policy access. ID: aws_ec2_instance_no_iam_role_with_new_role_creation_with_attached_policy_access -Title: "EC2 instance IAM role should not allow new role creation with attached policy access" -Description: "This control ensures that EC2 instance IAM role does not allow new role creation with attached policy access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), iam_role_with_permission as ( - select - arn - from - aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in (select role_arn from iam_roles) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and action = 'iam:createrole' - and action = 'iam:attachrolepolicy' - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no new role creation access with attached policy .' - else title || ' has new role creation access with attached policy.' - end as reason - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_iam_role - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), + iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action = 'iam:createrole' + AND action = 'iam:attachrolepolicy' + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN p.arn IS NULL THEN title || ' has no new role creation access with attached policy.' + ELSE title || ' has new role creation access with attached policy.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow new role creation with attached policy access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_org_write_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_org_write_access.yaml old mode 100755 new mode 100644 index 22a6d2c2c..d6420879b --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_org_write_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_org_write_access.yaml @@ -1,58 +1,85 @@ +Description: This control ensures that EC2 instance IAM role does not allow organization write access. ID: aws_ec2_instance_no_iam_role_with_org_write_access -Title: "EC2 instance IAM role should not allow oraganization write access" -Description: "This control ensures that EC2 instance IAM role does not allow oraganization write access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), iam_role_with_permission as ( - select + ListOfTables: + - aws_iam_role + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT arn - from + FROM aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in (select role_arn from iam_roles) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and ( - (action in ('organizations:accepthandshake','organizations:attachpolicy','organizations:cancelhandshake','organizations:createaccount','organizations:creategovcloudaccount','organizations:createorganization','organizations:createorganizationalunit','organizations:createpolicy','organizations:declinehandshake','organizations:deleteorganization','organizations:deleteorganizationalunit','organizations:deletepolicy','organizations:deregisterdelegatedadministrator','organizations:detachpolicy','organizations:disableawsserviceaccess','organizations:disablepolicytype','organizations:enableawsserviceaccess','organizations:enableallfeatures','organizations:enablepolicytype','organizations:inviteaccounttoorganization','organizations:Leaveorganization','organizations:moveaccount','organizations:registerdelegatedadministrator','organizations:removeaccountfromorganization','organizations:updateorganizationalunit','organizations:updatepolicy','*:*') + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND ( + action IN ( + 'organizations:AcceptHandshake', + 'organizations:AttachPolicy', + 'organizations:CancelHandshake', + 'organizations:CreateAccount', + 'organizations:CreateGovCloudAccount', + 'organizations:CreateOrganization', + 'organizations:CreateOrganizationalUnit', + 'organizations:CreatePolicy', + 'organizations:DeclineHandshake', + 'organizations:DeleteOrganization', + 'organizations:DeleteOrganizationalUnit', + 'organizations:DeletePolicy', + 'organizations:DeregisterDelegatedAdministrator', + 'organizations:DetachPolicy', + 'organizations:DisableAWSServiceAccess', + 'organizations:DisablePolicyType', + 'organizations:EnableAWSServiceAccess', + 'organizations:EnableAllFeatures', + 'organizations:EnablePolicyType', + 'organizations:InviteAccountToOrganization', + 'organizations:LeaveOrganization', + 'organizations:MoveAccount', + 'organizations:RegisterDelegatedAdministrator', + 'organizations:RemoveAccountFromOrganization', + 'organizations:UpdateOrganizationalUnit', + 'organizations:UpdatePolicy', + '*:*' ) ) ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no organization write access.' - else title || ' has organization write access.' - end as reason - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_iam_role - - aws_ec2_instance - Parameters: [] + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' has no organization write access.' + ELSE title || ' has organization write access.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow organization write access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_privilege_escalation_risk_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_privilege_escalation_risk_access.yaml old mode 100755 new mode 100644 index 954004de8..2a678dd8d --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_privilege_escalation_risk_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_privilege_escalation_risk_access.yaml @@ -1,58 +1,66 @@ +Description: This control ensures that EC2 instance IAM role does not allow privilege escalation risk access. ID: aws_ec2_instance_no_iam_role_with_privilege_escalation_risk_access -Title: "EC2 instance IAM role should not allow privilege escalation risk access" -Description: "This control ensures that EC2 instance IAM role does not allow privilege escalation risk access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), iam_role_with_permission as ( - select + ListOfTables: + - aws_iam_role + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i + ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT arn - from + FROM aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in (select role_arn from iam_roles) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and ( - (action in ('iam:createpolicy', 'iam:createpolicyversion', 'iam:SetDefaultpolicyversion', 'iam:passrole', 'iam:createaccessKey', 'iam:createloginprofile', 'iam:updateloginprofile', 'iam:attachuserpolicy', 'iam:attachgrouppolicy', 'iam:attachrolepolicy', 'iam:putuserpolicy', 'iam:putgrouppolicy', 'iam:putrolepolicy', 'iam:addusertogroup', 'iam:updateassumerolepolicy', '*:*') + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND ( + action IN ( + 'iam:createpolicy', 'iam:createpolicyversion', 'iam:SetDefaultpolicyversion', + 'iam:passrole', 'iam:createaccessKey', 'iam:createloginprofile', + 'iam:updateloginprofile', 'iam:attachuserpolicy', 'iam:attachgrouppolicy', + 'iam:attachrolepolicy', 'iam:putuserpolicy', 'iam:putgrouppolicy', + 'iam:putrolepolicy', 'iam:addusertogroup', 'iam:updateassumerolepolicy', '*:*' ) ) ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no privilege escalation access.' - else title || ' has privilege escalation access.' - end as reason - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_iam_role - - aws_ec2_instance - Parameters: [] + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' has no privilege escalation access.' + ELSE title || ' has privilege escalation access.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r + ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p + ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow privilege escalation risk access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_security_group_write_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_security_group_write_access.yaml old mode 100755 new mode 100644 index 4351b57a8..3daec46db --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_security_group_write_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_security_group_write_access.yaml @@ -1,55 +1,72 @@ +Description: This control ensures that EC2 instance IAM roles do not allow security group write access. ID: aws_ec2_instance_no_iam_role_with_security_group_write_access -Title: "EC2 instance IAM role should not allow security group write access" -Description: "This control ensures that EC2 instance IAM roles do not allow security group write access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), iam_role_with_permission as ( - select - arn - from - aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in (select role_arn from iam_roles) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and action in ( 'rds:createdbsecuritygroup','rds:deletedbsecuritygroup','rds:revokedbsecuritygroupingress','ec2:authorizesecuritygroupegress','ec2:authorizesecuritygroupingress','ec2:createsecuritygroup','ec2:deletesecuritygroup','ec2:modifysecuritygrouprules','ec2:revokesecuritygroupegress','ec2:revokesecuritygroupingress','elasticloadbalancing:applysecuritygroupsToLoadbalancer','elasticloadbalancing:setsecuritygroups','redshift:authorizeclustersecuritygroupingress','redshift:createclustersecuritygroup','redshift:deleteclustersecuritygroup','*:*') - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no IAM role with security group write access.' - else title || ' has IAM role with security group write access.' - end as reason - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_iam_role - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ( + 'rds:createdbsecuritygroup', + 'rds:deletedbsecuritygroup', + 'rds:revokedbsecuritygroupingress', + 'ec2:authorizesecuritygroupegress', + 'ec2:authorizesecuritygroupingress', + 'ec2:createsecuritygroup', + 'ec2:deletesecuritygroup', + 'ec2:modifysecuritygrouprules', + 'ec2:revokesecuritygroupegress', + 'ec2:revokesecuritygroupingress', + 'elasticloadbalancing:applysecuritygroupsToLoadbalancer', + 'elasticloadbalancing:setsecuritygroups', + 'redshift:authorizeclustersecuritygroupingress', + 'redshift:createclustersecuritygroup', + 'redshift:deleteclustersecuritygroup', + '*:*' + ) + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM role with security group write access.' + ELSE title || ' has IAM role with security group write access.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow security group write access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_write_permission_on_critical_s3_configuration.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_write_permission_on_critical_s3_configuration.yaml old mode 100755 new mode 100644 index 44ec859ca..1e6b605db --- a/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_write_permission_on_critical_s3_configuration.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_role_with_write_permission_on_critical_s3_configuration.yaml @@ -1,38 +1,46 @@ +Description: This control ensures that EC2 instance IAM roles do not allow write permission on critical S3 configuration. ID: aws_ec2_instance_no_iam_role_with_write_permission_on_critical_s3_configuration -Title: "EC2 instance IAM role should not allow write permission on critical s3 configuration" -Description: "This control ensures that EC2 instance IAM roles do not allow write permission on critical s3 configuration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with iam_roles as ( - select - r.arn as role_arn, - i.arn as intance_arn - from - aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where - i.arn is not null - ), - iam_role_with_permission as ( - select + ListOfTables: + - aws_ec2_instance + - iam_roles + - iam_role_with_permission + Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN + aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), + iam_role_with_permission AS ( + SELECT arn - from + FROM aws_iam_role, - jsonb_array_elements(assume_role_policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service, - jsonb_array_elements_text(s -> 'Action') as action - where - arn in ( - select + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN ( + SELECT role_arn - from + FROM iam_roles ) - and s ->> 'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and action in ( + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ( 'rds:createdbsecuritygroup', 'rds:deletedbsecuritygroup', 'rds:revokedbsecuritygroupingress', @@ -50,31 +58,26 @@ Query: 'redshift:deleteclustersecuritygroup', '*:*' ) - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no IAM role with security group write access.' - else title || ' has IAM role with security group write access.' - end as reason, + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM role with security group write access.' + ELSE title || ' has IAM role with security group write access.' + END AS reason, i.account_id - from - aws_ec2_instance as i - left join iam_roles as r on r.intance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - - iam_roles - - iam_role_with_permission - Parameters: [] + FROM + aws_ec2_instance AS i + LEFT JOIN + iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN + iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow write permission on critical S3 configuration \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_iam_with_write_level_access.yaml b/compliance/controls/aws/aws_ec2_instance_no_iam_with_write_level_access.yaml old mode 100755 new mode 100644 index e9f42a986..a53bbce1f --- a/compliance/controls/aws/aws_ec2_instance_no_iam_with_write_level_access.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_iam_with_write_level_access.yaml @@ -1,113 +1,118 @@ +Description: This control ensures that EC2 instance IAM role does not allow write level access. ID: aws_ec2_instance_no_iam_with_write_level_access -Title: "EC2 instance IAM role should not allow write level access" -Description: "This control ensures that EC2 instance IAM role does not allow write level access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with iam_roles as ( - select r.arn as role_arn, - i.arn as instance_arn - from aws_iam_role as r, - jsonb_array_elements_text(instance_profile_arns) as p - left join aws_ec2_instance as i on p = i.iam_instance_profile_arn - where i.arn is not null - ), - iam_role_with_permission as ( - select arn - from aws_iam_role, - jsonb_array_elements(assume_role_policy_std->'Statement') as s, - jsonb_array_elements_text(s->'Principal'->'Service') as service, - jsonb_array_elements_text(s->'Action') as action - where arn in ( - select role_arn - from iam_roles - ) - and s->>'Effect' = 'Allow' - and service = 'ec2.amazonaws.com' - and ( - ( - action in ( - 'iam:addclientidtoopenidconnectprovider', - 'iam:addroletoinstanceprofile', - 'iam:addusertogroup', - 'iam:changepassword', - 'iam:createaccesskey', - 'iam:createaccountalias', - 'iam:creategroup', - 'iam:createinstanceprofile', - 'iam:createloginprofile', - 'iam:createopenidconnectprovider', - 'iam:createrole', - 'iam:createsamlprovider', - 'iam:createservicelinkedrole', - 'iam:createservicespecificcredential', - 'iam:createuser', - 'iam:createvirtualmfadevice', - 'iam:deactivatemfadevice', - 'iam:deleteaccesskey', - 'iam:deleteaccountalias', - 'iam:deletegroup', - 'iam:deleteinstanceprofile', - 'iam:deleteloginprofile', - 'iam:deleteopenidconnectprovider', - 'iam:deleterole', - 'iam:deletesamlprovider', - 'iam:deletesshpublickey', - 'iam:deleteservercertificate', - 'iam:deleteservicelinkedrole', - 'iam:deleteservicespecificcredential', - 'iam:deletesigningcertificate', - 'iam:deleteUser', - 'iam:deletevirtualmfadevice', - 'iam:enablemfadevice', - 'iam:passrole', - 'iam:removeclientidfromopenidconnectprovider', - 'iam:removerolefrominstanceprofile', - 'iam:removeuserfromgroup', - 'iam:resetservicespecificcredential', - 'iam:resyncmfadevice', - 'iam:setsecuritytokenservicepreferences', - 'iam:updateaccesskey', - 'iam:updateaccountpasswordpolicy', - 'iam:updategroup', - 'iam:updateloginprofile', - 'iam:updateopenidconnectproviderthumbprint', - 'iam:updaterole', - 'iam:updateroledescription', - 'iam:updatesamlprovider', - 'iam:updatesshpublicKey', - 'iam:updateservercertificate', - 'iam:updateservicespecificcredential', - 'iam:updatesigningcertificate', - 'iam:updateuser', - 'iam:uploadsshpublicKey', - 'iam:uploadservercertificate', - 'iam:uploadsigningcertificate', - '*:*' - ) - ) - ) - ) - select i.arn as resource, - case - when p.arn is null then 'ok' - else 'alarm' - end status, - case - when p.arn is null then title || ' has no IAM rite level access.' - else title || ' has IAM write level access.' - end as reason, - i.og_account_id, - i.og_resource_id, - i.account_id - from aws_ec2_instance as i - left join iam_roles as r on r.instance_arn = i.arn - left join iam_role_with_permission as p on p.arn = r.role_arn; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance - aws_iam_role Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH iam_roles AS ( + SELECT r.arn AS role_arn, + i.arn AS instance_arn + FROM aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i + ON p = i.iam_instance_profile_arn + WHERE i.arn IS NOT NULL + ), + iam_role_with_permission AS ( + SELECT arn + FROM aws_iam_role, + jsonb_array_elements(assume_role_policy_std->'Statement') AS s, + jsonb_array_elements_text(s->'Principal'->'Service') AS service, + jsonb_array_elements_text(s->'Action') AS action + WHERE arn IN ( + SELECT role_arn + FROM iam_roles + ) + AND s->>'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND ( + ( + action IN ( + 'iam:addclientidtoopenidconnectprovider', + 'iam:addroletoinstanceprofile', + 'iam:addusertogroup', + 'iam:changepassword', + 'iam:createaccesskey', + 'iam:createaccountalias', + 'iam:creategroup', + 'iam:createinstanceprofile', + 'iam:createloginprofile', + 'iam:createopenidconnectprovider', + 'iam:createrole', + 'iam:createsamlprovider', + 'iam:createservicelinkedrole', + 'iam:createservicespecificcredential', + 'iam:createuser', + 'iam:createvirtualmfadevice', + 'iam:deactivatemfadevice', + 'iam:deleteaccesskey', + 'iam:deleteaccountalias', + 'iam:deletegroup', + 'iam:deleteinstanceprofile', + 'iam:deleteloginprofile', + 'iam:deleteopenidconnectprovider', + 'iam:deleterole', + 'iam:deletesamlprovider', + 'iam:deletesshpublickey', + 'iam:deleteservercertificate', + 'iam:deleteservicelinkedrole', + 'iam:deleteservicespecificcredential', + 'iam:deletesigningcertificate', + 'iam:deleteUser', + 'iam:deletevirtualmfadevice', + 'iam:enablemfadevice', + 'iam:passrole', + 'iam:removeclientidfromopenidconnectprovider', + 'iam:removerolefrominstanceprofile', + 'iam:removeuserfromgroup', + 'iam:resetservicespecificcredential', + 'iam:resyncmfadevice', + 'iam:setsecuritytokenservicepreferences', + 'iam:updateaccesskey', + 'iam:updateaccountpasswordpolicy', + 'iam:updategroup', + 'iam:updateloginprofile', + 'iam:updateopenidconnectproviderthumbprint', + 'iam:updaterole', + 'iam:updateroledescription', + 'iam:updatesamlprovider', + 'iam:updatesshpublicKey', + 'iam:updateservercertificate', + 'iam:updateservicespecificcredential', + 'iam:updatesigningcertificate', + 'iam:updateuser', + 'iam:uploadsshpublicKey', + 'iam:uploadservercertificate', + 'iam:uploadsigningcertificate', + '*:*' + ) + ) + ) + ) + SELECT i.arn AS resource, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM writ level access.' + ELSE title || ' has IAM write level access.' + END AS reason, + i.og_account_id, + i.og_resource_id, + i.account_id + FROM aws_ec2_instance AS i + LEFT JOIN iam_roles AS r + ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p + ON p.arn = r.role_arn; + Severity: critical Tags: category: @@ -128,12 +133,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -146,5 +151,4 @@ Tags: - AWS/EC2 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow write level access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_no_launch_wizard_security_group.yaml b/compliance/controls/aws/aws_ec2_instance_no_launch_wizard_security_group.yaml old mode 100755 new mode 100644 index c58df6eb1..ffa69cd4f --- a/compliance/controls/aws/aws_ec2_instance_no_launch_wizard_security_group.yaml +++ b/compliance/controls/aws/aws_ec2_instance_no_launch_wizard_security_group.yaml @@ -1,38 +1,39 @@ +Description: Ensure EC2 instances provisioned in your AWS account are not associated with security groups that have their name prefixed with 'launch-wizard', in order to enforce using secure and custom security groups that exercise the principle of least privilege. ID: aws_ec2_instance_no_launch_wizard_security_group -Title: "EC2 instances should not be attached to 'launch wizard' security groups" -Description: "Ensure EC2 instances provisioned in your AWS account are not associated with security groups that have their name prefixed with 'launch-wizard', in order to enforce using secure and custom security groups that exercise the principle of least privilege." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with launch_wizard_sg_attached_instance as ( - select - distinct arn as arn - from - aws_ec2_instance, - jsonb_array_elements(security_groups) as sg - where - sg ->> 'GroupName' like 'launch-wizard%' - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when sg.arn is null then 'ok' - else 'alarm' - end as status, - case - when sg.arn is null then i.title || ' not associated with launch-wizard security group.' - else i.title || ' associated with launch-wizard security group.' - end as reason - from - aws_ec2_instance as i - left join launch_wizard_sg_attached_instance as sg on i.arn = sg.arn; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH launch_wizard_sg_attached_instance AS ( + SELECT + DISTINCT arn AS arn + FROM + aws_ec2_instance, + jsonb_array_elements(security_groups) AS sg + WHERE + sg ->> 'GroupName' LIKE 'launch-wizard%' + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN sg.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sg.arn IS NULL THEN i.title || ' not associated with launch-wizard security group.' + ELSE i.title || ' associated with launch-wizard security group.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN + launch_wizard_sg_attached_instance AS sg ON i.arn = sg.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instances should not be attached to 'launch wizard' security groups \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_not_older_than_180_days.yaml b/compliance/controls/aws/aws_ec2_instance_not_older_than_180_days.yaml old mode 100755 new mode 100644 index e0a418d90..eb16f1894 --- a/compliance/controls/aws/aws_ec2_instance_not_older_than_180_days.yaml +++ b/compliance/controls/aws/aws_ec2_instance_not_older_than_180_days.yaml @@ -1,14 +1,26 @@ +Description: '"Identify any running AWS EC2 instances older than 180 days.' ID: aws_ec2_instance_not_older_than_180_days -Title: "Ensure no AWS EC2 Instances are older than 180 days" -Description: "\"Identify any running AWS EC2 instances older than 180 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n instance_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n launch_time,\n case\n when launch_time >= (current_date - interval '180 days') then 'ok'\n else 'alarm'\n end as status,\n title || ' created ' || to_char(launch_time , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - launch_time) || ' days).' as reason\n \n \nfrom\n aws_ec2_instance;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + instance_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + launch_time, + CASE + WHEN launch_time >= (current_date - INTERVAL '180 days') THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' created ' || TO_CHAR(launch_time, 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM CURRENT_TIMESTAMP - launch_time) || ' days).' AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure no AWS EC2 Instances are older than 180 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_not_publicly_accessible.yaml b/compliance/controls/aws/aws_ec2_instance_not_publicly_accessible.yaml old mode 100755 new mode 100644 index 92ce910c5..36a6fbbec --- a/compliance/controls/aws/aws_ec2_instance_not_publicly_accessible.yaml +++ b/compliance/controls/aws/aws_ec2_instance_not_publicly_accessible.yaml @@ -1,13 +1,30 @@ +Description: '"Manage access to the AWS Cloud by ensuring AWS Elastic Compute Cloud (AWS EC2) instances cannot be publicly accessed.' ID: aws_ec2_instance_not_publicly_accessible -Title: "EC2 instances should not have a public IP address" -Description: "\"Manage access to the AWS Cloud by ensuring AWS Elastic Compute Cloud (AWS EC2) instances cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when public_ip_address is null then 'ok'\n else 'alarm'\n end as status,\n case\n when public_ip_address is null then instance_id || ' not publicly accessible.'\n else instance_id || ' publicly accessible.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_instance;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN public_ip_address IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN public_ip_address IS NULL THEN instance_id || ' not publicly accessible.' + ELSE instance_id || ' publicly accessible.' + END AS reason, + region, + account_id + FROM + aws_ec2_instance; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/EC2 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EC2 instances should not have a public IP address \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_not_use_multiple_enis.yaml b/compliance/controls/aws/aws_ec2_instance_not_use_multiple_enis.yaml old mode 100755 new mode 100644 index 23d12f741..a5c70d3f1 --- a/compliance/controls/aws/aws_ec2_instance_not_use_multiple_enis.yaml +++ b/compliance/controls/aws/aws_ec2_instance_not_use_multiple_enis.yaml @@ -1,13 +1,27 @@ +Description: This control checks whether an EC2 instance uses multiple Elastic Network Interfaces (ENIs) or Elastic Fabric Adapters (EFAs). This control passes if a single network adapter is used. The control includes an optional parameter list to identify the allowed ENIs. ID: aws_ec2_instance_not_use_multiple_enis -Title: "EC2 instances should not use multiple ENIs" -Description: "This control checks whether an EC2 instance uses multiple Elastic Network Interfaces (ENIs) or Elastic Fabric Adapters (EFAs). This control passes if a single network adapter is used. The control includes an optional parameter list to identify the allowed ENIs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(network_interfaces) = 1 then 'ok'\n else 'alarm'\n end status,\n title || ' has ' || jsonb_array_length(network_interfaces) || ' ENI(s) attached.'\n as reason\n \n , region, account_id\nfrom\n aws_ec2_instance;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(network_interfaces) = 1 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' has ' || jsonb_array_length(network_interfaces) || ' ENI(s) attached.' AS reason, + region, + account_id + FROM + aws_ec2_instance; Severity: low Tags: aws_foundational_security: @@ -22,5 +36,4 @@ Tags: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: EC2 instances should not use multiple ENIs \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_protected_by_backup_plan.yaml b/compliance/controls/aws/aws_ec2_instance_protected_by_backup_plan.yaml old mode 100755 new mode 100644 index aa23f0ee5..6697c486a --- a/compliance/controls/aws/aws_ec2_instance_protected_by_backup_plan.yaml +++ b/compliance/controls/aws/aws_ec2_instance_protected_by_backup_plan.yaml @@ -1,14 +1,40 @@ +Description: Ensure that AWS Elastic Compute Cloud (AWS EC2) instances are protected by a backup plan. The rule is non-compliant if the AWS EC2 instance is not covered by a backup plan. ID: aws_ec2_instance_protected_by_backup_plan -Title: "EC2 instances should be protected by backup plan" -Description: "Ensure that AWS Elastic Compute Cloud (AWS EC2) instances are protected by a backup plan. The rule is non-compliant if the AWS EC2 instance is not covered by a backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with backup_protected_instance as (\n select\n resource_arn as arn\n from\n aws_backup_protected_resource as b\n where\n resource_type = 'EC2'\n)\nselect\n i.arn as resource,\n i.og_account_id as og_account_id,\n i.og_resource_id as og_resource_id,\n case\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is not null then i.title || ' is protected by backup plan.'\n else i.title || ' is not protected by backup plan.'\n end as reason\n \n , i.region, i.account_id\nfrom\n aws_ec2_instance as i\n left join backup_protected_instance as b on i.arn = b.arn;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_backup_protected_resource - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH backup_protected_instance AS ( + SELECT + resource_arn AS arn + FROM + aws_backup_protected_resource AS b + WHERE + resource_type = 'EC2' + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NOT NULL THEN i.title || ' is protected by backup plan.' + ELSE i.title || ' is not protected by backup plan.' + END AS reason, + i.region, + i.account_id + FROM + aws_ec2_instance AS i + LEFT JOIN backup_protected_instance AS b ON i.arn = b.arn; Severity: high Tags: category: @@ -41,5 +67,4 @@ Tags: - AWS/EC2 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EC2 instances should be protected by backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_publicly_accessible_iam_profile_attached.yaml b/compliance/controls/aws/aws_ec2_instance_publicly_accessible_iam_profile_attached.yaml old mode 100755 new mode 100644 index 5070101c3..bd643e86f --- a/compliance/controls/aws/aws_ec2_instance_publicly_accessible_iam_profile_attached.yaml +++ b/compliance/controls/aws/aws_ec2_instance_publicly_accessible_iam_profile_attached.yaml @@ -1,14 +1,30 @@ +Description: Ensure AWS Elastic Compute Cloud (AWS EC2) public instances have an Identity and Access Management (IAM) profile attached to them. This rule is non-compliant if no IAM profile is attached to a public AWS EC2 instance. ID: aws_ec2_instance_publicly_accessible_iam_profile_attached -Title: "Public EC2 instances should have IAM profile attached" -Description: "Ensure AWS Elastic Compute Cloud (AWS EC2) public instances have an Identity and Access Management (IAM) profile attached to them. This rule is non-compliant if no IAM profile is attached to a public AWS EC2 instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when iam_instance_profile_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when iam_instance_profile_id is not null then title || ' IAM profile attached.'\n else title || ' IAM profile not attached.'\n end as reason\n \n \nfrom\n aws_ec2_instance\nwhere\n public_ip_address is not null;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN iam_instance_profile_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN iam_instance_profile_id IS NOT NULL THEN title || ' IAM profile attached.' + ELSE title || ' IAM profile not attached.' + END AS reason + FROM + aws_ec2_instance + WHERE + public_ip_address IS NOT NULL; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Public EC2 instances should have IAM profile attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_ssm_managed.yaml b/compliance/controls/aws/aws_ec2_instance_ssm_managed.yaml old mode 100755 new mode 100644 index 971fbbfaa..0a98d5176 --- a/compliance/controls/aws/aws_ec2_instance_ssm_managed.yaml +++ b/compliance/controls/aws/aws_ec2_instance_ssm_managed.yaml @@ -1,14 +1,37 @@ +Description: An inventory of the software platforms and applications within the organization is possible by managing AWS Elastic Compute Cloud (AWS EC2) instances with AWS Systems Manager. ID: aws_ec2_instance_ssm_managed -Title: "EC2 instances should be managed by AWS Systems Manager" -Description: "An inventory of the software platforms and applications within the organization is possible by managing AWS Elastic Compute Cloud (AWS EC2) instances with AWS Systems Manager." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n i.arn as resource,\n i.og_account_id as og_account_id,\n i.og_resource_id as og_resource_id,\n case\n when i.instance_state = 'stopped' then 'info'\n when m.instance_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when i.instance_state = 'stopped' then i.title || ' is in stopped state.'\n when m.instance_id is null then i.title || ' not managed by AWS SSM.'\n else i.title || ' managed by AWS SSM.'\n end as reason\n \n , i.region, i.account_id\nfrom\n aws_ec2_instance i\n left join aws_ssm_managed_instance m on m.instance_id = i.instance_id;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance - aws_ssm_managed_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN i.instance_state = 'stopped' THEN 'info' + WHEN m.instance_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.instance_state = 'stopped' THEN i.title || ' is in stopped state.' + WHEN m.instance_id IS NULL THEN i.title || ' not managed by AWS SSM.' + ELSE i.title || ' managed by AWS SSM.' + END AS reason, + i.region, + i.account_id + FROM + aws_ec2_instance i + LEFT JOIN + aws_ssm_managed_instance m + ON + m.instance_id = i.instance_id; Severity: low Tags: category: @@ -29,12 +52,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -47,5 +70,4 @@ Tags: - AWS/SSM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EC2 instances should be managed by AWS Systems Manager \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_termination_protection_enabled.yaml b/compliance/controls/aws/aws_ec2_instance_termination_protection_enabled.yaml old mode 100755 new mode 100644 index a363e7f50..2ab132be3 --- a/compliance/controls/aws/aws_ec2_instance_termination_protection_enabled.yaml +++ b/compliance/controls/aws/aws_ec2_instance_termination_protection_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether termination protection is enabled for EC2 instances. The control fails if termination protection is not enabled for an EC2 instance. ID: aws_ec2_instance_termination_protection_enabled -Title: "AWS EC2 instances should have termination protection enabled" -Description: "This control checks whether termination protection is enabled for EC2 instances. The control fails if termination protection is not enabled for an EC2 instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when disable_api_termination then 'ok' - else 'alarm' - end status, - case - when disable_api_termination then instance_id || ' termination protection enabled.' - else instance_id || ' termination protection disabled.' - end reason - from - aws_ec2_instance; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN disable_api_termination THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN disable_api_termination THEN instance_id || ' termination protection enabled.' + ELSE instance_id || ' termination protection disabled.' + END AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: AWS EC2 instances should have termination protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_user_data_no_secrets.yaml b/compliance/controls/aws/aws_ec2_instance_user_data_no_secrets.yaml old mode 100755 new mode 100644 index 5b9ab4d42..886a040d9 --- a/compliance/controls/aws/aws_ec2_instance_user_data_no_secrets.yaml +++ b/compliance/controls/aws/aws_ec2_instance_user_data_no_secrets.yaml @@ -1,14 +1,32 @@ +Description: User data is a metadata field of an EC2 instance that allows custom code to run after the instance is launched. It contains code which is exposed to any entity which has the most basic access to EC2, even read-only configurations. It is recommended to not use secrets in user data. ID: aws_ec2_instance_user_data_no_secrets -Title: "EC2 instances user data should not have secrets" -Description: "User data is a metadata field of an EC2 instance that allows custom code to run after the instance is launched. It contains code which is exposed to any entity which has the most basic access to EC2, even read-only configurations. It is recommended to not use secrets in user data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when user_data like any (array ['%pass%', '%secret%','%token%','%key%'])\n or user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]' then 'alarm'\n else 'ok'\n end as status,\n case\n when user_data like any (array ['%pass%', '%secret%','%token%','%key%'])\n or user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]' then instance_id ||' potential secret found in user data.'\n else instance_id || ' no secrets found in user data.'\n end as reason\n \n \nfrom\n aws_ec2_instance;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_data LIKE ANY (ARRAY ['%pass%', '%secret%', '%token%', '%key%']) + OR user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN user_data LIKE ANY (ARRAY ['%pass%', '%secret%', '%token%', '%key%']) + OR user_data ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' + THEN instance_id || ' potential secret found in user data.' + ELSE instance_id || ' no secrets found in user data.' + END AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instances user data should not have secrets \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_uses_imdsv2.yaml b/compliance/controls/aws/aws_ec2_instance_uses_imdsv2.yaml old mode 100755 new mode 100644 index 080792ed3..7ffbe8f06 --- a/compliance/controls/aws/aws_ec2_instance_uses_imdsv2.yaml +++ b/compliance/controls/aws/aws_ec2_instance_uses_imdsv2.yaml @@ -1,13 +1,30 @@ +Description: Ensure the Instance Metadata Service Version 2 (IMDSv2) method is enabled to help protect access and control of AWS Elastic Compute Cloud (AWS EC2) instance metadata. ID: aws_ec2_instance_uses_imdsv2 -Title: "EC2 instances should use IMDSv2" -Description: "Ensure the Instance Metadata Service Version 2 (IMDSv2) method is enabled to help protect access and control of AWS Elastic Compute Cloud (AWS EC2) instance metadata." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when metadata_options ->> 'HttpTokens' = 'optional' then 'alarm'\n else 'ok'\n end as status,\n case\n when metadata_options ->> 'HttpTokens' = 'optional' then title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).'\n else title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_instance;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' + ELSE title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' + END AS reason, + region, + account_id + FROM + aws_ec2_instance; Severity: high Tags: category: @@ -32,5 +49,4 @@ Tags: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: EC2 instances should use IMDSv2 \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_instance_virtualization_type_no_paravirtual.yaml b/compliance/controls/aws/aws_ec2_instance_virtualization_type_no_paravirtual.yaml old mode 100755 new mode 100644 index cfb859312..32329e34b --- a/compliance/controls/aws/aws_ec2_instance_virtualization_type_no_paravirtual.yaml +++ b/compliance/controls/aws/aws_ec2_instance_virtualization_type_no_paravirtual.yaml @@ -1,13 +1,27 @@ +Description: This control checks whether the virtualization type of an EC2 instance is paravirtual. The control fails if the virtualizationType of the EC2 instance is set to paravirtual. ID: aws_ec2_instance_virtualization_type_no_paravirtual -Title: "Paravirtual EC2 instance types should not be used" -Description: "This control checks whether the virtualization type of an EC2 instance is paravirtual. The control fails if the virtualizationType of the EC2 instance is set to paravirtual." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when virtualization_type = 'paravirtual' then 'alarm'\n else 'ok'\n end as status,\n title || ' virtualization type is ' || virtualization_type || '.' as reason\n \n , region, account_id\nfrom\n aws_ec2_instance;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN virtualization_type = 'paravirtual' THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' virtualization type is ' || virtualization_type || '.' AS reason, + region, + account_id + FROM + aws_ec2_instance; Severity: medium Tags: aws_foundational_security: @@ -22,5 +36,4 @@ Tags: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: Paravirtual EC2 instance types should not be used \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_launch_template_not_publicly_accessible.yaml b/compliance/controls/aws/aws_ec2_launch_template_not_publicly_accessible.yaml old mode 100755 new mode 100644 index 7b9946f92..491f81b99 --- a/compliance/controls/aws/aws_ec2_launch_template_not_publicly_accessible.yaml +++ b/compliance/controls/aws/aws_ec2_launch_template_not_publicly_accessible.yaml @@ -1,14 +1,49 @@ +Description: This control checks if AWS EC2 launch templates are configured to assign public IP addresses to network interfaces upon launch. The control fails if an EC2 launch template is configured to assign a public IP address to network interfaces or if there is at least one network interface that has a public IP address. ID: aws_ec2_launch_template_not_publicly_accessible -Title: "AWS EC2 launch templates should not assign public IPs to network interfaces" -Description: "This control checks if AWS EC2 launch templates are configured to assign public IP addresses to network interfaces upon launch. The control fails if an EC2 launch template is configured to assign a public IP address to network interfaces or if there is at least one network interface that has a public IP address." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with public_launch_templates as (\n select\n i.tags ->> 'aws:ec2launchtemplate:id' as public_launch_template_id\n from\n aws_ec2_instance as i,\n jsonb_array_elements(launch_template_data -> 'NetworkInterfaces') as nic\n where\n (nic -> 'AssociatePublicIpAddress')::bool\n),\nlaunch_templates_associated_instance as (\n select\n distinct tags ->> 'aws:ec2launchtemplate:id' as launch_template_id\n from\n aws_ec2_instance\n)\nselect\n t.launch_template_id as resource,\n t.og_account_id as og_account_id,\n t.og_resource_id as og_resource_id,\n case\n when i.launch_template_id is null then 'skip'\n when t.launch_template_id in ( select public_launch_template_id from public_launch_templates ) then 'alarm'\n else 'ok'\n end as status,\n case\n when i.launch_template_id is null then t.title || ' does not launch any instance.'\n when t.launch_template_id in ( select public_launch_template_id from public_launch_templates ) then t.title || ' publicly accessible.'\n else t.title || ' not publicly accessible.'\n end as reason\n \n , t.region, t.account_id\nfrom\n aws_ec2_launch_template as t\n left join launch_templates_associated_instance as i on i.launch_template_id = t.launch_template_id;\n" - PrimaryTable: aws_ec2_launch_template ListOfTables: - aws_ec2_instance - aws_ec2_launch_template Parameters: [] + PrimaryTable: aws_ec2_launch_template + QueryToExecute: | + WITH public_launch_templates AS ( + SELECT + i.tags ->> 'aws:ec2launchtemplate:id' AS public_launch_template_id + FROM + aws_ec2_instance AS i, + JSONB_ARRAY_ELEMENTS(launch_template_data -> 'NetworkInterfaces') AS nic + WHERE + (nic -> 'AssociatePublicIpAddress')::BOOL + ), + launch_templates_associated_instance AS ( + SELECT + DISTINCT tags ->> 'aws:ec2launchtemplate:id' AS launch_template_id + FROM + aws_ec2_instance + ) + SELECT + t.launch_template_id AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN i.launch_template_id IS NULL THEN 'skip' + WHEN t.launch_template_id IN (SELECT public_launch_template_id FROM public_launch_templates) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.launch_template_id IS NULL THEN t.title || ' does not launch any instance.' + WHEN t.launch_template_id IN (SELECT public_launch_template_id FROM public_launch_templates) THEN t.title || ' publicly accessible.' + ELSE t.title || ' not publicly accessible.' + END AS reason, + t.region, + t.account_id + FROM + aws_ec2_launch_template AS t + LEFT JOIN launch_templates_associated_instance AS i ON i.launch_template_id = t.launch_template_id; Severity: high Tags: aws_foundational_security: @@ -23,5 +58,4 @@ Tags: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: AWS EC2 launch templates should not assign public IPs to network interfaces \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_network_interface_unused.yaml b/compliance/controls/aws/aws_ec2_network_interface_unused.yaml old mode 100755 new mode 100644 index df53fe08f..c8ef2c85e --- a/compliance/controls/aws/aws_ec2_network_interface_unused.yaml +++ b/compliance/controls/aws/aws_ec2_network_interface_unused.yaml @@ -1,14 +1,28 @@ +Description: Identify and delete any unused Amazon AWS Elastic Network Interfaces in order to adhere to best practices and to avoid reaching the service limit. An AWS Elastic Network Interface (ENI) is pronounced unused when is not attached anymore to an EC2 instance. ID: aws_ec2_network_interface_unused -Title: "Ensure unused ENIs are removed" -Description: "Identify and delete any unused Amazon AWS Elastic Network Interfaces in order to adhere to best practices and to avoid reaching the service limit. An AWS Elastic Network Interface (ENI) is pronounced unused when is not attached anymore to an EC2 instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n network_interface_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when status = 'available' and attached_instance_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when status = 'available' and attached_instance_id is null then title || ' not in use.'\n else title || ' in use.'\n end as reason\n \n \nfrom\n aws_ec2_network_interface;" - PrimaryTable: aws_ec2_network_interface ListOfTables: - aws_ec2_network_interface Parameters: [] + PrimaryTable: aws_ec2_network_interface + QueryToExecute: | + SELECT + network_interface_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN status = 'available' AND attached_instance_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status = 'available' AND attached_instance_id IS NULL THEN title || ' not in use.' + ELSE title || ' in use.' + END AS reason + FROM + aws_ec2_network_interface; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure unused ENIs are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_stopped_instance_30_days.yaml b/compliance/controls/aws/aws_ec2_stopped_instance_30_days.yaml old mode 100755 new mode 100644 index 9ba319ee2..932beabc6 --- a/compliance/controls/aws/aws_ec2_stopped_instance_30_days.yaml +++ b/compliance/controls/aws/aws_ec2_stopped_instance_30_days.yaml @@ -1,13 +1,31 @@ +Description: Enable this rule to help with the baseline configuration of AWS Elastic Compute Cloud (AWS EC2) instances by checking whether AWS EC2 instances have been stopped for more than the allowed number of days, according to your organization's standards. ID: aws_ec2_stopped_instance_30_days -Title: "EC2 stopped instances should be removed in 30 days" -Description: "Enable this rule to help with the baseline configuration of AWS Elastic Compute Cloud (AWS EC2) instances by checking whether AWS EC2 instances have been stopped for more than the allowed number of days, according to your organization's standards." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when instance_state not in ('stopped', 'stopping') then 'skip'\n when state_transition_time <= (current_date - interval '30' day) then 'alarm'\n else 'ok'\n end as status,\n case\n when instance_state not in ('stopped', 'stopping') then title || ' is in ' || instance_state || ' state.'\n else title || ' stopped since ' || to_char(state_transition_time , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - state_transition_time) || ' days).'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_instance;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN instance_state NOT IN ('stopped', 'stopping') THEN 'skip' + WHEN state_transition_time <= (current_date - INTERVAL '30' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN instance_state NOT IN ('stopped', 'stopping') THEN title || ' is in ' || instance_state || ' state.' + ELSE title || ' stopped since ' || TO_CHAR(state_transition_time, 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM current_timestamp - state_transition_time) || ' days).' + END AS reason, + region, + account_id + FROM + aws_ec2_instance; Severity: medium Tags: category: @@ -28,17 +46,16 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: EC2 stopped instances should be removed in 30 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_stopped_instance_90_days.yaml b/compliance/controls/aws/aws_ec2_stopped_instance_90_days.yaml old mode 100755 new mode 100644 index 273bccddf..699b348cb --- a/compliance/controls/aws/aws_ec2_stopped_instance_90_days.yaml +++ b/compliance/controls/aws/aws_ec2_stopped_instance_90_days.yaml @@ -1,29 +1,29 @@ +Description: Enable this rule to help with the baseline configuration of Amazon Elastic Compute Cloud (Amazon EC2) instances by checking whether Amazon EC2 instances have been stopped for more than the allowed number of days, according to your organization's standards. ID: aws_ec2_stopped_instance_90_days -Title: "Ensure instances stopped for over 90 days are removed" -Description: "Enable this rule to help with the baseline configuration of Amazon Elastic Compute Cloud (Amazon EC2) instances by checking whether Amazon EC2 instances have been stopped for more than the allowed number of days, according to your organization's standards." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when instance_state not in ('stopped', 'stopping') then 'skip' - when state_transition_time <= (current_date - interval '90' day) then 'alarm' - else 'ok' - end as status, - case - when instance_state not in ('stopped', 'stopping') then title || ' is in ' || instance_state || ' state.' - else title || ' stopped since ' || to_char(state_transition_time , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - state_transition_time) || ' days).' - end as reason - from - aws_ec2_instance; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN instance_state NOT IN ('stopped', 'stopping') THEN 'skip' + WHEN state_transition_time <= (current_date - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN instance_state NOT IN ('stopped', 'stopping') THEN title || ' is in ' || instance_state || ' state.' + ELSE title || ' stopped since ' || TO_CHAR(state_transition_time, 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM current_timestamp - state_transition_time) || ' days).' + END AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure instances stopped for over 90 days are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_ec2_transit_gateway_auto_cross_account_attachment_disabled.yaml b/compliance/controls/aws/aws_ec2_transit_gateway_auto_cross_account_attachment_disabled.yaml old mode 100755 new mode 100644 index 2b14e411d..af01f191d --- a/compliance/controls/aws/aws_ec2_transit_gateway_auto_cross_account_attachment_disabled.yaml +++ b/compliance/controls/aws/aws_ec2_transit_gateway_auto_cross_account_attachment_disabled.yaml @@ -1,13 +1,31 @@ +Description: Ensure transit gateways have auto accept shared attachments feature disabled. If this setting is disabled, + then any VPC that attempts to attach to a transit gateway will need to request authorization, and the account that owns the transit gateway will need to accept the authorization. ID: aws_ec2_transit_gateway_auto_cross_account_attachment_disabled -Title: "EC2 transit gateways should have auto accept shared attachments disabled" -Description: "Ensure transit gateways have auto accept shared attachments feature disabled. If this setting is disabled, then any VPC that attempts to attach to a transit gateway will need to request authorization, and the account that owns the transit gateway will need to accept the authorization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n transit_gateway_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when auto_accept_shared_attachments = 'enable' then 'alarm'\n else 'ok'\n end as status,\n case\n when auto_accept_shared_attachments = 'enable' then title || ' automatic shared account attachment enabled.'\n else title || ' automatic shared account attachment disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_transit_gateway;\n" - PrimaryTable: aws_ec2_transit_gateway ListOfTables: - aws_ec2_transit_gateway Parameters: [] + PrimaryTable: aws_ec2_transit_gateway + QueryToExecute: | + SELECT + transit_gateway_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_accept_shared_attachments = 'enable' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN auto_accept_shared_attachments = 'enable' THEN title || ' automatic shared account attachment enabled.' + ELSE title || ' automatic shared account attachment disabled.' + END AS reason, + region, + account_id + FROM + aws_ec2_transit_gateway; Severity: high Tags: aws_foundational_security: @@ -22,5 +40,4 @@ Tags: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: EC2 transit gateways should have auto accept shared attachments disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecr_repository_image_scan_on_push_enabled.yaml b/compliance/controls/aws/aws_ecr_repository_image_scan_on_push_enabled.yaml old mode 100755 new mode 100644 index e5e6936fe..47b2ae5c7 --- a/compliance/controls/aws/aws_ecr_repository_image_scan_on_push_enabled.yaml +++ b/compliance/controls/aws/aws_ecr_repository_image_scan_on_push_enabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure AWS Elastic Container Registry (ECR) repositories have image scanning enabled. The rule is non-compliant if image scanning is not enabled for the ECR repository. ID: aws_ecr_repository_image_scan_on_push_enabled -Title: "ECR repositories should have image scan on push enabled" -Description: "Ensure AWS Elastic Container Registry (ECR) repositories have image scanning enabled. The rule is non-compliant if image scanning is not enabled for the ECR repository." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when image_scanning_configuration ->> 'ScanOnPush' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when image_scanning_configuration ->> 'ScanOnPush' = 'true' then title || ' scan on push enabled.'\n else title || ' scan on push disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecr_repository;\n" - PrimaryTable: aws_ecr_repository ListOfTables: - aws_ecr_repository Parameters: [] + PrimaryTable: aws_ecr_repository + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN image_scanning_configuration ->> 'ScanOnPush' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN image_scanning_configuration ->> 'ScanOnPush' = 'true' THEN title || ' scan on push enabled.' + ELSE title || ' scan on push disabled.' + END AS reason, + region, + account_id + FROM + aws_ecr_repository; Severity: high Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/ECR -IntegrationType: - - aws_cloud_account +Title: ECR repositories should have image scan on push enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecr_repository_lifecycle_policy_configured.yaml b/compliance/controls/aws/aws_ecr_repository_lifecycle_policy_configured.yaml old mode 100755 new mode 100644 index 6dbd669e6..a94021661 --- a/compliance/controls/aws/aws_ecr_repository_lifecycle_policy_configured.yaml +++ b/compliance/controls/aws/aws_ecr_repository_lifecycle_policy_configured.yaml @@ -1,13 +1,30 @@ +Description: This control checks if ECR repositories have lifecycle policy configured. This rule fails if ECR repository lifecycle policy is not enabled. ID: aws_ecr_repository_lifecycle_policy_configured -Title: "ECR repositories should have lifecycle policies configured" -Description: "This control checks if ECR repositories have lifecycle policy configured. This rule fails if ECR repository lifecycle policy is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when lifecycle_policy -> 'rules' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when lifecycle_policy -> 'rules' is not null then title || ' lifecycle policy configured.'\n else title || ' lifecycle policy not configured.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecr_repository;\n" - PrimaryTable: aws_ecr_repository ListOfTables: - aws_ecr_repository Parameters: [] + PrimaryTable: aws_ecr_repository + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN lifecycle_policy -> 'rules' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN lifecycle_policy -> 'rules' IS NOT NULL THEN title || ' lifecycle policy configured.' + ELSE title || ' lifecycle policy not configured.' + END AS reason, + region, + account_id + FROM + aws_ecr_repository; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/ECR -IntegrationType: - - aws_cloud_account +Title: ECR repositories should have lifecycle policies configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecr_repository_prohibit_public_access.yaml b/compliance/controls/aws/aws_ecr_repository_prohibit_public_access.yaml old mode 100755 new mode 100644 index 47a421f50..cd3c4ddb2 --- a/compliance/controls/aws/aws_ecr_repository_prohibit_public_access.yaml +++ b/compliance/controls/aws/aws_ecr_repository_prohibit_public_access.yaml @@ -1,46 +1,46 @@ +Description: Ensure there are no ECR repositories set as public. ID: aws_ecr_repository_prohibit_public_access -Title: "ECR repositories should prohibit public access" -Description: "Ensure there are no ECR repositories set as public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with open_access_ecr_repo as( - select - distinct arn - from + ListOfTables: + - aws_ecr_repository + Parameters: [] + PrimaryTable: aws_ecr_repository + QueryToExecute: | + WITH open_access_ecr_repo AS ( + SELECT + DISTINCT arn + FROM aws_ecr_repository, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p, - string_to_array(p, ':') as pa, - jsonb_array_elements_text(s -> 'Action') as a - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + string_to_array(p, ':') AS pa, + jsonb_array_elements_text(s -> 'Action') AS a + WHERE s ->> 'Effect' = 'Allow' - and ( + AND ( p = '*' ) ) - select - r.arn as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - when o.arn is not null then 'alarm' - else 'ok' - end as status, - case - when o.arn is not null then r.title || ' allows public access.' - else r.title || ' does not allow public access.' - end as reason - from - aws_ecr_repository as r - left join open_access_ecr_repo as o on r.arn = o.arn - group by + SELECT + r.arn AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN o.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN o.arn IS NOT NULL THEN r.title || ' allows public access.' + ELSE r.title || ' does not allow public access.' + END AS reason + FROM + aws_ecr_repository AS r + LEFT JOIN open_access_ecr_repo AS o ON r.arn = o.arn + GROUP BY resource, status, reason, r.region, r.account_id, r.tags, r._ctx, r.og_account_id, r.og_resource_id; - PrimaryTable: aws_ecr_repository - ListOfTables: - - aws_ecr_repository - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECR repositories should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecr_repository_tag_immutability_enabled.yaml b/compliance/controls/aws/aws_ecr_repository_tag_immutability_enabled.yaml old mode 100755 new mode 100644 index 73abe8a7f..78952432f --- a/compliance/controls/aws/aws_ecr_repository_tag_immutability_enabled.yaml +++ b/compliance/controls/aws/aws_ecr_repository_tag_immutability_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether a private ECR repository has tag immutability enabled. This control fails if a private ECR repository has tag immutability disabled. This rule passes if tag immutability is enabled and has the value IMMUTABLE. ID: aws_ecr_repository_tag_immutability_enabled -Title: "ECR private repositories should have tag immutability configured" -Description: "This control checks whether a private ECR repository has tag immutability enabled. This control fails if a private ECR repository has tag immutability disabled. This rule passes if tag immutability is enabled and has the value IMMUTABLE." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when image_tag_mutability = 'IMMUTABLE' then 'ok'\n else 'alarm'\n end as status,\n case\n when image_tag_mutability = 'IMMUTABLE' then title || ' tag immutability enabled.'\n else title || ' tag immutability disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecr_repository;\n" - PrimaryTable: aws_ecr_repository ListOfTables: - aws_ecr_repository Parameters: [] + PrimaryTable: aws_ecr_repository + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN image_tag_mutability = 'IMMUTABLE' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN image_tag_mutability = 'IMMUTABLE' THEN title || ' tag immutability enabled.' + ELSE title || ' tag immutability disabled.' + END AS reason, + region, + account_id + FROM + aws_ecr_repository; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/ECR -IntegrationType: - - aws_cloud_account +Title: ECR private repositories should have tag immutability configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_cluster_container_insights_enabled.yaml b/compliance/controls/aws/aws_ecs_cluster_container_insights_enabled.yaml old mode 100755 new mode 100644 index 0ed5c619e..e85b76ea7 --- a/compliance/controls/aws/aws_ecs_cluster_container_insights_enabled.yaml +++ b/compliance/controls/aws/aws_ecs_cluster_container_insights_enabled.yaml @@ -1,13 +1,31 @@ +Description: This control checks if ECS clusters use Container Insights. This control fails if Container Insights are not set up for a cluster. ID: aws_ecs_cluster_container_insights_enabled -Title: "ECS clusters should have container insights enabled" -Description: "This control checks if ECS clusters use Container Insights. This control fails if Container Insights are not set up for a cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n cluster_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when s ->> 'Name' = 'containerInsights' and s ->> 'Value' = 'enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when s ->> 'Name' = 'containerInsights' and s ->> 'Value' = 'enabled' then title || ' Container Insights enabled.'\n else title || ' Container Insights disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecs_cluster as c,\n jsonb_array_elements(settings) as s;\n" - PrimaryTable: aws_ecs_cluster ListOfTables: - aws_ecs_cluster Parameters: [] + PrimaryTable: aws_ecs_cluster + QueryToExecute: | + SELECT + cluster_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN s ->> 'Name' = 'containerInsights' AND s ->> 'Value' = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s ->> 'Name' = 'containerInsights' AND s ->> 'Value' = 'enabled' THEN title || ' Container Insights enabled.' + ELSE title || ' Container Insights disabled.' + END AS reason, + region, + account_id + FROM + aws_ecs_cluster AS c, + jsonb_array_elements(settings) AS s; Severity: medium Tags: aws_foundational_security: @@ -22,5 +40,4 @@ Tags: - aws service: - AWS/ECS -IntegrationType: - - aws_cloud_account +Title: ECS clusters should have container insights enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_cluster_container_instance_agent_connected.yaml b/compliance/controls/aws/aws_ecs_cluster_container_instance_agent_connected.yaml old mode 100755 new mode 100644 index 7fc365bd4..687be7235 --- a/compliance/controls/aws/aws_ecs_cluster_container_instance_agent_connected.yaml +++ b/compliance/controls/aws/aws_ecs_cluster_container_instance_agent_connected.yaml @@ -1,40 +1,44 @@ +Description: This control checks if ECS cluster container instances have connected agent. This control fails if the agent is not connected. ID: aws_ecs_cluster_container_instance_agent_connected -Title: "ECS cluster container instances should have connected agent" -Description: "This control checks if ECS cluster container instances have connected agent. This control fails if the agent is not connected." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with unconnected_agent_instance as ( - select - distinct cluster_arn - from - aws_ecs_container_instance - where - agent_connected = false and status = 'ACTIVE' - ) - select - c.cluster_arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when c.registered_container_instances_count = 0 then 'skip' - when i.cluster_arn is null then 'ok' - else 'alarm' - end as status, - case - when c.registered_container_instances_count = 0 then title || ' has no container instance registered.' - when i.cluster_arn is null then title || ' container instance has connected agent.' - else title || ' container instance is either draining or has unconnected agents.' - end as reason - from - aws_ecs_cluster as c - left join unconnected_agent_instance as i on c.cluster_arn = i.cluster_arn; - PrimaryTable: aws_ecs_cluster ListOfTables: - aws_ecs_cluster - aws_ecs_container_instance Parameters: [] + PrimaryTable: aws_ecs_cluster + QueryToExecute: | + WITH unconnected_agent_instance AS ( + SELECT + DISTINCT cluster_arn + FROM + aws_ecs_container_instance + WHERE + agent_connected = FALSE + AND status = 'ACTIVE' + ) + SELECT + c.cluster_arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.registered_container_instances_count = 0 THEN 'skip' + WHEN i.cluster_arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.registered_container_instances_count = 0 THEN title || ' has no container instance registered.' + WHEN i.cluster_arn IS NULL THEN title || ' container instance has connected agent.' + ELSE title || ' container instance is either draining or has unconnected agents.' + END AS reason + FROM + aws_ecs_cluster AS c + LEFT JOIN + unconnected_agent_instance AS i + ON + c.cluster_arn = i.cluster_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECS cluster container instances should have connected agent \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_cluster_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_ecs_cluster_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 20df559a6..742e3171a --- a/compliance/controls/aws/aws_ecs_cluster_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_ecs_cluster_encryption_at_rest_enabled.yaml @@ -1,47 +1,47 @@ +Description: This control checks whether ECS Clustes have encryption at rest enabled. The check fails if encryption at rest is not enabled as sensitive data should be protected. ID: aws_ecs_cluster_encryption_at_rest_enabled -Title: "ECS clusters encryption at rest should be enabled" -Description: "This control checks whether ECS Clustes have encryption at rest enabled. The check fails if encryption at rest is not enabled as sensitive data should be protected." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with unencrypted_volumes as ( - select - distinct cluster_arn - from - aws_ecs_container_instance as i, - aws_ec2_instance as e, - jsonb_array_elements(block_device_mappings) as b, - aws_ebs_volume as v - where - i.ec2_instance_id = e.instance_id - and b -> 'Ebs' ->> 'VolumeId' = v.volume_id - and not v.encrypted - ) - select - c.cluster_arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when c.registered_container_instances_count = 0 then 'skip' - when v.cluster_arn is not null then 'alarm' - else 'ok' - end as status, - case - when c.registered_container_instances_count = 0 then title || ' has no container instance registered.' - when v.cluster_arn is not null then c.title || ' encryption at rest disabled.' - else c.title || ' encryption at rest enabled.' - end as reason - from - aws_ecs_cluster as c - left join unencrypted_volumes as v on v.cluster_arn = c.cluster_arn; - PrimaryTable: aws_ecs_cluster ListOfTables: - aws_ecs_container_instance - aws_ec2_instance - aws_ebs_volume - aws_ecs_cluster Parameters: [] + PrimaryTable: aws_ecs_cluster + QueryToExecute: | + WITH unencrypted_volumes AS ( + SELECT + DISTINCT cluster_arn + FROM + aws_ecs_container_instance AS i, + aws_ec2_instance AS e, + JSONB_ARRAY_ELEMENTS(block_device_mappings) AS b, + aws_ebs_volume AS v + WHERE + i.ec2_instance_id = e.instance_id + AND b -> 'Ebs' ->> 'VolumeId' = v.volume_id + AND NOT v.encrypted + ) + SELECT + c.cluster_arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.registered_container_instances_count = 0 THEN 'skip' + WHEN v.cluster_arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.registered_container_instances_count = 0 THEN c.title || ' has no container instance registered.' + WHEN v.cluster_arn IS NOT NULL THEN c.title || ' encryption at rest disabled.' + ELSE c.title || ' encryption at rest enabled.' + END AS reason + FROM + aws_ecs_cluster AS c + LEFT JOIN unencrypted_volumes AS v ON v.cluster_arn = c.cluster_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECS clusters encryption at rest should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_cluster_no_active_services_count.yaml b/compliance/controls/aws/aws_ecs_cluster_no_active_services_count.yaml old mode 100755 new mode 100644 index 0547b0cb8..9eae060d3 --- a/compliance/controls/aws/aws_ecs_cluster_no_active_services_count.yaml +++ b/compliance/controls/aws/aws_ecs_cluster_no_active_services_count.yaml @@ -1,28 +1,28 @@ +Description: This control checks if ECS cluster have active services. This control fails if ECS cluster does not have any active services. ID: aws_ecs_cluster_no_active_services_count -Title: "ECS cluster should be configured with active services" -Description: "This control checks if ECS cluster have active services. This control fails if ECS cluster does not have any active services." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - cluster_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when active_services_count > 0 then 'ok' - else 'alarm' - end as status, - case - when active_services_count > 0 then title || ' has ' || active_services_count || ' active service(s).' - else title || ' has no active service.' - end as reason - from - aws_ecs_cluster; - PrimaryTable: aws_ecs_cluster ListOfTables: - aws_ecs_cluster Parameters: [] + PrimaryTable: aws_ecs_cluster + QueryToExecute: | + SELECT + cluster_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN active_services_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN active_services_count > 0 THEN title || ' has ' || active_services_count || ' active service(s).' + ELSE title || ' has no active service.' + END AS reason + FROM + aws_ecs_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECS cluster should be configured with active services \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_cluster_no_registered_container_instance.yaml b/compliance/controls/aws/aws_ecs_cluster_no_registered_container_instance.yaml old mode 100755 new mode 100644 index ce3fa39e3..e7bcecbdd --- a/compliance/controls/aws/aws_ecs_cluster_no_registered_container_instance.yaml +++ b/compliance/controls/aws/aws_ecs_cluster_no_registered_container_instance.yaml @@ -1,28 +1,28 @@ +Description: This control ensures that at least one container instance is registered with an ECS cluster. ID: aws_ecs_cluster_no_registered_container_instance -Title: "At least one instance should be registered with ECS cluster" -Description: "This control ensures that at least one container instance is registered with an ECS cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - cluster_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when registered_container_instances_count = 0 then 'alarm' - else 'ok' - end as status, - case - when registered_container_instances_count = 0 then title || ' has no container instance registered.' - else title || ' has ' || registered_container_instances_count || ' container instance(s) registered.' - end as reason - from - aws_ecs_cluster; - PrimaryTable: aws_ecs_cluster ListOfTables: - aws_ecs_cluster Parameters: [] + PrimaryTable: aws_ecs_cluster + QueryToExecute: | + SELECT + cluster_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN registered_container_instances_count = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN registered_container_instances_count = 0 THEN title || ' has no container instance registered.' + ELSE title || ' has ' || registered_container_instances_count || ' container instance(s) registered.' + END AS reason + FROM + aws_ecs_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: At least one instance should be registered with ECS cluster \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_service_fargate_using_latest_platform_version.yaml b/compliance/controls/aws/aws_ecs_service_fargate_using_latest_platform_version.yaml old mode 100755 new mode 100644 index 862ed9280..6fa4e56cf --- a/compliance/controls/aws/aws_ecs_service_fargate_using_latest_platform_version.yaml +++ b/compliance/controls/aws/aws_ecs_service_fargate_using_latest_platform_version.yaml @@ -1,13 +1,32 @@ +Description: This control checks if AWS ECS Fargate services are running the latest Fargate platform version. This control fails if the platform version is not the latest. ID: aws_ecs_service_fargate_using_latest_platform_version -Title: "ECS fargate services should run on the latest fargate platform version" -Description: "This control checks if AWS ECS Fargate services are running the latest Fargate platform version. This control fails if the platform version is not the latest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when launch_type <> 'FARGATE' then 'skip'\n when platform_version = 'LATEST' then 'ok'\n else 'alarm'\n end as status,\n case\n when launch_type <> 'FARGATE' then title || ' is ' || launch_type || ' service.'\n when platform_version = 'LATEST' then title || ' running on the latest fargate platform version.'\n else title || ' not running on the latest fargate platform version.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecs_service;\n" - PrimaryTable: aws_ecs_service ListOfTables: - aws_ecs_service Parameters: [] + PrimaryTable: aws_ecs_service + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN launch_type <> 'FARGATE' THEN 'skip' + WHEN platform_version = 'LATEST' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN launch_type <> 'FARGATE' THEN title || ' is ' || launch_type || ' service.' + WHEN platform_version = 'LATEST' THEN title || ' running on the latest Fargate platform version.' + ELSE title || ' not running on the latest Fargate platform version.' + END AS reason, + region, + account_id + FROM + aws_ecs_service; Severity: medium Tags: aws_foundational_security: @@ -22,5 +41,4 @@ Tags: - aws service: - AWS/ECS -IntegrationType: - - aws_cloud_account +Title: ECS Fargate services should run on the latest Fargate platform version \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_service_load_balancer_attached.yaml b/compliance/controls/aws/aws_ecs_service_load_balancer_attached.yaml old mode 100755 new mode 100644 index 981dec83b..684930e5e --- a/compliance/controls/aws/aws_ecs_service_load_balancer_attached.yaml +++ b/compliance/controls/aws/aws_ecs_service_load_balancer_attached.yaml @@ -1,14 +1,28 @@ +Description: ECS service can be configured to use Elastic Load Balancing to distribute traffic evenly across the tasks in your service. It is recommended to use Application Load Balancers for your AWS ECS services so that you can take advantage of these latest features, unless your service requires a feature that is only available with Network Load Balancers or Classic Load Balancers. ID: aws_ecs_service_load_balancer_attached -Title: "ECS services should be attached to a load balancer" -Description: "ECS service can be configured to use Elastic Load Balancing to distribute traffic evenly across the tasks in your service. It is recommended to use Application Load Balancers for your AWS ECS services so that you can take advantage of these latest features, unless your service requires a feature that is only available with Network Load Balancers or Classic Load Balancers." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(load_balancers) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when jsonb_array_length(load_balancers) = 0 then title || ' has no load balancer attached.'\n else title || ' has ' || jsonb_array_length(load_balancers) || ' load balancer(s) attached.'\n end as reason\n \n \nfrom\n aws_ecs_service;" - PrimaryTable: aws_ecs_service ListOfTables: - aws_ecs_service Parameters: [] + PrimaryTable: aws_ecs_service + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(load_balancers) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN jsonb_array_length(load_balancers) = 0 THEN title || ' has no load balancer attached.' + ELSE title || ' has ' || jsonb_array_length(load_balancers) || ' load balancer(s) attached.' + END AS reason + FROM + aws_ecs_service; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECS services should be attached to a load balancer \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_service_not_publicly_accessible.yaml b/compliance/controls/aws/aws_ecs_service_not_publicly_accessible.yaml old mode 100755 new mode 100644 index 7f94599df..a8b307d74 --- a/compliance/controls/aws/aws_ecs_service_not_publicly_accessible.yaml +++ b/compliance/controls/aws/aws_ecs_service_not_publicly_accessible.yaml @@ -1,14 +1,46 @@ +Description: This control checks whether AWS ECS services are configured to automatically assign public IP addresses. This control fails if AssignPublicIP is enabled. ID: aws_ecs_service_not_publicly_accessible -Title: "AWS ECS services should not have public IP addresses assigned to them automatically" -Description: "This control checks whether AWS ECS services are configured to automatically assign public IP addresses. This control fails if AssignPublicIP is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with service_awsvpc_mode_task_definition as (\n select\n a.service_name as service_name,\n b.task_definition_arn as task_definition\n from\n aws_ecs_service as a\n left join aws_ecs_task_definition as b on a.task_definition = b.task_definition_arn\n where\n b.network_mode = 'awsvpc'\n)\nselect\n a.arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.service_name is null then 'skip'\n when network_configuration -> 'AwsvpcConfiguration' ->> 'AssignPublicIp' = 'DISABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when b.service_name is null then a.title || ' task definition not host network mode.'\n when network_configuration -> 'AwsvpcConfiguration' ->> 'AssignPublicIp' = 'DISABLED' then a.title || ' not publicly accessible.'\n else a.title || ' publicly accessible.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecs_service as a\n left join service_awsvpc_mode_task_definition as b on a.service_name = b.service_name;\n" - PrimaryTable: aws_ecs_service ListOfTables: - aws_ecs_service - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_service + QueryToExecute: | + WITH service_awsvpc_mode_task_definition AS ( + SELECT + a.service_name AS service_name, + b.task_definition_arn AS task_definition + FROM + aws_ecs_service AS a + LEFT JOIN aws_ecs_task_definition AS b + ON a.task_definition = b.task_definition_arn + WHERE + b.network_mode = 'awsvpc' + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.service_name IS NULL THEN 'skip' + WHEN network_configuration -> 'AwsvpcConfiguration' ->> 'AssignPublicIp' = 'DISABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.service_name IS NULL THEN a.title || ' task definition not host network mode.' + WHEN network_configuration -> 'AwsvpcConfiguration' ->> 'AssignPublicIp' = 'DISABLED' THEN a.title || ' not publicly accessible.' + ELSE a.title || ' publicly accessible.' + END AS reason, + region, + account_id + FROM + aws_ecs_service AS a + LEFT JOIN service_awsvpc_mode_task_definition AS b + ON a.service_name = b.service_name Severity: high Tags: aws_foundational_security: @@ -23,5 +55,4 @@ Tags: - aws service: - AWS/ECS -IntegrationType: - - aws_cloud_account +Title: AWS ECS services should not have public IP addresses assigned to them automatically \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_task_definition_container_environment_no_secret.yaml b/compliance/controls/aws/aws_ecs_task_definition_container_environment_no_secret.yaml old mode 100755 new mode 100644 index 0820d0ead..cbe3630cc --- a/compliance/controls/aws/aws_ecs_task_definition_container_environment_no_secret.yaml +++ b/compliance/controls/aws/aws_ecs_task_definition_container_environment_no_secret.yaml @@ -1,13 +1,64 @@ +Description: This control checks if the key value of any variables in the environment parameter of container definitions includes AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. This control fails if a single environment variable in any container definition equals AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. This control does not cover environmental variables passed in from other locations such as AWS S3. ID: aws_ecs_task_definition_container_environment_no_secret -Title: "ECS task definition containers should not have secrets passed as environment variables" -Description: "This control checks if the key value of any variables in the environment parameter of container definitions includes AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. This control fails if a single environment variable in any container definition equals AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. This control does not cover environmental variables passed in from other locations such as AWS S3." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with definitions_with_secret_environment_variable as (\n select\n distinct task_definition_arn as arn\n from\n aws_ecs_task_definition,\n jsonb_array_elements(container_definitions) as c,\n jsonb_array_elements(\n case jsonb_typeof(c -> 'Environment')\n when 'array' then (c -> 'Environment')\n else null end\n ) as s\n where\n s ->> 'Name' like any (array ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY','ECS_ENGINE_AUTH_DATA'])\n UNION\n select\n distinct task_definition_arn as arn\n from\n aws_ecs_task_definition,\n jsonb_array_elements(container_definitions) as c,\n jsonb_array_elements(\n case jsonb_typeof(c -> 'Secrets')\n when 'array' then (c -> 'Secrets')\n else null end\n ) as s\n where\n s ->> 'Name' like any (array ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY','ECS_ENGINE_AUTH_DATA'])\n)\nselect\n d.task_definition_arn as resource,\n d.og_account_id as og_account_id,\n d.og_resource_id as og_resource_id,\n case\n when e.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when e.arn is null then d.title || ' container environment variables does not have secrets.'\n else d.title || ' container environment variables have secrets.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecs_task_definition as d\n left join definitions_with_secret_environment_variable as e on d.task_definition_arn = e.arn;\n" - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH definitions_with_secret_environment_variable AS ( + SELECT DISTINCT + task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c, + jsonb_array_elements( + CASE jsonb_typeof(c -> 'Environment') + WHEN 'array' THEN (c -> 'Environment') + ELSE NULL + END + ) AS s + WHERE + s ->> 'Name' LIKE ANY (ARRAY ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'ECS_ENGINE_AUTH_DATA']) + + UNION + + SELECT DISTINCT + task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c, + jsonb_array_elements( + CASE jsonb_typeof(c -> 'Secrets') + WHEN 'array' THEN (c -> 'Secrets') + ELSE NULL + END + ) AS s + WHERE + s ->> 'Name' LIKE ANY (ARRAY ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'ECS_ENGINE_AUTH_DATA']) + ) + + SELECT + d.task_definition_arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN e.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN e.arn IS NULL THEN d.title || ' container environment variables does not have secrets.' + ELSE d.title || ' container environment variables have secrets.' + END AS reason, + region, + account_id + FROM + aws_ecs_task_definition AS d + LEFT JOIN definitions_with_secret_environment_variable AS e + ON d.task_definition_arn = e.arn; Severity: high Tags: aws_foundational_security: @@ -22,5 +73,4 @@ Tags: - aws service: - AWS/ECS -IntegrationType: - - aws_cloud_account +Title: ECS task definition containers should not have secrets passed as environment variables \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_task_definition_container_non_privileged.yaml b/compliance/controls/aws/aws_ecs_task_definition_container_non_privileged.yaml old mode 100755 new mode 100644 index d40ebe4bb..2e95e5f34 --- a/compliance/controls/aws/aws_ecs_task_definition_container_non_privileged.yaml +++ b/compliance/controls/aws/aws_ecs_task_definition_container_non_privileged.yaml @@ -1,13 +1,43 @@ +Description: This control checks if the privileged parameter in the container definition of AWS ECS Task Definitions is set to true. The control fails if this parameter is equal to true. ID: aws_ecs_task_definition_container_non_privileged -Title: "ECS containers should run as non-privileged" -Description: "This control checks if the privileged parameter in the container definition of AWS ECS Task Definitions is set to true. The control fails if this parameter is equal to true." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with privileged_container_definition as (\n select\n distinct task_definition_arn as arn\n from\n aws_ecs_task_definition,\n jsonb_array_elements(container_definitions) as c\n where\n c ->> 'Privileged' = 'true'\n)\nselect\n d.task_definition_arn as resource,\n d.og_account_id as og_account_id,\n d.og_resource_id as og_resource_id,\n case\n when c.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when c.arn is null then d.title || ' does not have elevated privileges.'\n else d.title || ' has elevated privileges.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecs_task_definition as d\n left join privileged_container_definition as c on d.task_definition_arn = c.arn;\n" - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH privileged_container_definition AS ( + SELECT DISTINCT + task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c + WHERE + c ->> 'Privileged' = 'true' + ) + SELECT + d.task_definition_arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN c.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.arn IS NULL THEN d.title || ' does not have elevated privileges.' + ELSE d.title || ' has elevated privileges.' + END AS reason, + region, + account_id + FROM + aws_ecs_task_definition AS d + LEFT JOIN + privileged_container_definition AS c + ON + d.task_definition_arn = c.arn; Severity: high Tags: aws_foundational_security: @@ -22,5 +52,4 @@ Tags: - aws service: - AWS/ECS -IntegrationType: - - aws_cloud_account +Title: ECS containers should run as non-privileged \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_task_definition_container_readonly_root_filesystem.yaml b/compliance/controls/aws/aws_ecs_task_definition_container_readonly_root_filesystem.yaml old mode 100755 new mode 100644 index 3e0bc654e..74611e83c --- a/compliance/controls/aws/aws_ecs_task_definition_container_readonly_root_filesystem.yaml +++ b/compliance/controls/aws/aws_ecs_task_definition_container_readonly_root_filesystem.yaml @@ -1,13 +1,43 @@ +Description: This control checks if ECS containers are limited to read-only access to mounted root filesystems. This control fails if the ReadonlyRootFilesystem parameter in the container definition of ECS task definitions is set to false. ID: aws_ecs_task_definition_container_readonly_root_filesystem -Title: "ECS containers should be limited to read-only access to root filesystems" -Description: "This control checks if ECS containers are limited to read-only access to mounted root filesystems. This control fails if the ReadonlyRootFilesystem parameter in the container definition of ECS task definitions is set to false." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with privileged_container_definition as (\n select\n distinct task_definition_arn as arn\n from\n aws_ecs_task_definition,\n jsonb_array_elements(container_definitions) as c\n where\n c ->> 'ReadonlyRootFilesystem' = 'true'\n)\nselect\n d.task_definition_arn as resource,\n d.og_account_id as og_account_id,\n d.og_resource_id as og_resource_id,\n case\n when c.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when c.arn is not null then d.title || ' containers limited to read-only access to root filesystems.'\n else d.title || ' containers not limited to read-only access to root filesystems.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecs_task_definition as d\n left join privileged_container_definition as c on d.task_definition_arn = c.arn;\n" - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH privileged_container_definition AS ( + SELECT DISTINCT + task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c + WHERE + c ->> 'ReadonlyRootFilesystem' = 'true' + ) + SELECT + d.task_definition_arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN c.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.arn IS NOT NULL THEN d.title || ' containers limited to read-only access to root filesystems.' + ELSE d.title || ' containers not limited to read-only access to root filesystems.' + END AS reason, + region, + account_id + FROM + aws_ecs_task_definition AS d + LEFT JOIN + privileged_container_definition AS c + ON + d.task_definition_arn = c.arn; Severity: high Tags: aws_foundational_security: @@ -22,5 +52,4 @@ Tags: - aws service: - AWS/ECS -IntegrationType: - - aws_cloud_account +Title: ECS containers should be limited to read-only access to root filesystems \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_task_definition_logging_enabled.yaml b/compliance/controls/aws/aws_ecs_task_definition_logging_enabled.yaml old mode 100755 new mode 100644 index 9d8abbf5a..5e4887c4f --- a/compliance/controls/aws/aws_ecs_task_definition_logging_enabled.yaml +++ b/compliance/controls/aws/aws_ecs_task_definition_logging_enabled.yaml @@ -1,14 +1,39 @@ +Description: Ensure logging is enabled for task definitions so that you can access your containerized application logs for debugging and auditing purposes. On top of centralized logging, these log drivers often include additional capabilities that are useful for operation. ID: aws_ecs_task_definition_logging_enabled -Title: "ECS task definitions should have logging enabled" -Description: "Ensure logging is enabled for task definitions so that you can access your containerized application logs for debugging and auditing purposes. On top of centralized logging, these log drivers often include additional capabilities that are useful for operation." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with task_definitions_logging_enabled as (\n select\n distinct task_definition_arn as arn\n from\n aws_ecs_task_definition,\n jsonb_array_elements(container_definitions) as c\n where\n c ->> 'LogConfiguration' is not null\n)\nselect\n a.task_definition_arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is not null then a.title || ' logging enabled.'\n else a.title || ' logging disabled.'\n end as reason\n \n \nfrom\n aws_ecs_task_definition as a\n left join task_definitions_logging_enabled as b on a.task_definition_arn = b.arn;" - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH task_definitions_logging_enabled AS ( + SELECT + DISTINCT task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c + WHERE + c ->> 'LogConfiguration' IS NOT NULL + ) + SELECT + a.task_definition_arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NOT NULL THEN a.title || ' logging enabled.' + ELSE a.title || ' logging disabled.' + END AS reason + FROM + aws_ecs_task_definition AS a + LEFT JOIN task_definitions_logging_enabled AS b + ON a.task_definition_arn = b.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECS task definitions should have logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_task_definition_no_host_pid_mode.yaml b/compliance/controls/aws/aws_ecs_task_definition_no_host_pid_mode.yaml old mode 100755 new mode 100644 index 5e2237948..2dc8f45ce --- a/compliance/controls/aws/aws_ecs_task_definition_no_host_pid_mode.yaml +++ b/compliance/controls/aws/aws_ecs_task_definition_no_host_pid_mode.yaml @@ -1,13 +1,30 @@ +Description: This control checks if AWS ECS task definitions are configured to share a host's process namespace with its containers. The control fails if the task definition shares the host's process namespace with the containers running on it. ID: aws_ecs_task_definition_no_host_pid_mode -Title: "ECS task definitions should not share the host's process namespace" -Description: "This control checks if AWS ECS task definitions are configured to share a host's process namespace with its containers. The control fails if the task definition shares the host's process namespace with the containers running on it." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n task_definition_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when pid_mode = 'host' then 'alarm'\n else 'ok'\n end as status,\n case\n when pid_mode = 'host' then title || ' shares the host process namespace.'\n else title || ' does not share the host process namespace.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecs_task_definition;\n" - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + SELECT + task_definition_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN pid_mode = 'host' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN pid_mode = 'host' THEN title || ' shares the host process namespace.' + ELSE title || ' does not share the host process namespace.' + END AS reason, + region, + account_id + FROM + aws_ecs_task_definition; Severity: high Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/ECS -IntegrationType: - - aws_cloud_account +Title: ECS task definitions should not share the host's process namespace \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_task_definition_no_root_user.yaml b/compliance/controls/aws/aws_ecs_task_definition_no_root_user.yaml old mode 100755 new mode 100644 index 4b267c189..ee9cf6c4a --- a/compliance/controls/aws/aws_ecs_task_definition_no_root_user.yaml +++ b/compliance/controls/aws/aws_ecs_task_definition_no_root_user.yaml @@ -1,38 +1,41 @@ +Description: This control checks if ECS task definitions have root user. This control fails if the ECS task definitions have root user. ID: aws_ecs_task_definition_no_root_user -Title: "ECS task definitions should not use root user." -Description: "This control checks if ECS task definitions have root user. This control fails if the ECS task definitions have root user." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with root_user_task_definition as ( - select - distinct task_definition_arn as arn - from - aws_ecs_task_definition, - jsonb_array_elements(container_definitions) as c - where - c ->> 'User' = 'root' - ) - select - a.task_definition_arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.arn is not null then 'alarm' - else 'ok' - end as status, - case - when b.arn is not null then a.title || ' have root user.' - else a.title || ' does not have root user.' - end as reason - from - aws_ecs_task_definition as a - left join root_user_task_definition as b on a.task_definition_arn = b.arn; - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH root_user_task_definition AS ( + SELECT DISTINCT + task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c + WHERE + c ->> 'User' = 'root' + ) + SELECT + a.task_definition_arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.arn IS NOT NULL THEN a.title || ' have root user.' + ELSE a.title || ' does not have root user.' + END AS reason + FROM + aws_ecs_task_definition AS a + LEFT JOIN + root_user_task_definition AS b + ON + a.task_definition_arn = b.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECS task definitions should not use root user. \ No newline at end of file diff --git a/compliance/controls/aws/aws_ecs_task_definition_user_for_host_mode_check.yaml b/compliance/controls/aws/aws_ecs_task_definition_user_for_host_mode_check.yaml old mode 100755 new mode 100644 index 607a7e1e7..f1a6fffd1 --- a/compliance/controls/aws/aws_ecs_task_definition_user_for_host_mode_check.yaml +++ b/compliance/controls/aws/aws_ecs_task_definition_user_for_host_mode_check.yaml @@ -1,13 +1,49 @@ +Description: Check if AWS Elastic Container Service (AWS ECS) task definition with host networking mode has 'privileged' or 'user' container definitions. The rule is non-compliant for task definitions with host network mode and container definitions of privileged. ID: aws_ecs_task_definition_user_for_host_mode_check -Title: "ECS task definition container definitions should be checked for host mode" -Description: "Check if AWS Elastic Container Service (AWS ECS) task definition with host networking mode has 'privileged' or 'user' container definitions.The rule is non-compliant for task definitions with host network mode and container definitions of privileged" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with host_network_task_definition as (\n select\n distinct task_definition_arn as arn\n from\n aws_ecs_task_definition,\n jsonb_array_elements(container_definitions) as c\n where\n network_mode = 'host'\n and\n (c ->> 'Privileged' is not null\n and c ->> 'Privileged' <> 'false'\n )\n and\n ( c ->> 'User' is not null\n and c ->> 'User' <> 'root'\n )\n)\nselect\n a.task_definition_arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.network_mode is null or a.network_mode <> 'host' then 'skip'\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.network_mode is null or a.network_mode <> 'host' then a.title || ' not host network mode.'\n when b.arn is not null then a.title || ' have secure host network mode.'\n else a.title || ' not have secure host network mode.'\n end as reason\n \n , region, account_id\nfrom\n aws_ecs_task_definition as a\n left join host_network_task_definition as b on a.task_definition_arn = b.arn;\n" - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH host_network_task_definition AS ( + SELECT + DISTINCT task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c + WHERE + network_mode = 'host' + AND (c ->> 'Privileged' IS NOT NULL + AND c ->> 'Privileged' <> 'false' + ) + AND (c ->> 'User' IS NOT NULL + AND c ->> 'User' <> 'root' + ) + ) + SELECT + a.task_definition_arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.network_mode IS NULL OR a.network_mode <> 'host' THEN 'skip' + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.network_mode IS NULL OR a.network_mode <> 'host' THEN a.title || ' not host network mode.' + WHEN b.arn IS NOT NULL THEN a.title || ' have secure host network mode.' + ELSE a.title || ' not have secure host network mode.' + END AS reason, + region, + account_id + FROM + aws_ecs_task_definition AS a + LEFT JOIN host_network_task_definition AS b + ON a.task_definition_arn = b.arn; Severity: high Tags: category: @@ -26,15 +62,14 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: - aws service: - AWS/ECS -IntegrationType: - - aws_cloud_account +Title: ECS task definition container definitions should be checked for host mode \ No newline at end of file diff --git a/compliance/controls/aws/aws_efs_access_point_enforce_root_directory.yaml b/compliance/controls/aws/aws_efs_access_point_enforce_root_directory.yaml old mode 100755 new mode 100644 index 3de1a6260..b73963dab --- a/compliance/controls/aws/aws_efs_access_point_enforce_root_directory.yaml +++ b/compliance/controls/aws/aws_efs_access_point_enforce_root_directory.yaml @@ -1,13 +1,30 @@ +Description: This control checks if AWS EFS access points are configured to enforce a root directory. The control fails if the value of Path is set to / (the default root directory of the file system). ID: aws_efs_access_point_enforce_root_directory -Title: "EFS access points should enforce a root directory" -Description: "This control checks if AWS EFS access points are configured to enforce a root directory. The control fails if the value of Path is set to / (the default root directory of the file system)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n access_point_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when root_directory ->> 'Path'= '/' then 'alarm'\n else 'ok'\n end as status,\n case\n when root_directory ->> 'Path'= '/' then title || ' not configured to enforce a root directory.'\n else title || ' configured to enforce a root directory.'\n end as reason\n \n , region, account_id\nfrom\n aws_efs_access_point;\n" - PrimaryTable: aws_efs_access_point ListOfTables: - aws_efs_access_point Parameters: [] + PrimaryTable: aws_efs_access_point + QueryToExecute: | + SELECT + access_point_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN root_directory ->> 'Path' = '/' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN root_directory ->> 'Path' = '/' THEN title || ' not configured to enforce a root directory.' + ELSE title || ' configured to enforce a root directory.' + END AS reason, + region, + account_id + FROM + aws_efs_access_point; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/EFS -IntegrationType: - - aws_cloud_account +Title: EFS access points should enforce a root directory \ No newline at end of file diff --git a/compliance/controls/aws/aws_efs_access_point_enforce_user_identity.yaml b/compliance/controls/aws/aws_efs_access_point_enforce_user_identity.yaml old mode 100755 new mode 100644 index 9d10283de..4634a7a6f --- a/compliance/controls/aws/aws_efs_access_point_enforce_user_identity.yaml +++ b/compliance/controls/aws/aws_efs_access_point_enforce_user_identity.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether AWS EFS access points are configured to enforce a user identity. This control fails if a POSIX user identity is not defined while creating the EFS access point. ID: aws_efs_access_point_enforce_user_identity -Title: "EFS access points should enforce a user identity" -Description: "This control checks whether AWS EFS access points are configured to enforce a user identity. This control fails if a POSIX user identity is not defined while creating the EFS access point." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n access_point_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when posix_user is null then 'alarm'\n else 'ok'\n end as status,\n case\n when posix_user is null then title || ' does not enforce a user identity.'\n else title || ' enforces a user identity.'\n end as reason\n \n , region, account_id\nfrom\n aws_efs_access_point;\n" - PrimaryTable: aws_efs_access_point ListOfTables: - aws_efs_access_point Parameters: [] + PrimaryTable: aws_efs_access_point + QueryToExecute: | + SELECT + access_point_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN posix_user IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN posix_user IS NULL THEN title || ' does not enforce a user identity.' + ELSE title || ' enforces a user identity.' + END AS reason, + region, + account_id + FROM + aws_efs_access_point; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/EFS -IntegrationType: - - aws_cloud_account +Title: EFS access points should enforce a user identity \ No newline at end of file diff --git a/compliance/controls/aws/aws_efs_file_system_encrypt_data_at_rest.yaml b/compliance/controls/aws/aws_efs_file_system_encrypt_data_at_rest.yaml old mode 100755 new mode 100644 index 6f4354a8f..ac9f07fe8 --- a/compliance/controls/aws/aws_efs_file_system_encrypt_data_at_rest.yaml +++ b/compliance/controls/aws/aws_efs_file_system_encrypt_data_at_rest.yaml @@ -1,13 +1,30 @@ +Description: Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your AWS Elastic File System (EFS). ID: aws_efs_file_system_encrypt_data_at_rest -Title: "EFS file system encryption at rest should be enabled" -Description: "Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your AWS Elastic File System (EFS)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n , region, account_id\nfrom\n aws_efs_file_system;\n" - PrimaryTable: aws_efs_file_system ListOfTables: - aws_efs_file_system Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason, + region, + account_id + FROM + aws_efs_file_system; Severity: high Tags: category: @@ -28,5 +45,4 @@ Tags: - aws service: - AWS/EFS -IntegrationType: - - aws_cloud_account +Title: EFS file system encryption at rest should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_efs_file_system_encrypted_with_cmk.yaml b/compliance/controls/aws/aws_efs_file_system_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index db1e1023e..011a5cfb1 --- a/compliance/controls/aws/aws_efs_file_system_encrypted_with_cmk.yaml +++ b/compliance/controls/aws/aws_efs_file_system_encrypted_with_cmk.yaml @@ -1,14 +1,44 @@ +Description: Ensure AWS Elastic File Systems (AWS EFS) are encrypted using CMK. The rule is non-compliant if the EFS File System is not encrypted using CMK. ID: aws_efs_file_system_encrypted_with_cmk -Title: "EFS file systems should be encrypted with CMK" -Description: "Ensure AWS Elastic File Systems (AWS EFS) are encrypted using CMK. The rule is non-compliant if the EFS File System is not encrypted using CMK." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with encrypted_fs as (\n select\n fs.arn as arn,\n key_manager\n from\n aws_efs_file_system as fs\n left join aws_kms_key as k on fs.kms_key_id = k.arn\n where\n enabled\n)\nselect\n f.arn as resource,\n f.og_account_id as og_account_id,\n f.og_resource_id as og_resource_id,\n case\n when not encrypted then 'alarm'\n when encrypted and e.key_manager = 'CUSTOMER' then 'ok'\n else 'alarm'\n end as status,\n case\n when not encrypted then title || ' not encrypted.'\n when encrypted and e.key_manager = 'CUSTOMER' then title || ' encrypted with CMK.'\n else title || ' not encrypted with CMK.'\n end as reason\n \n , region, account_id\nfrom\n aws_efs_file_system as f\n left join encrypted_fs as e on f.arn = e.arn;\n" - PrimaryTable: aws_efs_file_system ListOfTables: - aws_efs_file_system - aws_kms_key Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + WITH encrypted_fs AS ( + SELECT + fs.arn AS arn, + key_manager + FROM + aws_efs_file_system AS fs + LEFT JOIN aws_kms_key AS k ON fs.kms_key_id = k.arn + WHERE + enabled + ) + SELECT + f.arn AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN NOT encrypted THEN 'alarm' + WHEN encrypted AND e.key_manager = 'CUSTOMER' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT encrypted THEN title || ' not encrypted.' + WHEN encrypted AND e.key_manager = 'CUSTOMER' THEN title || ' encrypted with CMK.' + ELSE title || ' not encrypted with CMK.' + END AS reason, + region, + account_id + FROM + aws_efs_file_system AS f + LEFT JOIN encrypted_fs AS e ON f.arn = e.arn Severity: high Tags: category: @@ -21,5 +51,4 @@ Tags: - aws service: - AWS/EFS -IntegrationType: - - aws_cloud_account +Title: EFS file systems should be encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/aws/aws_efs_file_system_enforces_ssl.yaml b/compliance/controls/aws/aws_efs_file_system_enforces_ssl.yaml old mode 100755 new mode 100644 index 2f47f6046..6a4ac1a2e --- a/compliance/controls/aws/aws_efs_file_system_enforces_ssl.yaml +++ b/compliance/controls/aws/aws_efs_file_system_enforces_ssl.yaml @@ -1,47 +1,48 @@ +Description: To help protect data in transit, ensure that your EFS file systems require requests to use Secure Socket Layer (SSL). ID: aws_efs_file_system_enforces_ssl -Title: "EFS file systems should enforce SSL" -Description: "To help protect data in transit, ensure that your EFS file systems require requests to use Secure Socket Layer (SSL)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ssl_ok as ( - select - distinct name, + ListOfTables: + - aws_efs_file_system + Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + WITH ssl_ok AS ( + SELECT + DISTINCT name, arn, - 'ok' as status - from + 'ok' AS status + FROM aws_efs_file_system, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p, - jsonb_array_elements_text(s -> 'Action') as a, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + jsonb_array_elements_text(s -> 'Action') AS a, jsonb_array_elements_text( s -> 'Condition' -> 'Bool' -> 'aws:securetransport' - ) as ssl - where + ) AS ssl + WHERE p = '*' - and s ->> 'Effect' = 'Deny' - and ssl :: bool = false + AND s ->> 'Effect' = 'Deny' + AND ssl::bool = false ) - select - f.arn as resource, - f.og_account_id as og_account_id, - f.og_resource_id as og_resource_id, - case - when ok.status = 'ok' then 'ok' - else 'alarm' - end as status, - case - when ok.status = 'ok' then f.title || ' policy enforces HTTPS.' - else f.title || ' policy does not enforce HTTPS.' - end as reason - from - aws_efs_file_system as f - left join ssl_ok as ok on ok.name = f.name; - PrimaryTable: aws_efs_file_system - ListOfTables: - - aws_efs_file_system - Parameters: [] + SELECT + f.arn AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN ok.status = 'ok' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ok.status = 'ok' THEN f.title || ' policy enforces HTTPS.' + ELSE f.title || ' policy does not enforce HTTPS.' + END AS reason + FROM + aws_efs_file_system AS f + LEFT JOIN ssl_ok AS ok + ON ok.name = f.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EFS file systems should enforce SSL \ No newline at end of file diff --git a/compliance/controls/aws/aws_efs_file_system_in_backup_plan.yaml b/compliance/controls/aws/aws_efs_file_system_in_backup_plan.yaml old mode 100755 new mode 100644 index d0cbd8ef8..2aeec9ca4 --- a/compliance/controls/aws/aws_efs_file_system_in_backup_plan.yaml +++ b/compliance/controls/aws/aws_efs_file_system_in_backup_plan.yaml @@ -1,14 +1,28 @@ +Description: To help with data back-up processes, ensure your AWS Elastic File System (AWS EFS) file systems are a part of an AWS Backup plan. ID: aws_efs_file_system_in_backup_plan -Title: "EFS file systems should be in a backup plan" -Description: "To help with data back-up processes, ensure your AWS Elastic File System (AWS EFS) file systems are a part of an AWS Backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when automatic_backups = 'enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when automatic_backups = 'enabled' then title || ' automatic backups enabled.'\n else title || ' automatic backups not enabled.'\n end as reason\n \n \nfrom\n aws_efs_file_system;" - PrimaryTable: aws_efs_file_system ListOfTables: - aws_efs_file_system Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN automatic_backups = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN automatic_backups = 'enabled' THEN title || ' automatic backups enabled.' + ELSE title || ' automatic backups not enabled.' + END AS reason + FROM + aws_efs_file_system; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EFS file systems should be in a backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_efs_file_system_protected_by_backup_plan.yaml b/compliance/controls/aws/aws_efs_file_system_protected_by_backup_plan.yaml old mode 100755 new mode 100644 index 5567f4fa7..d0c267033 --- a/compliance/controls/aws/aws_efs_file_system_protected_by_backup_plan.yaml +++ b/compliance/controls/aws/aws_efs_file_system_protected_by_backup_plan.yaml @@ -1,14 +1,44 @@ +Description: Ensure that AWS Elastic File System (AWS EFS) File Systems are protected by a backup plan. The rule is non-compliant if the EFS File System is not covered by a backup plan. ID: aws_efs_file_system_protected_by_backup_plan -Title: "EFS file systems should be protected by backup plan" -Description: "Ensure that AWS Elastic File System (AWS EFS) File Systems are protected by a backup plan. The rule is non-compliant if the EFS File System is not covered by a backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with backup_protected_file_system as (\n select\n resource_arn as arn\n from\n aws_backup_protected_resource as b\n where\n resource_type = 'EFS'\n)\nselect\n f.arn as resource,\n f.og_account_id as og_account_id,\n f.og_resource_id as og_resource_id,\n case\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is not null then f.title || ' is protected by backup plan.'\n else f.title || ' is not protected by backup plan.'\n end as reason\n \n , f.region, f.account_id\nfrom\n aws_efs_file_system as f\n left join backup_protected_file_system as b on f.arn = b.arn;\n" - PrimaryTable: aws_efs_file_system ListOfTables: - aws_backup_protected_resource - aws_efs_file_system Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + WITH backup_protected_file_system AS ( + SELECT + resource_arn AS arn + FROM + aws_backup_protected_resource AS b + WHERE + resource_type = 'EFS' + ) + + SELECT + f.arn AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NOT NULL THEN f.title || ' is protected by backup plan.' + ELSE f.title || ' is not protected by backup plan.' + END AS reason, + f.region, + f.account_id + FROM + aws_efs_file_system AS f + LEFT JOIN + backup_protected_file_system AS b + ON + f.arn = b.arn; Severity: high Tags: category: @@ -39,5 +69,4 @@ Tags: - AWS/EFS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EFS file systems should be protected by backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_efs_file_system_restrict_public_access.yaml b/compliance/controls/aws/aws_efs_file_system_restrict_public_access.yaml old mode 100755 new mode 100644 index e6e882e6b..7f87f33e4 --- a/compliance/controls/aws/aws_efs_file_system_restrict_public_access.yaml +++ b/compliance/controls/aws/aws_efs_file_system_restrict_public_access.yaml @@ -1,46 +1,46 @@ +Description: Manage access to resources in the AWS Cloud by ensuring AWS EFS file systems cannot be publicly accessed. ID: aws_efs_file_system_restrict_public_access -Title: "EFS file systems should restrict public access" -Description: "Manage access to resources in the AWS Cloud by ensuring AWS EFS file systems cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with wildcard_action_policies as ( - select + ListOfTables: + - aws_efs_file_system + Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_efs_file_system, - jsonb_array_elements(policy_std -> 'Statement') as s - where + jsonb_array_elements(policy_std -> 'Statement') AS s + WHERE s ->> 'Effect' = 'Allow' - and ( - ( s -> 'Principal' -> 'AWS') = '["*"]' - or s ->> 'Principal' = '*' + AND ( + (s -> 'Principal' -> 'AWS') = '["*"]' + OR s ->> 'Principal' = '*' ) - group by + GROUP BY arn ) - select - f.arn as resource, - f.og_account_id as og_account_id, - f.og_resource_id as og_resource_id, - case - when p.arn is null then 'ok' - else 'alarm' - end as status, - case - when p.arn is null then title || ' does not allow public access.' - else title || ' contains ' || coalesce(p.statements_num, 0) || - ' statements that allows public access.' - end as reason - from - aws_efs_file_system as f - left join wildcard_action_policies as p on p.arn = f.arn; - PrimaryTable: aws_efs_file_system - ListOfTables: - - aws_efs_file_system - Parameters: [] + SELECT + f.arn AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' does not allow public access.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || + ' statements that allow public access.' + END AS reason + FROM + aws_efs_file_system AS f + LEFT JOIN wildcard_action_policies AS p ON p.arn = f.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EFS file systems should restrict public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_eks_cluster_control_plane_audit_logging_enabled.yaml b/compliance/controls/aws/aws_eks_cluster_control_plane_audit_logging_enabled.yaml old mode 100755 new mode 100644 index 8900d6404..f373a274a --- a/compliance/controls/aws/aws_eks_cluster_control_plane_audit_logging_enabled.yaml +++ b/compliance/controls/aws/aws_eks_cluster_control_plane_audit_logging_enabled.yaml @@ -1,43 +1,45 @@ +Description: AWS EKS clusters should have control plane audit logging enabled. These logs make it easy to secure and run clusters. ID: aws_eks_cluster_control_plane_audit_logging_enabled -Title: "EKS clusters should have control plane audit logging enabled" -Description: "AWS EKS clusters should have control plane audit logging enabled. These logs make it easy to secure and run clusters." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with control_panel_audit_logging as ( - select - distinct arn, - log -> 'Types' as log_type - from - aws_eks_cluster, - jsonb_array_elements(logging -> 'ClusterLogging') as log - where - log ->> 'Enabled' = 'true' - and (log -> 'Types') @> '["api", "audit", "authenticator", "controllerManager", "scheduler"]' - ) - select - c.arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when l.arn is not null then 'ok' - else 'alarm' - end as status, - case - when l.arn is not null then c.title || ' control plane audit logging enabled for all log types.' - else - case when logging -> 'ClusterLogging' @> '[{"Enabled": true}]' then c.title || ' control plane audit logging not enabled for all log types.' - else c.title || ' control plane audit logging not enabled.' - end - end as reason - from - aws_eks_cluster as c - left join control_panel_audit_logging as l on l.arn = c.arn; - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + WITH control_panel_audit_logging AS ( + SELECT + DISTINCT arn, + log -> 'Types' AS log_type + FROM + aws_eks_cluster, + jsonb_array_elements(logging -> 'ClusterLogging') AS log + WHERE + log ->> 'Enabled' = 'true' + AND (log -> 'Types') @> '["api", "audit", "authenticator", "controllerManager", "scheduler"]' + ) + SELECT + c.arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN l.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN l.arn IS NOT NULL THEN c.title || ' control plane audit logging enabled for all log types.' + ELSE + CASE + WHEN logging -> 'ClusterLogging' @> '[{"Enabled": true}]' THEN c.title || ' control plane audit logging not enabled for all log types.' + ELSE c.title || ' control plane audit logging not enabled.' + END + END AS reason + FROM + aws_eks_cluster AS c + LEFT JOIN control_panel_audit_logging AS l + ON l.arn = c.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EKS clusters should have control plane audit logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_eks_cluster_endpoint_public_access_restricted.yaml b/compliance/controls/aws/aws_eks_cluster_endpoint_public_access_restricted.yaml old mode 100755 new mode 100644 index 591bbb3c1..6242ca8ab --- a/compliance/controls/aws/aws_eks_cluster_endpoint_public_access_restricted.yaml +++ b/compliance/controls/aws/aws_eks_cluster_endpoint_public_access_restricted.yaml @@ -1,30 +1,38 @@ +Description: EKS clusters endpoint with private access allows communication between your nodes and the API server stays within. This control is non-compliant if clusters endpoint public access is enabled as cluster API server is accessible from the internet. ID: aws_eks_cluster_endpoint_public_access_restricted -Title: "EKS clusters endpoint public access should be restricted" -Description: "EKS clusters endpoint with private access allows communication between your nodes and the API server stays within. This control is non-compliant if clusters endpoint public access is enabled as cluster API server is accessible from the internet." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when resources_vpc_config ->> 'EndpointPrivateAccess' = 'true' and resources_vpc_config ->> 'EndpointPublicAccess' = 'false' then 'ok' - when resources_vpc_config ->> 'EndpointPublicAccess' = 'true' and resources_vpc_config -> 'PublicAccessCidrs' @> '["0.0.0.0/0"]' then 'alarm' - else 'ok' - end as status, - case - when resources_vpc_config ->> 'EndpointPrivateAccess' = 'true' and resources_vpc_config ->> 'EndpointPublicAccess' = 'false' then title || ' endpoint access is private.' - when resources_vpc_config ->> 'EndpointPublicAccess' = 'true' and resources_vpc_config -> 'PublicAccessCidrs' @> '["0.0.0.0/0"]' then title || ' endpoint access is public.' - else title || ' endpoint public access is restricted.' - end as reason - from - aws_eks_cluster; - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN resources_vpc_config ->> 'EndpointPrivateAccess' = 'true' + AND resources_vpc_config ->> 'EndpointPublicAccess' = 'false' + THEN 'ok' + WHEN resources_vpc_config ->> 'EndpointPublicAccess' = 'true' + AND resources_vpc_config -> 'PublicAccessCidrs' @> '["0.0.0.0/0"]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN resources_vpc_config ->> 'EndpointPrivateAccess' = 'true' + AND resources_vpc_config ->> 'EndpointPublicAccess' = 'false' + THEN title || ' endpoint access is private.' + WHEN resources_vpc_config ->> 'EndpointPublicAccess' = 'true' + AND resources_vpc_config -> 'PublicAccessCidrs' @> '["0.0.0.0/0"]' + THEN title || ' endpoint access is public.' + ELSE title || ' endpoint public access is restricted.' + END AS reason + FROM + aws_eks_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EKS clusters endpoint public access should be restricted \ No newline at end of file diff --git a/compliance/controls/aws/aws_eks_cluster_endpoint_restrict_public_access.yaml b/compliance/controls/aws/aws_eks_cluster_endpoint_restrict_public_access.yaml old mode 100755 new mode 100644 index 841beb6cb..633215cc4 --- a/compliance/controls/aws/aws_eks_cluster_endpoint_restrict_public_access.yaml +++ b/compliance/controls/aws/aws_eks_cluster_endpoint_restrict_public_access.yaml @@ -1,13 +1,30 @@ +Description: Ensure whether AWS Elastic Kubernetes Service (AWS EKS) endpoint is not publicly accessible. The rule is compliant if the endpoint is publicly accessible. ID: aws_eks_cluster_endpoint_restrict_public_access -Title: "EKS clusters endpoint should restrict public access" -Description: "Ensure whether AWS Elastic Kubernetes Service (AWS EKS) endpoint is not publicly accessible. The rule is compliant if the endpoint is publicly accessible." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when resources_vpc_config ->> 'EndpointPublicAccess' = 'true' then 'alarm'\n else 'ok'\n end as status,\n case\n when resources_vpc_config ->> 'EndpointPublicAccess' = 'true' then title || ' endpoint publicly accessible.'\n else title || ' endpoint not publicly accessible.'\n end as reason\n \n , region, account_id\nfrom\n aws_eks_cluster;\n" - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN resources_vpc_config ->> 'EndpointPublicAccess' = 'true' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN resources_vpc_config ->> 'EndpointPublicAccess' = 'true' THEN title || ' endpoint publicly accessible.' + ELSE title || ' endpoint not publicly accessible.' + END AS reason, + region, + account_id + FROM + aws_eks_cluster; Severity: low Tags: category: @@ -24,5 +41,4 @@ Tags: - aws service: - AWS/EKS -IntegrationType: - - aws_cloud_account +Title: EKS clusters endpoint should restrict public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_eks_cluster_no_default_vpc.yaml b/compliance/controls/aws/aws_eks_cluster_no_default_vpc.yaml old mode 100755 new mode 100644 index 2c39409ee..072f53ffb --- a/compliance/controls/aws/aws_eks_cluster_no_default_vpc.yaml +++ b/compliance/controls/aws/aws_eks_cluster_no_default_vpc.yaml @@ -1,39 +1,41 @@ +Description: Ensure to configure a new VPC for your EKS cluster as default VPC comes with a default configuration that lacks the proper security controls. Your network should be well configured and should follow the least privilege principle, meaning only the necessary privileges are granted. ID: aws_eks_cluster_no_default_vpc -Title: "EKS clusters should not be configured within a default VPC" -Description: "Ensure to configure a new VPC for your EKS cluster as default VPC comes with a default configuration that lacks the proper security controls. Your network should be well configured and should follow the least privilege principle, meaning only the necessary privileges are granted." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with default_vpc_cluster as ( - select - distinct c.arn - from - aws_eks_cluster as c - left join aws_vpc as v on v.vpc_id = c.resources_vpc_config ->> 'VpcId' - where - v.is_default - ) - select - c.arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when v.arn is not null then 'alarm' - else 'ok' - end as status, - case - when v.arn is not null then title || ' uses default VPC.' - else title || ' does not use default VPC.' - end as reason - from - aws_eks_cluster as c - left join default_vpc_cluster as v on v.arn = c.arn; - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster - aws_vpc Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + WITH default_vpc_cluster AS ( + SELECT + DISTINCT c.arn + FROM + aws_eks_cluster AS c + LEFT JOIN + aws_vpc AS v ON v.vpc_id = c.resources_vpc_config ->> 'VpcId' + WHERE + v.is_default + ) + SELECT + c.arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN v.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.arn IS NOT NULL THEN title || ' uses default VPC.' + ELSE title || ' does not use default VPC.' + END AS reason + FROM + aws_eks_cluster AS c + LEFT JOIN + default_vpc_cluster AS v ON v.arn = c.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EKS clusters should not be configured within a default VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_eks_cluster_no_multiple_security_groups.yaml b/compliance/controls/aws/aws_eks_cluster_no_multiple_security_groups.yaml old mode 100755 new mode 100644 index 18158d46b..b866bbe16 --- a/compliance/controls/aws/aws_eks_cluster_no_multiple_security_groups.yaml +++ b/compliance/controls/aws/aws_eks_cluster_no_multiple_security_groups.yaml @@ -1,14 +1,25 @@ +Description: This controls ensures that EKS clusters is not using multiple security groups. ID: aws_eks_cluster_no_multiple_security_groups -Title: "EKS clusters should not use multiple security groups" -Description: "This controls ensures that EKS clusters is not using multiple security groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(resources_vpc_config -> 'SecurityGroupIds') > 1 then 'alarm'\n else 'ok'\n end as status,\n title || ' has '|| jsonb_array_length(resources_vpc_config -> 'SecurityGroupIds') || ' security group(s).' as reason\n \n \nfrom\n aws_eks_cluster;" - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(resources_vpc_config -> 'SecurityGroupIds') > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(resources_vpc_config -> 'SecurityGroupIds') || ' security group(s).' AS reason + FROM + aws_eks_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EKS clusters should not use multiple security groups \ No newline at end of file diff --git a/compliance/controls/aws/aws_eks_cluster_secrets_encrypted.yaml b/compliance/controls/aws/aws_eks_cluster_secrets_encrypted.yaml old mode 100755 new mode 100644 index 87fef8a7c..48f980066 --- a/compliance/controls/aws/aws_eks_cluster_secrets_encrypted.yaml +++ b/compliance/controls/aws/aws_eks_cluster_secrets_encrypted.yaml @@ -1,13 +1,42 @@ +Description: Ensure that AWS Elastic Kubernetes Service clusters are configured to have Kubernetes secrets encrypted using AWS Key Management Service (KMS) keys. ID: aws_eks_cluster_secrets_encrypted -Title: "EKS clusters should be configured to have kubernetes secrets encrypted using KMS" -Description: "Ensure that AWS Elastic Kubernetes Service clusters are configured to have Kubernetes secrets encrypted using AWS Key Management Service (KMS) keys." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with eks_secrets_encrypted as (\n select\n distinct arn as arn\n from\n aws_eks_cluster,\n jsonb_array_elements(encryption_config) as e\n where\n e -> 'Resources' @> '[\"secrets\"]'\n)\nselect\n a.arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when encryption_config is null then 'alarm'\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption_config is null then a.title || ' encryption not enabled.'\n when b.arn is not null then a.title || ' encrypted with EKS secrets.'\n else a.title || ' not encrypted with EKS secrets.'\n end as reason\n \n , region, account_id\nfrom\n aws_eks_cluster as a\n left join eks_secrets_encrypted as b on a.arn = b.arn;\n" - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + WITH eks_secrets_encrypted AS ( + SELECT + DISTINCT arn AS arn + FROM + aws_eks_cluster, + jsonb_array_elements(encryption_config) AS e + WHERE + e -> 'Resources' @> '["secrets"]' + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN encryption_config IS NULL THEN 'alarm' + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_config IS NULL THEN a.title || ' encryption not enabled.' + WHEN b.arn IS NOT NULL THEN a.title || ' encrypted with EKS secrets.' + ELSE a.title || ' not encrypted with EKS secrets.' + END AS reason, + region, + account_id + FROM + aws_eks_cluster AS a + LEFT JOIN eks_secrets_encrypted AS b ON a.arn = b.arn; Severity: high Tags: category: @@ -26,5 +55,4 @@ Tags: - aws service: - AWS/EKS -IntegrationType: - - aws_cloud_account +Title: EKS clusters should be configured to have kubernetes secrets encrypted using KMS \ No newline at end of file diff --git a/compliance/controls/aws/aws_eks_cluster_with_latest_kubernetes_version.yaml b/compliance/controls/aws/aws_eks_cluster_with_latest_kubernetes_version.yaml old mode 100755 new mode 100644 index 0a1060ff9..c91fbd3b3 --- a/compliance/controls/aws/aws_eks_cluster_with_latest_kubernetes_version.yaml +++ b/compliance/controls/aws/aws_eks_cluster_with_latest_kubernetes_version.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether an AWS EKS cluster is running on a supported Kubernetes version. The control fails if the EKS cluster is running on an unsupported version. If your application doesn't require a specific version of Kubernetes, we recommend that you use the latest available Kubernetes version that's supported by EKS for your clusters. ID: aws_eks_cluster_with_latest_kubernetes_version -Title: "EKS clusters should run on a supported Kubernetes version" -Description: "This control checks whether an AWS EKS cluster is running on a supported Kubernetes version. The control fails if the EKS cluster is running on an unsupported version. If your application doesn't require a specific version of Kubernetes, we recommend that you use the latest available Kubernetes version that's supported by EKS for your clusters." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n -- eks:oldestVersionSupported (Current oldest supported version is 1.19)\n when (version)::decimal >= 1.19 then 'ok'\n else 'alarm'\n end as status,\n case\n when (version)::decimal >= 1.19 then title || ' runs on a supported kubernetes version.'\n else title || ' does not run on a supported kubernetes version.'\n end as reason\n \n , region, account_id\nfrom\n aws_eks_cluster;\n" - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (version)::decimal >= 1.19 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (version)::decimal >= 1.19 THEN title || ' runs on a supported kubernetes version.' + ELSE title || ' does not run on a supported kubernetes version.' + END AS reason, + region, + account_id + FROM + aws_eks_cluster; Severity: high Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/EKS -IntegrationType: - - aws_cloud_account +Title: EKS clusters should run on a supported Kubernetes version \ No newline at end of file diff --git a/compliance/controls/aws/aws_elastic_beanstalk_enhanced_health_reporting_enabled.yaml b/compliance/controls/aws/aws_elastic_beanstalk_enhanced_health_reporting_enabled.yaml old mode 100755 new mode 100644 index 20ce1c6ca..723149166 --- a/compliance/controls/aws/aws_elastic_beanstalk_enhanced_health_reporting_enabled.yaml +++ b/compliance/controls/aws/aws_elastic_beanstalk_enhanced_health_reporting_enabled.yaml @@ -1,13 +1,30 @@ +Description: AWS Elastic Beanstalk enhanced health reporting enables a more rapid response to changes in the health of the underlying infrastructure. These changes could result in a lack of availability of the application. Elastic Beanstalk enhanced health reporting provides a status descriptor to gauge the severity of the identified issues and identify possible causes to investigate. ID: aws_elastic_beanstalk_enhanced_health_reporting_enabled -Title: "Elastic Beanstalk enhanced health reporting should be enabled" -Description: "AWS Elastic Beanstalk enhanced health reporting enables a more rapid response to changes in the health of the underlying infrastructure. These changes could result in a lack of availability of the application. Elastic Beanstalk enhanced health reporting provides a status descriptor to gauge the severity of the identified issues and identify possible causes to investigate." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n application_name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when health_status is not null and health is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when health_status is not null and health is not null then application_name || ' enhanced health check enabled.'\n else application_name || ' enhanced health check disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_elastic_beanstalk_environment;\n" - PrimaryTable: aws_elastic_beanstalk_environment ListOfTables: - aws_elastic_beanstalk_environment Parameters: [] + PrimaryTable: aws_elastic_beanstalk_environment + QueryToExecute: | + SELECT + application_name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN health_status IS NOT NULL AND health IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN health_status IS NOT NULL AND health IS NOT NULL THEN application_name || ' enhanced health check enabled.' + ELSE application_name || ' enhanced health check disabled.' + END AS reason, + region, + account_id + FROM + aws_elastic_beanstalk_environment; Severity: medium Tags: category: @@ -26,5 +43,4 @@ Tags: - aws service: - AWS/ElasticBeanstalk -IntegrationType: - - aws_cloud_account +Title: Elastic Beanstalk enhanced health reporting should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_elastic_beanstalk_environment_logs_to_cloudwatch.yaml b/compliance/controls/aws/aws_elastic_beanstalk_environment_logs_to_cloudwatch.yaml old mode 100755 new mode 100644 index 158727b3d..8d0593a54 --- a/compliance/controls/aws/aws_elastic_beanstalk_environment_logs_to_cloudwatch.yaml +++ b/compliance/controls/aws/aws_elastic_beanstalk_environment_logs_to_cloudwatch.yaml @@ -1,42 +1,42 @@ +Description: This control checks whether an Elastic Beanstalk environment is configured to send logs to CloudWatch Logs. The control fails if an Elastic Beanstalk environment isn't configured to send logs to CloudWatch Logs. Optionally, you can provide a custom value for the RetentionInDays parameter if you want the control to pass only if logs are retained for the specified number of days before expiration. ID: aws_elastic_beanstalk_environment_logs_to_cloudwatch -Title: "Elastic Beanstalk should stream logs to CloudWatch" -Description: "This control checks whether an Elastic Beanstalk environment is configured to send logs to CloudWatch Logs. The control fails if an Elastic Beanstalk environment isn't configured to send logs to CloudWatch Logs. Optionally, you can provide a custom value for the RetentionInDays parameter if you want the control to pass only if logs are retained for the specified number of days before expiration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with beanstalk_environment_logs_enabled as ( - select - distinct e.arn - from - aws_elastic_beanstalk_environment as e, - jsonb_array_elements(e.configuration_settings) as c, - jsonb_array_elements(c -> 'OptionSettings') as s - where - s ->> 'OptionName' = 'StreamLogs' - and s ->> 'Value' = 'true' - group by - arn - ) - select - e.arn as resource, - e.og_account_id as og_account_id, - e.og_resource_id as og_resource_id, - case - when l.arn is not null then 'ok' - else 'alarm' - end as status, - case - when l.arn is not null then title || ' send logs to AWS CloudWatch.' - else title || ' does not send logs to AWS CloudWatch.' - end as reason - from - aws_elastic_beanstalk_environment as e - left join beanstalk_environment_logs_enabled as l on e.arn = l.arn; - PrimaryTable: aws_elastic_beanstalk_environment ListOfTables: - aws_elastic_beanstalk_environment Parameters: [] + PrimaryTable: aws_elastic_beanstalk_environment + QueryToExecute: | + WITH beanstalk_environment_logs_enabled AS ( + SELECT + DISTINCT e.arn + FROM + aws_elastic_beanstalk_environment AS e, + jsonb_array_elements(e.configuration_settings) AS c, + jsonb_array_elements(c -> 'OptionSettings') AS s + WHERE + s ->> 'OptionName' = 'StreamLogs' + AND s ->> 'Value' = 'true' + GROUP BY + arn + ) + SELECT + e.arn AS resource, + e.og_account_id AS og_account_id, + e.og_resource_id AS og_resource_id, + CASE + WHEN l.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN l.arn IS NOT NULL THEN title || ' send logs to AWS CloudWatch.' + ELSE title || ' does not send logs to AWS CloudWatch.' + END AS reason + FROM + aws_elastic_beanstalk_environment AS e + LEFT JOIN beanstalk_environment_logs_enabled AS l ON e.arn = l.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Elastic Beanstalk should stream logs to CloudWatch \ No newline at end of file diff --git a/compliance/controls/aws/aws_elastic_beanstalk_environment_managed_updates_enabled.yaml b/compliance/controls/aws/aws_elastic_beanstalk_environment_managed_updates_enabled.yaml old mode 100755 new mode 100644 index 6e51a86be..2515fa8e8 --- a/compliance/controls/aws/aws_elastic_beanstalk_environment_managed_updates_enabled.yaml +++ b/compliance/controls/aws/aws_elastic_beanstalk_environment_managed_updates_enabled.yaml @@ -1,42 +1,43 @@ +Description: This control checks whether managed platform updates in an AWS Elastic Beanstalk environment is enabled. The rule is COMPLIANT if the value for ManagedActionsEnabled is set to true. The rule is NON_COMPLIANT if the value for ManagedActionsEnabled is set to false, or if a parameter is provided and its value does not match the existing configurations. ID: aws_elastic_beanstalk_environment_managed_updates_enabled -Title: "Elastic Beanstalk environment should have managed updates enabled" -Description: "This control checks whether managed platform updates in an AWS Elastic Beanstalk environment is enabled. The rule is COMPLIANT if the value for ManagedActionsEnabled is set to true. The rule is NON_COMPLIANT if the value for ManagedActionsEnabled is set to false, or if a parameter is provided and its value does not match the existing configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with beanstalk_environment_logs_enabled as ( - select - distinct e.arn - from - aws_elastic_beanstalk_environment as e, - jsonb_array_elements(e.configuration_settings) as c, - jsonb_array_elements(c -> 'OptionSettings') as s - where - s ->> 'OptionName' = 'ManagedActionsEnabled' - and s ->> 'Value' = 'true' - group by - arn - ) - select - e.arn as resource, - e.og_account_id as og_account_id, - e.og_resource_id as og_resource_id, - case - when l.arn is not null then 'ok' - else 'alarm' - end as status, - case - when l.arn is not null then title || ' managed actions Enabled.' - else title || ' managed actions disabled.' - end as reason - from - aws_elastic_beanstalk_environment as e - left join beanstalk_environment_logs_enabled as l on e.arn = l.arn; - PrimaryTable: aws_elastic_beanstalk_environment ListOfTables: - aws_elastic_beanstalk_environment Parameters: [] + PrimaryTable: aws_elastic_beanstalk_environment + QueryToExecute: | + WITH beanstalk_environment_logs_enabled AS ( + SELECT + DISTINCT e.arn + FROM + aws_elastic_beanstalk_environment AS e, + jsonb_array_elements(e.configuration_settings) AS c, + jsonb_array_elements(c -> 'OptionSettings') AS s + WHERE + s ->> 'OptionName' = 'ManagedActionsEnabled' + AND s ->> 'Value' = 'true' + GROUP BY + e.arn + ) + SELECT + e.arn AS resource, + e.og_account_id AS og_account_id, + e.og_resource_id AS og_resource_id, + CASE + WHEN l.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN l.arn IS NOT NULL THEN title || ' managed actions Enabled.' + ELSE title || ' managed actions disabled.' + END AS reason + FROM + aws_elastic_beanstalk_environment AS e + LEFT JOIN beanstalk_environment_logs_enabled AS l + ON e.arn = l.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Elastic Beanstalk environment should have managed updates enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_elasticache_cluster_auto_minor_version_upgrade_enabled.yaml b/compliance/controls/aws/aws_elasticache_cluster_auto_minor_version_upgrade_enabled.yaml old mode 100755 new mode 100644 index f643350d0..6a0200145 --- a/compliance/controls/aws/aws_elasticache_cluster_auto_minor_version_upgrade_enabled.yaml +++ b/compliance/controls/aws/aws_elasticache_cluster_auto_minor_version_upgrade_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control evaluates whether ElastiCache for Redis automatically applies minor version upgrades to cache clusters. This control fails if ElastiCache for Redis cache clusters do not have minor version upgrades automatically applied. ID: aws_elasticache_cluster_auto_minor_version_upgrade_enabled -Title: "Minor version upgrades should be automatically applied to ElastiCache for Redis cache clusters" -Description: "This control evaluates whether ElastiCache for Redis automatically applies minor version upgrades to cache clusters. This control fails if ElastiCache for Redis cache clusters do not have minor version upgrades automatically applied." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when auto_minor_version_upgrade then 'ok'\n else 'alarm'\n end as status,\n case\n when auto_minor_version_upgrade then title || ' automatic minor version upgrades enabled.'\n else title || ' automatic minor version upgrades disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_elasticache_cluster;\n" - PrimaryTable: aws_elasticache_cluster ListOfTables: - aws_elasticache_cluster Parameters: [] + PrimaryTable: aws_elasticache_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrades enabled.' + ELSE title || ' automatic minor version upgrades disabled.' + END AS reason, + region, + account_id + FROM + aws_elasticache_cluster; Severity: high Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/ElastiCache -IntegrationType: - - aws_cloud_account +Title: Minor version upgrades should be automatically applied to ElastiCache for Redis cache clusters \ No newline at end of file diff --git a/compliance/controls/aws/aws_elasticache_cluster_no_default_subnet_group.yaml b/compliance/controls/aws/aws_elasticache_cluster_no_default_subnet_group.yaml old mode 100755 new mode 100644 index e107e03e6..7d7aadbb4 --- a/compliance/controls/aws/aws_elasticache_cluster_no_default_subnet_group.yaml +++ b/compliance/controls/aws/aws_elasticache_cluster_no_default_subnet_group.yaml @@ -1,13 +1,30 @@ +Description: This control checks if ElastiCache clusters are configured with a custom subnet group. The control fails for an ElastiCache cluster if CacheSubnetGroupName has the value default. ID: aws_elasticache_cluster_no_default_subnet_group -Title: "ElastiCache clusters should not use the default subnet group" -Description: "This control checks if ElastiCache clusters are configured with a custom subnet group. The control fails for an ElastiCache cluster if CacheSubnetGroupName has the value default." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when cache_subnet_group_name = 'default' then 'alarm'\n else 'ok'\n end as status,\n case\n when cache_subnet_group_name = 'default' then title || ' not configured with a custom subnet group.'\n else title || ' configured with a custom subnet group.'\n end as reason\n \n , region, account_id\nfrom\n aws_elasticache_cluster;\n" - PrimaryTable: aws_elasticache_cluster ListOfTables: - aws_elasticache_cluster Parameters: [] + PrimaryTable: aws_elasticache_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cache_subnet_group_name = 'default' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN cache_subnet_group_name = 'default' THEN title || ' not configured with a custom subnet group.' + ELSE title || ' configured with a custom subnet group.' + END AS reason, + region, + account_id + FROM + aws_elasticache_cluster; Severity: high Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/ElastiCache -IntegrationType: - - aws_cloud_account +Title: ElastiCache clusters should not use the default subnet group \ No newline at end of file diff --git a/compliance/controls/aws/aws_elasticache_cluster_no_public_subnet.yaml b/compliance/controls/aws/aws_elasticache_cluster_no_public_subnet.yaml old mode 100755 new mode 100644 index ea54b325c..4577772a1 --- a/compliance/controls/aws/aws_elasticache_cluster_no_public_subnet.yaml +++ b/compliance/controls/aws/aws_elasticache_cluster_no_public_subnet.yaml @@ -1,94 +1,93 @@ +Description: This control checks if ElastiCache clusters are configured with public subnet as there is a risk of exposing sensitive data. ID: aws_elasticache_cluster_no_public_subnet -Title: "ElastiCache clusters should not use public_subnet" -Description: "This control checks if ElastiCache clusters are configured with public subnet as there is a risk of exposing sensitive data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with subnets_with_explicit_route as ( - select - distinct ( a ->> 'SubnetId') as all_sub - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a - where - a ->> 'SubnetId' is not null - ), public_subnets_with_explicit_route as ( - select - distinct a ->> 'SubnetId' as SubnetId - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a, - jsonb_array_elements(routes) as r - where - r ->> 'DestinationCidrBlock' = '0.0.0.0/0' - and - ( - r ->> 'GatewayId' like 'igw-%' - or r ->> 'NatGatewayId' like 'nat-%' - ) - and a ->> 'SubnetId' is not null - ), public_subnets_with_implicit_route as ( - select - distinct route_table_id, - vpc_id, - region - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a, - jsonb_array_elements(routes) as r - where - a ->> 'Main' = 'true' - and r ->> 'DestinationCidrBlock' = '0.0.0.0/0' - and ( - r ->> 'GatewayId' like 'igw-%' - or r ->> 'NatGatewayId' like 'nat-%' - ) - ), subnet_accessibility as ( - select - subnet_id, - vpc_id, - case - when s.subnet_id in (select all_sub from subnets_with_explicit_route where all_sub not in (select SubnetId from public_subnets_with_explicit_route )) then 'private' - when p.SubnetId is not null or s.vpc_id in ( select vpc_id from public_subnets_with_implicit_route) then 'public' - else 'private' - end as access - from - aws_vpc_subnet as s - left join public_subnets_with_explicit_route as p on p.SubnetId = s.subnet_id - ), cluster_public_subnet as ( - select - distinct arn, - cache_subnet_group_name - from - aws_elasticache_subnet_group, - jsonb_array_elements(subnets) as s - left join subnet_accessibility as a on a.subnet_id = s ->> 'SubnetIdentifier' - where - a.access = 'public' - ) - select - c.arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when s.cache_subnet_group_name is not null then 'alarm' - else 'ok' - end as status, - case - when s.cache_subnet_group_name is not null then c.title || ' has public subnet.' - else c.title || ' has private subnet.' - end as reason - from - aws_elasticache_cluster as c - left join cluster_public_subnet as s on s.cache_subnet_group_name = c.cache_subnet_group_name; - PrimaryTable: aws_elasticache_cluster ListOfTables: - aws_vpc_route_table - aws_vpc_subnet - aws_elasticache_subnet_group - aws_elasticache_cluster Parameters: [] + PrimaryTable: aws_elasticache_cluster + QueryToExecute: | + WITH subnets_with_explicit_route AS ( + SELECT DISTINCT (a ->> 'SubnetId') AS all_sub + FROM aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a + WHERE a ->> 'SubnetId' IS NOT NULL + ), + public_subnets_with_explicit_route AS ( + SELECT DISTINCT a ->> 'SubnetId' AS SubnetId + FROM aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND ( + r ->> 'GatewayId' LIKE 'igw-%' + OR r ->> 'NatGatewayId' LIKE 'nat-%' + ) + AND a ->> 'SubnetId' IS NOT NULL + ), + public_subnets_with_implicit_route AS ( + SELECT DISTINCT route_table_id, + vpc_id, + region + FROM aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE a ->> 'Main' = 'true' + AND r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND ( + r ->> 'GatewayId' LIKE 'igw-%' + OR r ->> 'NatGatewayId' LIKE 'nat-%' + ) + ), + subnet_accessibility AS ( + SELECT subnet_id, + vpc_id, + CASE + WHEN s.subnet_id IN (SELECT all_sub + FROM subnets_with_explicit_route + WHERE all_sub NOT IN (SELECT SubnetId + FROM public_subnets_with_explicit_route)) + THEN 'private' + WHEN p.SubnetId IS NOT NULL + OR s.vpc_id IN (SELECT vpc_id + FROM public_subnets_with_implicit_route) + THEN 'public' + ELSE 'private' + END AS access + FROM aws_vpc_subnet AS s + LEFT JOIN public_subnets_with_explicit_route AS p + ON p.SubnetId = s.subnet_id + ), + cluster_public_subnet AS ( + SELECT DISTINCT arn, + cache_subnet_group_name + FROM aws_elasticache_subnet_group, + jsonb_array_elements(subnets) AS s + LEFT JOIN subnet_accessibility AS a + ON a.subnet_id = s ->> 'SubnetIdentifier' + WHERE a.access = 'public' + ) + SELECT c.arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN s.cache_subnet_group_name IS NOT NULL + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.cache_subnet_group_name IS NOT NULL + THEN c.title || ' has public subnet.' + ELSE c.title || ' has private subnet.' + END AS reason + FROM aws_elasticache_cluster AS c + LEFT JOIN cluster_public_subnet AS s + ON s.cache_subnet_group_name = c.cache_subnet_group_name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ElastiCache clusters should not use public_subnet \ No newline at end of file diff --git a/compliance/controls/aws/aws_elasticache_redis_cluster_automatic_backup_retention_15_days.yaml b/compliance/controls/aws/aws_elasticache_redis_cluster_automatic_backup_retention_15_days.yaml old mode 100755 new mode 100644 index dd56bbb32..1f7b54a57 --- a/compliance/controls/aws/aws_elasticache_redis_cluster_automatic_backup_retention_15_days.yaml +++ b/compliance/controls/aws/aws_elasticache_redis_cluster_automatic_backup_retention_15_days.yaml @@ -1,29 +1,31 @@ +Description: When automatic backups are enabled, AWS ElastiCache creates a backup of the cluster on a daily basis. The backup can be retained for a number of days as specified by your organization. Automatic backups can help guard against data loss. ID: aws_elasticache_redis_cluster_automatic_backup_retention_15_days -Title: "ElastiCache Redis cluster automatic backup should be enabled with retention period of 15 days or greater" -Description: "When automatic backups are enabled, AWS ElastiCache creates a backup of the cluster on a daily basis. The backup can be retained for a number of days as specified by your organization. Automatic backups can help guard against data loss." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when snapshot_retention_limit < 15 then 'alarm' - else 'ok' - end as status, - case - when snapshot_retention_limit = 0 then title || ' automatic backups not enabled.' - when snapshot_retention_limit < 15 then title || ' automatic backup retention period is less than 15 days.' - else title || ' automatic backup retention period is more than 15 days.' - end as reason - , region, account_id - from - aws_elasticache_replication_group; - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_replication_group Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN snapshot_retention_limit < 15 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN snapshot_retention_limit = 0 THEN title || ' automatic backups not enabled.' + WHEN snapshot_retention_limit < 15 THEN title || ' automatic backup retention period is less than 15 days.' + ELSE title || ' automatic backup retention period is more than 15 days.' + END AS reason, + region, + account_id + FROM + aws_elasticache_replication_group; Severity: low Tags: category: @@ -46,12 +48,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -64,5 +66,4 @@ Tags: - AWS/ElastiCache soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: ElastiCache Redis cluster automatic backup should be enabled with retention period of 15 days or greater \ No newline at end of file diff --git a/compliance/controls/aws/aws_elasticache_replication_group_auto_failover_enabled.yaml b/compliance/controls/aws/aws_elasticache_replication_group_auto_failover_enabled.yaml old mode 100755 new mode 100644 index 1d2a8f1de..1d784437e --- a/compliance/controls/aws/aws_elasticache_replication_group_auto_failover_enabled.yaml +++ b/compliance/controls/aws/aws_elasticache_replication_group_auto_failover_enabled.yaml @@ -1,28 +1,30 @@ +Description: This control checks if ElastiCache for Redis replication groups have automatic failover enabled. This control fails if automatic failover isn't enabled for a Redis replication group. ID: aws_elasticache_replication_group_auto_failover_enabled -Title: "ElastiCache for Redis replication groups should have automatic failover enabled" -Description: "This control checks if ElastiCache for Redis replication groups have automatic failover enabled. This control fails if automatic failover isn't enabled for a Redis replication group." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when automatic_failover = 'enabled' then 'ok' - else 'alarm' - end as status, - case - when automatic_failover = 'enabled' then title || ' automatic failover enabled.' - else title || ' automatic failover disabled.' - end as reason - , region, account_id - from - aws_elasticache_replication_group; - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_replication_group Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN automatic_failover = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN automatic_failover = 'enabled' THEN title || ' automatic failover enabled.' + ELSE title || ' automatic failover disabled.' + END AS reason, + region, + account_id + FROM + aws_elasticache_replication_group; Severity: medium Tags: aws_foundational_security: @@ -37,5 +39,4 @@ Tags: - aws service: - AWS/ElastiCache -IntegrationType: - - aws_cloud_account +Title: ElastiCache for Redis replication groups should have automatic failover enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_elasticache_replication_group_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_elasticache_replication_group_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 2f2f04585..c0b099538 --- a/compliance/controls/aws/aws_elasticache_replication_group_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_elasticache_replication_group_encryption_at_rest_enabled.yaml @@ -1,28 +1,30 @@ +Description: This control checks if ElastiCache for Redis replication groups are encrypted at rest. This control fails if an ElastiCache for Redis replication group isn't encrypted at rest. ID: aws_elasticache_replication_group_encryption_at_rest_enabled -Title: "ElastiCache for Redis replication groups should be encrypted at rest" -Description: "This control checks if ElastiCache for Redis replication groups are encrypted at rest. This control fails if an ElastiCache for Redis replication group isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when at_rest_encryption_enabled then 'ok' - else 'alarm' - end as status, - case - when at_rest_encryption_enabled then title || ' encryption at rest enabled.' - else title || ' encryption at rest disabled.' - end as reason - , region, account_id - from - aws_elasticache_replication_group; - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_replication_group Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN at_rest_encryption_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN at_rest_encryption_enabled THEN title || ' encryption at rest enabled.' + ELSE title || ' encryption at rest disabled.' + END AS reason, + region, + account_id + FROM + aws_elasticache_replication_group; Severity: medium Tags: aws_foundational_security: @@ -37,5 +39,4 @@ Tags: - aws service: - AWS/ElastiCache -IntegrationType: - - aws_cloud_account +Title: ElastiCache for Redis replication groups should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_elasticache_replication_group_encryption_at_rest_enabled_with_kms_cmk.yaml b/compliance/controls/aws/aws_elasticache_replication_group_encryption_at_rest_enabled_with_kms_cmk.yaml old mode 100755 new mode 100644 index a893dc9ce..3d733444a --- a/compliance/controls/aws/aws_elasticache_replication_group_encryption_at_rest_enabled_with_kms_cmk.yaml +++ b/compliance/controls/aws/aws_elasticache_replication_group_encryption_at_rest_enabled_with_kms_cmk.yaml @@ -1,15 +1,59 @@ +Description: Ensure ElastiCache for Redis replication group are encrypted using CMK. The rule is non-compliant if the ElastiCache for Redis replication group is not encrypted using CMK. ID: aws_elasticache_replication_group_encryption_at_rest_enabled_with_kms_cmk -Title: "ElastiCache for Redis replication groups should be encrypted with CMK" -Description: "Ensure ElastiCache for Redis replication group are encrypted using CMK. The rule is non-compliant if the ElastiCache for Redis replication group is not encrypted using CMK." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with aws_elasticache_replication_groups as (\n select\n arn,\n at_rest_encryption_enabled,\n title,\n kms_key_id,\n region,\n account_id,\n _ctx,\n og_account_id,\n og_resource_id\n from\n aws_elasticache_replication_group\n order by\n arn\n),\nkms_keys as (\n select\n k.arn,\n k.region,\n k.account_id,\n k.enabled\n from\n aws_kms_key as k\n)\nselect\n r.arn as resource,\n r.og_account_id as og_account_id,\n r.og_resource_id as og_resource_id,\n case\n when not at_rest_encryption_enabled then 'alarm'\n when at_rest_encryption_enabled and kms_key_id is null then 'alarm'\n when at_rest_encryption_enabled and kms_key_id is not null and k.enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when not at_rest_encryption_enabled then r.title || ' encryption at rest disabled.'\n when at_rest_encryption_enabled and kms_key_id is null then r.title || ' encryption at rest not enabled with CMK.'\n when at_rest_encryption_enabled and kms_key_id is not null and k.enabled then r.title || ' encryption at rest enabled with CMK.'\n else r.title || ' encryption at rest enabled with disabled CMK.'\n end as reason\n \nfrom\n aws_elasticache_replication_groups as r\n left join kms_keys as k on k.arn = r.kms_key_id;" - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_replication_group - aws_kms_key Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + WITH aws_elasticache_replication_groups AS ( + SELECT + arn, + at_rest_encryption_enabled, + title, + kms_key_id, + region, + account_id, + _ctx, + og_account_id, + og_resource_id + FROM + aws_elasticache_replication_group + ORDER BY + arn + ), + kms_keys AS ( + SELECT + k.arn, + k.region, + k.account_id, + k.enabled + FROM + aws_kms_key AS k + ) + SELECT + r.arn AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN NOT at_rest_encryption_enabled THEN 'alarm' + WHEN at_rest_encryption_enabled AND kms_key_id IS NULL THEN 'alarm' + WHEN at_rest_encryption_enabled AND kms_key_id IS NOT NULL AND k.enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT at_rest_encryption_enabled THEN r.title || ' encryption at rest disabled.' + WHEN at_rest_encryption_enabled AND kms_key_id IS NULL THEN r.title || ' encryption at rest not enabled with CMK.' + WHEN at_rest_encryption_enabled AND kms_key_id IS NOT NULL AND k.enabled THEN r.title || ' encryption at rest enabled with CMK.' + ELSE r.title || ' encryption at rest enabled with disabled CMK.' + END AS reason + FROM + aws_elasticache_replication_groups AS r + LEFT JOIN kms_keys AS k ON k.arn = r.kms_key_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ElastiCache for Redis replication groups should be encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/aws/aws_elasticache_replication_group_encryption_in_transit_enabled.yaml b/compliance/controls/aws/aws_elasticache_replication_group_encryption_in_transit_enabled.yaml old mode 100755 new mode 100644 index aadad1ee1..6cdc94c97 --- a/compliance/controls/aws/aws_elasticache_replication_group_encryption_in_transit_enabled.yaml +++ b/compliance/controls/aws/aws_elasticache_replication_group_encryption_in_transit_enabled.yaml @@ -1,28 +1,30 @@ +Description: This control checks if ElastiCache for Redis replication groups are encrypted in transit. This control fails if an ElastiCache for Redis replication group isn't encrypted in transit. ID: aws_elasticache_replication_group_encryption_in_transit_enabled -Title: "ElastiCache for Redis replication groups should be encrypted in transit" -Description: "This control checks if ElastiCache for Redis replication groups are encrypted in transit. This control fails if an ElastiCache for Redis replication group isn't encrypted in transit." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when transit_encryption_enabled then 'ok' - else 'alarm' - end as status, - case - when transit_encryption_enabled then title || ' encryption in transit enabled.' - else title || ' encryption in transit disabled.' - end as reason - , region, account_id - from - aws_elasticache_replication_group; - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_replication_group Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN transit_encryption_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN transit_encryption_enabled THEN title || ' encryption in transit enabled.' + ELSE title || ' encryption in transit disabled.' + END AS reason, + region, + account_id + FROM + aws_elasticache_replication_group; Severity: medium Tags: aws_foundational_security: @@ -37,5 +39,4 @@ Tags: - aws service: - AWS/ElastiCache -IntegrationType: - - aws_cloud_account +Title: ElastiCache for Redis replication groups should be encrypted in transit \ No newline at end of file diff --git a/compliance/controls/aws/aws_elasticache_replication_group_redis_auth_enabled.yaml b/compliance/controls/aws/aws_elasticache_replication_group_redis_auth_enabled.yaml old mode 100755 new mode 100644 index 1a96d2532..74366d3c6 --- a/compliance/controls/aws/aws_elasticache_replication_group_redis_auth_enabled.yaml +++ b/compliance/controls/aws/aws_elasticache_replication_group_redis_auth_enabled.yaml @@ -1,39 +1,42 @@ +Description: This control checks if ElastiCache for Redis replication groups has Redis Auth enabled. The control fails for an ElastiCache for Redis replication group if the Redis version of its nodes is below 6.0 and AuthToken isn't in use. ID: aws_elasticache_replication_group_redis_auth_enabled -Title: "ElastiCache for Redis replication groups before version 6.0 should use Redis Auth" -Description: "This control checks if ElastiCache for Redis replication groups has Redis Auth enabled. The control fails for an ElastiCache for Redis replication group if the Redis version of its nodes is below 6.0 and AuthToken isn't in use." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with elasticache_cluster_node_version as ( - select - distinct replication_group_id, - engine_version - from - aws_elasticache_cluster - ) - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when regexp_split_to_array(v.engine_version, '\.')::int[] >= regexp_split_to_array('6.0', '\.')::int[] then 'skip' - when regexp_split_to_array(v.engine_version, '\.')::int[] < regexp_split_to_array('6.0', '\.')::int[] and eg.auth_token_enabled then 'ok' - else 'alarm' - end as status, - case - when regexp_split_to_array(v.engine_version, '\.')::int[] >= regexp_split_to_array('6.0', '\.')::int[] then eg.title || ' node version is ' || engine_version || '.' - when regexp_split_to_array(v.engine_version, '\.')::int[] < regexp_split_to_array('6.0', '\.')::int[] and eg.auth_token_enabled then eg.title || ' has Redis AUTH enabled.' - else eg.title || ' has Redis AUTH disabled.' - end as reason - , eg.region, eg.account_id - from - aws_elasticache_replication_group as eg - left join elasticache_cluster_node_version as v on eg.replication_group_id = v.replication_group_id; - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_cluster - aws_elasticache_replication_group Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + WITH elasticache_cluster_node_version AS ( + SELECT + DISTINCT replication_group_id, + engine_version + FROM + aws_elasticache_cluster + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN regexp_split_to_array(v.engine_version, '.')::int[] >= regexp_split_to_array('6.0', '.')::int[] THEN 'skip' + WHEN regexp_split_to_array(v.engine_version, '.')::int[] < regexp_split_to_array('6.0', '.')::int[] AND eg.auth_token_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN regexp_split_to_array(v.engine_version, '.')::int[] >= regexp_split_to_array('6.0', '.')::int[] THEN eg.title || ' node version is ' || engine_version || '.' + WHEN regexp_split_to_array(v.engine_version, '.')::int[] < regexp_split_to_array('6.0', '.')::int[] AND eg.auth_token_enabled THEN eg.title || ' has Redis AUTH enabled.' + ELSE eg.title || ' has Redis AUTH disabled.' + END AS reason, + eg.region, + eg.account_id + FROM + aws_elasticache_replication_group AS eg + LEFT JOIN elasticache_cluster_node_version AS v + ON eg.replication_group_id = v.replication_group_id; Severity: medium Tags: aws_foundational_security: @@ -48,5 +51,4 @@ Tags: - aws service: - AWS/ElastiCache -IntegrationType: - - aws_cloud_account +Title: ElastiCache for Redis replication groups before version 6.0 should use Redis Auth \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_classic_lb_logging_enabled.yaml b/compliance/controls/aws/aws_elb_application_classic_lb_logging_enabled.yaml old mode 100755 new mode 100644 index d5e725aec..b2dca9f2b --- a/compliance/controls/aws/aws_elb_application_classic_lb_logging_enabled.yaml +++ b/compliance/controls/aws/aws_elb_application_classic_lb_logging_enabled.yaml @@ -1,14 +1,52 @@ +Description: Elastic Load Balancing activity is a central point of communication within an environment. ID: aws_elb_application_classic_lb_logging_enabled -Title: "ELB application and classic load balancer logging should be enabled" -Description: "Elastic Load Balancing activity is a central point of communication within an environment." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\n select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_ec2_application_load_balancer' as og_table_name,\n case\n when load_balancer_attributes @> '[{\"Key\": \"access_logs.s3.enabled\", \"Value\": \"true\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when load_balancer_attributes @> '[{\"Key\": \"access_logs.s3.enabled\", \"Value\": \"true\"}]' then title || ' logging enabled.'\n else title || ' logging disabled.'\n end as reason\n \n , region, account_id\n from\n aws_ec2_application_load_balancer\n)\nunion\n(\n select\n 'arn:' || partition || ':elasticloadbalancing:' || region || ':' || account_id || ':loadbalancer/' || title as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_ec2_classic_load_balancer' as og_table_name,\n case\n when access_log_enabled = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when access_log_enabled = 'true' then title || ' logging enabled.'\n else title || ' logging disabled.'\n end as reason\n \n , region, account_id\n from\n aws_ec2_classic_load_balancer\n);\n" - PrimaryTable: "" ListOfTables: - aws_ec2_application_load_balancer - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_ec2_application_load_balancer' AS og_table_name, + CASE + WHEN load_balancer_attributes @> '[{"Key": "access_logs.s3.enabled", "Value": "true"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN load_balancer_attributes @> '[{"Key": "access_logs.s3.enabled", "Value": "true"}]' THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason, + region, + account_id + FROM aws_ec2_application_load_balancer + ) + UNION + ( + SELECT + 'arn:' || partition || ':elasticloadbalancing:' || region || ':' || account_id || ':loadbalancer/' || title AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_ec2_classic_load_balancer' AS og_table_name, + CASE + WHEN access_log_enabled = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN access_log_enabled = 'true' THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason, + region, + account_id + FROM aws_ec2_classic_load_balancer + ); Severity: high Tags: category: @@ -31,12 +69,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -49,5 +87,4 @@ Tags: - AWS/ELB soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: ELB application and classic load balancer logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_classic_network_lb_prohibit_public_access.yaml b/compliance/controls/aws/aws_elb_application_classic_network_lb_prohibit_public_access.yaml old mode 100755 new mode 100644 index 60b55e5ad..8163a5370 --- a/compliance/controls/aws/aws_elb_application_classic_network_lb_prohibit_public_access.yaml +++ b/compliance/controls/aws/aws_elb_application_classic_network_lb_prohibit_public_access.yaml @@ -1,11 +1,18 @@ +Description: An internet facing load balancer has a publicly resolvable DNS name, so it can route requests from clients over the internet to the EC2 instances that are registered with the load balancer. ID: aws_elb_application_classic_network_lb_prohibit_public_access -Title: "ELB load balancers should prohibit public access" -Description: "An internet facing load balancer has a publicly resolvable DNS name, so it can route requests from clients over the internet to the EC2 instances that are registered with the load balancer." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with all_lb_details as ( - select + ListOfTables: + - aws_ec2_application_load_balancer + - aws_ec2_network_load_balancer + - aws_ec2_classic_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + WITH all_lb_details AS ( + SELECT arn, scheme, title, @@ -15,10 +22,10 @@ Query: _ctx, og_account_id, og_resource_id - from + FROM aws_ec2_application_load_balancer - union - select + UNION + SELECT arn, scheme, title, @@ -28,10 +35,10 @@ Query: _ctx, og_account_id, og_resource_id - from + FROM aws_ec2_network_load_balancer - union - select + UNION + SELECT arn, scheme, title, @@ -41,30 +48,23 @@ Query: _ctx, og_account_id, og_resource_id - from - aws_ec2_classic_load_balancer + FROM + aws_ec2_classic_load_balancer ) - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when scheme = 'internet-facing' then 'alarm' - else 'ok' - end as status, - case - when scheme = 'internet-facing' then title || ' publicly accessible.' - else title|| ' not publicly accessible.' - end as reason - from + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN scheme = 'internet-facing' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN scheme = 'internet-facing' THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM all_lb_details; - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - - aws_ec2_network_load_balancer - - aws_ec2_classic_load_balancer - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB load balancers should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_gateway_network_lb_multiple_az_configured.yaml b/compliance/controls/aws/aws_elb_application_gateway_network_lb_multiple_az_configured.yaml old mode 100755 new mode 100644 index f2246b7b5..f08bcfa83 --- a/compliance/controls/aws/aws_elb_application_gateway_network_lb_multiple_az_configured.yaml +++ b/compliance/controls/aws/aws_elb_application_gateway_network_lb_multiple_az_configured.yaml @@ -1,15 +1,60 @@ +Description: This control checks whether an Elastic Load Balancer V2 (Application, Network, or Gateway Load Balancer) has registered instances from multiple Availability Zones. The control fails if an Elastic Load Balancer V2 has instances registered in fewer than two Availability Zones. ID: aws_elb_application_gateway_network_lb_multiple_az_configured -Title: "ELB application, network, and gateway load balancers should span multiple availability zones" -Description: "This control checks whether an Elastic Load Balancer V2 (Application, Network, or Gateway Load Balancer) has registered instances from multiple Availability Zones. The control fails if an Elastic Load Balancer V2 has instances registered in fewer than two Availability Zones." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_ec2_application_load_balancer' as og_table_name,\n case\n when jsonb_array_length(availability_zones) < 2 then 'alarm'\n else 'ok'\n end as status,\n title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason\n \n , region, account_id\nfrom\n aws_ec2_application_load_balancer\nunion\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_ec2_network_load_balancer' as og_table_name,\n case\n when jsonb_array_length(availability_zones) < 2 then 'alarm'\n else 'ok'\n end as status,\n title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason\n \n , region, account_id\nfrom\n aws_ec2_network_load_balancer\nunion\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_ec2_gateway_load_balancer' as og_table_name,\n case\n when jsonb_array_length(availability_zones) < 2 then 'alarm'\n else 'ok'\n end as status,\n title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason\n \n , region, account_id\nfrom\n aws_ec2_gateway_load_balancer;\n" - PrimaryTable: "" ListOfTables: - aws_ec2_application_load_balancer - aws_ec2_gateway_load_balancer - aws_ec2_network_load_balancer Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_ec2_application_load_balancer' AS og_table_name, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason, + region, + account_id + FROM + aws_ec2_application_load_balancer + UNION + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_ec2_network_load_balancer' AS og_table_name, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason, + region, + account_id + FROM + aws_ec2_network_load_balancer + UNION + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_ec2_gateway_load_balancer' AS og_table_name, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason, + region, + account_id + FROM + aws_ec2_gateway_load_balancer; Severity: medium Tags: aws_foundational_security: @@ -24,5 +69,4 @@ Tags: - aws service: - AWS/ELB -IntegrationType: - - aws_cloud_account +Title: ELB application, network, and gateway load balancers should span multiple availability zones \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_lb_deletion_protection_enabled.yaml b/compliance/controls/aws/aws_elb_application_lb_deletion_protection_enabled.yaml old mode 100755 new mode 100644 index b1b924ea0..b7523336c --- a/compliance/controls/aws/aws_elb_application_lb_deletion_protection_enabled.yaml +++ b/compliance/controls/aws/aws_elb_application_lb_deletion_protection_enabled.yaml @@ -1,13 +1,30 @@ +Description: This rule ensures that Elastic Load Balancing has deletion protection enabled. ID: aws_elb_application_lb_deletion_protection_enabled -Title: "ELB application load balancer deletion protection should be enabled" -Description: "This rule ensures that Elastic Load Balancing has deletion protection enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when load_balancer_attributes @> '[{\"Key\": \"deletion_protection.enabled\", \"Value\": \"true\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when load_balancer_attributes @> '[{\"Key\": \"deletion_protection.enabled\", \"Value\": \"true\"}]' then title || ' deletion protection enabled.'\n else title || ' deletion protection disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_application_load_balancer;\n" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN load_balancer_attributes @> '[{"Key": "deletion_protection.enabled", "Value": "true"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN load_balancer_attributes @> '[{"Key": "deletion_protection.enabled", "Value": "true"}]' THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection disabled.' + END AS reason, + region, + account_id + FROM + aws_ec2_application_load_balancer; Severity: high Tags: category: @@ -26,17 +43,16 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: - aws service: - AWS/ELB -IntegrationType: - - aws_cloud_account +Title: ELB application load balancer deletion protection should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_lb_desync_mitigation_mode.yaml b/compliance/controls/aws/aws_elb_application_lb_desync_mitigation_mode.yaml old mode 100755 new mode 100644 index 61b9bcdbc..3a34fd786 --- a/compliance/controls/aws/aws_elb_application_lb_desync_mitigation_mode.yaml +++ b/compliance/controls/aws/aws_elb_application_lb_desync_mitigation_mode.yaml @@ -1,13 +1,39 @@ +Description: This control checks whether an Application Load Balancer is configured with defensive or strictest desync mitigation mode. The control fails if an Application Load Balancer is not configured with defensive or strictest desync mitigation mode. ID: aws_elb_application_lb_desync_mitigation_mode -Title: "ELB application load balancers should be configured with defensive or strictest desync mitigation mode" -Description: "This control checks whether an Application Load Balancer is configured with defensive or strictest desync mitigation mode. The control fails if an Application Load Balancer is not configured with defensive or strictest desync mitigation mode." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with app_lb_desync_mitigation_mode as (\n select\n arn,\n l ->> 'Key',\n l ->> 'Value' as v\n from\n aws_ec2_application_load_balancer,\n jsonb_array_elements(load_balancer_attributes) as l\n where\n l ->> 'Key' = 'routing.http.desync_mitigation_mode'\n)\nselect\n a.arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when m.v = any(array['defensive', 'strictest']) then 'ok'\n else 'alarm'\n end as status,\n title || ' has ' || m.v || ' desync mitigation mode.' as reason\n \n , region, account_id\nfrom\n aws_ec2_application_load_balancer as a\n left join app_lb_desync_mitigation_mode as m on a.arn = m.arn;\n" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + WITH app_lb_desync_mitigation_mode AS ( + SELECT + arn, + l ->> 'Key', + l ->> 'Value' AS v + FROM + aws_ec2_application_load_balancer, + jsonb_array_elements(load_balancer_attributes) AS l + WHERE + l ->> 'Key' = 'routing.http.desync_mitigation_mode' + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN m.v = ANY(ARRAY['defensive', 'strictest']) THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' has ' || m.v || ' desync mitigation mode.' AS reason, + region, + account_id + FROM + aws_ec2_application_load_balancer AS a + LEFT JOIN app_lb_desync_mitigation_mode AS m ON a.arn = m.arn; Severity: medium Tags: aws_foundational_security: @@ -22,5 +48,4 @@ Tags: - aws service: - AWS/ELB -IntegrationType: - - aws_cloud_account +Title: ELB application load balancers should be configured with defensive or strictest desync mitigation mode \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_lb_drop_http_headers.yaml b/compliance/controls/aws/aws_elb_application_lb_drop_http_headers.yaml old mode 100755 new mode 100644 index b3d7f4f8a..c27709b5d --- a/compliance/controls/aws/aws_elb_application_lb_drop_http_headers.yaml +++ b/compliance/controls/aws/aws_elb_application_lb_drop_http_headers.yaml @@ -1,15 +1,32 @@ +Description: Ensure that your Elastic Load Balancers (ELB) are configured to drop http headers. ID: aws_elb_application_lb_drop_http_headers -Title: "ELB application load balancers should be drop HTTP headers" -Description: "Ensure that your Elastic Load Balancers (ELB) are configured to drop http headers." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when load_balancer_attributes @> '[{\"Key\": \"routing.http.drop_invalid_header_fields.enabled\", \"Value\": \"true\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when load_balancer_attributes @> '[{\"Key\": \"routing.http.drop_invalid_header_fields.enabled\", \"Value\": \"true\"}]' then title || ' configured to drop http headers.'\n else title || ' not configured to drop http headers.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_application_load_balancer;\n" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN load_balancer_attributes @> '[{"Key": "routing.http.drop_invalid_header_fields.enabled", "Value": "true"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN load_balancer_attributes @> '[{"Key": "routing.http.drop_invalid_header_fields.enabled", "Value": "true"}]' THEN title || ' configured to drop http headers.' + ELSE title || ' not configured to drop http headers.' + END AS reason, + region, + account_id + FROM + aws_ec2_application_load_balancer; Severity: medium -Tags: +Tags: category: - Compliance fedramp_low_rev_4: @@ -20,10 +37,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -36,5 +53,4 @@ Tags: - AWS/ELB soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: ELB application load balancers should drop HTTP headers \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_lb_redirect_http_request_to_https.yaml b/compliance/controls/aws/aws_elb_application_lb_redirect_http_request_to_https.yaml old mode 100755 new mode 100644 index 7c397c31a..02aeca0d0 --- a/compliance/controls/aws/aws_elb_application_lb_redirect_http_request_to_https.yaml +++ b/compliance/controls/aws/aws_elb_application_lb_redirect_http_request_to_https.yaml @@ -1,14 +1,47 @@ +Description: To help protect data in transit, ensure that your Application Load Balancer automatically redirects unencrypted HTTP requests to HTTPS. ID: aws_elb_application_lb_redirect_http_request_to_https -Title: "ELB application load balancers should redirect HTTP requests to HTTPS" -Description: "To help protect data in transit, ensure that your Application Load Balancer automatically redirects unencrypted HTTP requests to HTTPS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with detailed_listeners as (\n select\n arn,\n load_balancer_arn,\n protocol\n from\n aws_ec2_load_balancer_listener,\n jsonb_array_elements(default_actions) as ac\n where\n split_part(arn,'/',2) = 'app'\n and protocol = 'HTTP'\n and ac ->> 'Type' = 'redirect'\n and ac -> 'RedirectConfig' ->> 'Protocol' = 'HTTPS'\n)\nselect\n a.arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.load_balancer_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when b.load_balancer_arn is not null then a.title || ' associated with HTTP redirection.'\n else a.title || ' not associated with HTTP redirection.'\n end as reason\n \n , a.region, a.account_id\nfrom\n aws_ec2_application_load_balancer a\n left join detailed_listeners b on a.arn = b.load_balancer_arn;\n" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer - aws_ec2_load_balancer_listener Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + WITH detailed_listeners AS ( + SELECT + arn, + load_balancer_arn, + protocol + FROM + aws_ec2_load_balancer_listener, + jsonb_array_elements(default_actions) AS ac + WHERE + split_part(arn, '/', 2) = 'app' + AND protocol = 'HTTP' + AND ac ->> 'Type' = 'redirect' + AND ac -> 'RedirectConfig' ->> 'Protocol' = 'HTTPS' + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.load_balancer_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.load_balancer_arn IS NOT NULL THEN a.title || ' associated with HTTP redirection.' + ELSE a.title || ' not associated with HTTP redirection.' + END AS reason, + a.region, + a.account_id + FROM + aws_ec2_application_load_balancer a + LEFT JOIN detailed_listeners b + ON a.arn = b.load_balancer_arn Severity: high Tags: category: @@ -29,12 +62,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -47,5 +80,4 @@ Tags: - AWS/ELB soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: ELB application load balancers should redirect HTTP requests to HTTPS \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_lb_waf_enabled.yaml b/compliance/controls/aws/aws_elb_application_lb_waf_enabled.yaml old mode 100755 new mode 100644 index 598f5c3a2..a05b7d348 --- a/compliance/controls/aws/aws_elb_application_lb_waf_enabled.yaml +++ b/compliance/controls/aws/aws_elb_application_lb_waf_enabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure AWS WAF is enabled on Elastic Load Balancers (ELB) to help protect web applications. ID: aws_elb_application_lb_waf_enabled -Title: "ELB application load balancers should have Web Application Firewall (WAF) enabled" -Description: "Ensure AWS WAF is enabled on Elastic Load Balancers (ELB) to help protect web applications." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when load_balancer_attributes @> '[{\"Key\":\"waf.fail_open.enabled\",\"Value\":\"true\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when load_balancer_attributes @> '[{\"Key\":\"waf.fail_open.enabled\",\"Value\":\"true\"}]' then title || ' WAF enabled.'\n else title || ' WAF disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_application_load_balancer;\n" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN load_balancer_attributes @> '[{"Key":"waf.fail_open.enabled","Value":"true"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN load_balancer_attributes @> '[{"Key":"waf.fail_open.enabled","Value":"true"}]' THEN title || ' WAF enabled.' + ELSE title || ' WAF disabled.' + END AS reason, + region, + account_id + FROM + aws_ec2_application_load_balancer; Severity: high Tags: category: @@ -20,12 +37,12 @@ Tags: - "true" ffiec: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -38,5 +55,4 @@ Tags: - AWS/ELB soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: ELB application load balancers should have Web Application Firewall (WAF) enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_lb_with_outbound_rule.yaml b/compliance/controls/aws/aws_elb_application_lb_with_outbound_rule.yaml old mode 100755 new mode 100644 index f99b849e6..b344708b0 --- a/compliance/controls/aws/aws_elb_application_lb_with_outbound_rule.yaml +++ b/compliance/controls/aws/aws_elb_application_lb_with_outbound_rule.yaml @@ -1,53 +1,54 @@ +Description: Ensure application load balancers have at least one outbound rule in all the attached security groups. A security group without any outbound rule rejects all outgoing traffic. This means that all outgoing traffic originating from your cloud assets (instances, containers, etc.) will be dropped when it reaches the ELB layer. ID: aws_elb_application_lb_with_outbound_rule -Title: "ELB application load balancers should have at least one outbound rule" -Description: "Ensure application load balancers have at least one outbound rule in all the attached security groups. A security group without any outbound rule rejects all outgoing traffic. This means that all outgoing traffic originating from your cloud assets (instances, containers, etc.) will be dropped when it reaches the ELB layer." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with sg_with_outbound as ( - select + ListOfTables: + - aws_ec2_application_load_balancer + - aws_vpc_security_group_rule + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + WITH sg_with_outbound AS ( + SELECT arn, sg - from + FROM aws_ec2_application_load_balancer, - jsonb_array_elements_text(security_groups) as sg - left join aws_vpc_security_group_rule as sgr on sg = sgr.group_id - where + jsonb_array_elements_text(security_groups) AS sg + LEFT JOIN aws_vpc_security_group_rule AS sgr ON sg = sgr.group_id + WHERE sgr.type = 'egress' - group by + GROUP BY sg, arn - ), application_lb_without_outbound as ( - select - distinct arn - from + ), + application_lb_without_outbound AS ( + SELECT + DISTINCT arn + FROM aws_ec2_application_load_balancer, - jsonb_array_elements_text(security_groups) as s - where - s not in ( select sg from sg_with_outbound) + jsonb_array_elements_text(security_groups) AS s + WHERE + s NOT IN (SELECT sg FROM sg_with_outbound) ) - select - distinct a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.security_groups is null then 'alarm' - when o.arn is not null then 'alarm' - else 'ok' - end as status, - case - when a.security_groups is null then a.title || ' does not have security group attached.' - when o.arn is not null then a.title || ' all attached security groups does not have outbound rule(s).' - else a.title || ' all attached security groups have outbound rule(s).' - end as reason - from - aws_ec2_application_load_balancer as a - left join application_lb_without_outbound as o on a.arn = o.arn; - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - - aws_vpc_security_group_rule - Parameters: [] + SELECT + DISTINCT a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.security_groups IS NULL THEN 'alarm' + WHEN o.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.security_groups IS NULL THEN a.title || ' does not have security group attached.' + WHEN o.arn IS NOT NULL THEN a.title || ' all attached security groups do not have outbound rule(s).' + ELSE a.title || ' all attached security groups have outbound rule(s).' + END AS reason + FROM + aws_ec2_application_load_balancer AS a + LEFT JOIN application_lb_without_outbound AS o ON a.arn = o.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB application load balancers should have at least one outbound rule \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_network_lb_use_listeners.yaml b/compliance/controls/aws/aws_elb_application_network_lb_use_listeners.yaml old mode 100755 new mode 100644 index e2d8136c0..f29fa4e78 --- a/compliance/controls/aws/aws_elb_application_network_lb_use_listeners.yaml +++ b/compliance/controls/aws/aws_elb_application_network_lb_use_listeners.yaml @@ -1,11 +1,18 @@ +Description: Ensure that application and network load balancer must have one or more listeners. A listener is a process that checks for connection requests, using the protocol and port that you configure. The rules that you define for a listener determine how the load balancer routes requests to its registered targets. ID: aws_elb_application_network_lb_use_listeners -Title: "ELB application and network load balancers should use listeners" -Description: "Ensure that application and network load balancer must have one or more listeners. A listener is a process that checks for connection requests, using the protocol and port that you configure. The rules that you define for a listener determine how the load balancer routes requests to its registered targets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with load_balancers as ( - select + ListOfTables: + - aws_ec2_network_load_balancer + - aws_ec2_application_load_balancer + - aws_ec2_load_balancer_listener + Parameters: [] + PrimaryTable: aws_ec2_network_load_balancer + QueryToExecute: | + WITH load_balancers AS ( + SELECT n.arn, n.title, n.region, @@ -14,10 +21,10 @@ Query: n.og_resource_id, tags, _ctx - from - aws_ec2_network_load_balancer as n - union - select + FROM + aws_ec2_network_load_balancer AS n + UNION + SELECT a.arn, a.title, a.region, @@ -26,31 +33,25 @@ Query: a.og_resource_id, tags, _ctx - from - aws_ec2_application_load_balancer as a + FROM + aws_ec2_application_load_balancer AS a ) - select - distinct lb.arn as resource, - lb.og_account_id as og_account_id, - lb.og_resource_id as og_resource_id, - case - when l.load_balancer_arn is not null then 'ok' - else 'alarm' - end as status, - case - when l.load_balancer_arn is not null then lb.title || ' uses listener.' - else lb.title || ' does not uses listener.' - end as reason - from - load_balancers as lb - left join aws_ec2_load_balancer_listener as l on lb.arn = l.load_balancer_arn; - PrimaryTable: aws_ec2_network_load_balancer - ListOfTables: - - aws_ec2_network_load_balancer - - aws_ec2_application_load_balancer - - aws_ec2_load_balancer_listener - Parameters: [] + SELECT + DISTINCT lb.arn AS resource, + lb.og_account_id AS og_account_id, + lb.og_resource_id AS og_resource_id, + CASE + WHEN l.load_balancer_arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN l.load_balancer_arn IS NOT NULL THEN lb.title || ' uses listener.' + ELSE lb.title || ' does not use listener.' + END AS reason + FROM + load_balancers AS lb + LEFT JOIN aws_ec2_load_balancer_listener AS l + ON lb.arn = l.load_balancer_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB application and network load balancers should use listeners \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_application_network_lb_use_ssl_certificate.yaml b/compliance/controls/aws/aws_elb_application_network_lb_use_ssl_certificate.yaml old mode 100755 new mode 100644 index 873ad1b56..03327399b --- a/compliance/controls/aws/aws_elb_application_network_lb_use_ssl_certificate.yaml +++ b/compliance/controls/aws/aws_elb_application_network_lb_use_ssl_certificate.yaml @@ -1,68 +1,77 @@ +Description: Ensure that Application Load Balancers and Network Load Balancers are configured to use certificates from AWS Certificate Manager (ACM). This rule is compliant if at least 1 load balancer is configured without a certificate from ACM. ID: aws_elb_application_network_lb_use_ssl_certificate -Title: "ELB application and network load balancers should only use SSL or HTTPS listeners" -Description: "Ensure that Application Load Balancers and Network Load Balancers are configured to use certificates from AWS Certificate Manager (ACM). This rule is compliant if at least 1 load balancer is configured without a certificate from ACM." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_application_load_balancer + - aws_ec2_load_balancer_listener + - aws_ec2_network_load_balancer + Parameters: [] + PrimaryTable: "" QueryToExecute: | - with listeners_without_certificate as ( - select + WITH listeners_without_certificate AS ( + SELECT load_balancer_arn, - count(*) as count - from + COUNT(*) AS count + FROM aws_ec2_load_balancer_listener - where arn not in - ( select arn from aws_ec2_load_balancer_listener, jsonb_array_elements(certificates) as c - where c ->> 'CertificateArn' like 'arn:aws:acm%' ) - group by load_balancer_arn + WHERE arn NOT IN ( + SELECT + arn + FROM + aws_ec2_load_balancer_listener, + jsonb_array_elements(certificates) AS c + WHERE + c ->> 'CertificateArn' LIKE 'arn:aws:acm%' + ) + GROUP BY + load_balancer_arn ), - all_application_network_load_balacer as ( - select + all_application_network_load_balancer AS ( + SELECT arn, account_id, region, title, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_ec2_application_load_balancer' as og_table_name, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_ec2_application_load_balancer' AS og_table_name, _ctx - from + FROM aws_ec2_application_load_balancer - union - select + UNION + SELECT arn, account_id, region, title, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_ec2_network_load_balancer' as og_table_name, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_ec2_network_load_balancer' AS og_table_name, _ctx - from + FROM aws_ec2_network_load_balancer ) - select - a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - a.og_table_name as og_table_name, - case - when b.load_balancer_arn is null then 'ok' - else 'alarm' - end as status, - case - when b.load_balancer_arn is null then a.title || ' uses certificates provided by ACM.' - else a.title || ' has ' || b.count || ' listeners which do not use certificates provided by ACM.' - end as reason - , a.region, a.account_id - from - all_application_network_load_balacer as a - left join listeners_without_certificate as b on a.arn = b.load_balancer_arn; - PrimaryTable: "" - ListOfTables: - - aws_ec2_application_load_balancer - - aws_ec2_load_balancer_listener - - aws_ec2_network_load_balancer - Parameters: [] + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + a.og_table_name AS og_table_name, + CASE + WHEN b.load_balancer_arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.load_balancer_arn IS NULL THEN a.title || ' uses certificates provided by ACM.' + ELSE a.title || ' has ' || b.count || ' listeners which do not use certificates provided by ACM.' + END AS reason, + a.region, + a.account_id + FROM + all_application_network_load_balancer AS a + LEFT JOIN listeners_without_certificate AS b ON a.arn = b.load_balancer_arn; Severity: low Tags: category: @@ -91,5 +100,4 @@ Tags: - "true" service: - AWS/ELB -IntegrationType: - - aws_cloud_account +Title: ELB application and network load balancers should only use SSL or HTTPS listeners \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_classic_lb_cross_zone_load_balancing_enabled.yaml b/compliance/controls/aws/aws_elb_classic_lb_cross_zone_load_balancing_enabled.yaml old mode 100755 new mode 100644 index aa2943741..791f420ba --- a/compliance/controls/aws/aws_elb_classic_lb_cross_zone_load_balancing_enabled.yaml +++ b/compliance/controls/aws/aws_elb_classic_lb_cross_zone_load_balancing_enabled.yaml @@ -1,13 +1,30 @@ +Description: Enable cross-zone load balancing for your Elastic Load Balancers (ELBs) to help maintain adequate capacity and availability. The cross-zone load balancing reduces the need to maintain equivalent numbers of instances in each enabled availability zone. ID: aws_elb_classic_lb_cross_zone_load_balancing_enabled -Title: "ELB classic load balancers should have cross-zone load balancing enabled" -Description: "Enable cross-zone load balancing for your Elastic Load Balancers (ELBs) to help maintain adequate capacity and availability. The cross-zone load balancing reduces the need to maintain equivalent numbers of instances in each enabled availability zone." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when cross_zone_load_balancing_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when cross_zone_load_balancing_enabled then title || ' cross-zone load balancing enabled.'\n else title || ' cross-zone load balancing disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_classic_load_balancer;\n" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cross_zone_load_balancing_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cross_zone_load_balancing_enabled THEN title || ' cross-zone load balancing enabled.' + ELSE title || ' cross-zone load balancing disabled.' + END AS reason, + region, + account_id + FROM + aws_ec2_classic_load_balancer; Severity: low Tags: category: @@ -26,17 +43,16 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: - aws service: - AWS/ELB -IntegrationType: - - aws_cloud_account +Title: ELB classic load balancers should have cross-zone load balancing enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_classic_lb_desync_mitigation_mode.yaml b/compliance/controls/aws/aws_elb_classic_lb_desync_mitigation_mode.yaml old mode 100755 new mode 100644 index 6be2910f8..d88d0651f --- a/compliance/controls/aws/aws_elb_classic_lb_desync_mitigation_mode.yaml +++ b/compliance/controls/aws/aws_elb_classic_lb_desync_mitigation_mode.yaml @@ -1,13 +1,40 @@ +Description: This control checks whether a Classic Load Balancer is configured with defensive or strictest desync mitigation mode. This control will fail if the Classic Load Balancer is not configured with defensive or strictest desync mitigation mode. ID: aws_elb_classic_lb_desync_mitigation_mode -Title: "ELB classic load balancers should be configured with defensive or strictest desync mitigation mode" -Description: "This control checks whether a Classic Load Balancer is configured with defensive or strictest desync mitigation mode. This control will fail if the Classic Load Balancer is not configured with defensive or strictest desync mitigation mode." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with app_lb_desync_mitigation_mode as (\n select\n arn,\n a ->> 'Key',\n a ->> 'Value' as v\n from\n aws_ec2_classic_load_balancer,\n jsonb_array_elements(additional_attributes) as a\n where\n a ->> 'Key' = 'elb.http.desyncmitigationmode'\n)\nselect\n c.arn as resource,\n c.og_account_id as og_account_id,\n c.og_resource_id as og_resource_id,\n case\n when m.v = any(array['defensive', 'strictest']) then 'ok'\n else 'alarm'\n end as status,\n title || ' has ' || m.v || ' desync mitigation mode.' as reason\n \n , region, account_id\nfrom\n aws_ec2_classic_load_balancer as c\n left join app_lb_desync_mitigation_mode as m on c.arn = m.arn;\n" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + WITH app_lb_desync_mitigation_mode AS ( + SELECT + arn, + a ->> 'Key', + a ->> 'Value' AS v + FROM + aws_ec2_classic_load_balancer, + jsonb_array_elements(additional_attributes) AS a + WHERE + a ->> 'Key' = 'elb.http.desyncmitigationmode' + ) + SELECT + c.arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN m.v = ANY(ARRAY['defensive', 'strictest']) THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' has ' || m.v || ' desync mitigation mode.' AS reason, + region, + account_id + FROM + aws_ec2_classic_load_balancer AS c + LEFT JOIN app_lb_desync_mitigation_mode AS m + ON c.arn = m.arn; Severity: medium Tags: aws_foundational_security: @@ -22,5 +49,4 @@ Tags: - aws service: - AWS/ELB -IntegrationType: - - aws_cloud_account +Title: ELB classic load balancers should be configured with defensive or strictest desync mitigation mode \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_classic_lb_multiple_az_configured.yaml b/compliance/controls/aws/aws_elb_classic_lb_multiple_az_configured.yaml old mode 100755 new mode 100644 index 7c2a92ede..3006814f9 --- a/compliance/controls/aws/aws_elb_classic_lb_multiple_az_configured.yaml +++ b/compliance/controls/aws/aws_elb_classic_lb_multiple_az_configured.yaml @@ -1,13 +1,27 @@ +Description: This control checks whether a Classic Load Balancer has been configured to span multiple Availability Zones. The control fails if the Classic Load Balancer does not span multiple Availability Zones. ID: aws_elb_classic_lb_multiple_az_configured -Title: "ELB classic load balancers should span multiple availability zones" -Description: "This control checks whether a Classic Load Balancer has been configured to span multiple Availability Zones. The control fails if the Classic Load Balancer does not span multiple Availability Zones." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(availability_zones) < 2 then 'alarm'\n else 'ok'\n end as status,\n title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason\n \n , region, account_id\nfrom\n aws_ec2_classic_load_balancer;\n" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason, + region, + account_id + FROM + aws_ec2_classic_load_balancer; Severity: medium Tags: aws_foundational_security: @@ -22,5 +36,4 @@ Tags: - aws service: - AWS/ELB -IntegrationType: - - aws_cloud_account +Title: ELB classic load balancers should span multiple availability zones \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_classic_lb_no_registered_instance.yaml b/compliance/controls/aws/aws_elb_classic_lb_no_registered_instance.yaml old mode 100755 new mode 100644 index 3a10b24dd..6133b5068 --- a/compliance/controls/aws/aws_elb_classic_lb_no_registered_instance.yaml +++ b/compliance/controls/aws/aws_elb_classic_lb_no_registered_instance.yaml @@ -1,14 +1,25 @@ +Description: This control checks whether an ELB classic load balancer has registered instances. The control fails if an ELB classic load balancer has zero instances registered. ID: aws_elb_classic_lb_no_registered_instance -Title: "ELB classic load balancers should have at least one registered instance" -Description: "This control checks whether an ELB classic load balancer has registered instances. The control fails if an ELB classic load balancer has zero instances registered." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(instances) = 0 then 'alarm'\n else 'ok'\n end as status,\n title || ' has ' || jsonb_array_length(instances) || ' instance(s) registered.' as reason\n \n \nfrom\n aws_ec2_classic_load_balancer;" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(instances) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(instances) || ' instance(s) registered.' AS reason + FROM + aws_ec2_classic_load_balancer; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB classic load balancers should have at least one registered instance \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_classic_lb_use_ssl_certificate.yaml b/compliance/controls/aws/aws_elb_classic_lb_use_ssl_certificate.yaml old mode 100755 new mode 100644 index 3a63126d7..5d648ec6b --- a/compliance/controls/aws/aws_elb_classic_lb_use_ssl_certificate.yaml +++ b/compliance/controls/aws/aws_elb_classic_lb_use_ssl_certificate.yaml @@ -1,13 +1,44 @@ +Description: Because sensitive data can exist and to help protect data at transit, ensure encryption is enabled for your Elastic Load Balancing. ID: aws_elb_classic_lb_use_ssl_certificate -Title: "ELB classic load balancers should use SSL certificates" -Description: "Because sensitive data can exist and to help protect data at transit, ensure encryption is enabled for your Elastic Load Balancing." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with detailed_classic_listeners as (\n select\n name,\n og_resource_id\n from\n aws_ec2_classic_load_balancer,\n jsonb_array_elements(listener_descriptions) as listener_description\n where\n listener_description -> 'Listener' ->> 'Protocol' in ('HTTPS', 'SSL', 'TLS')\n and listener_description -> 'Listener' ->> 'SSLCertificateId' like 'arn:aws:acm%'\n)\nselect\n 'arn:' || a.partition || ':elasticloadbalancing:' || a.region || ':' || a.account_id || ':loadbalancer/' || a.name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.listener_descriptions is null then 'skip'\n when b.name is not null then 'alarm'\n else 'ok'\n end as status,\n case\n when a.listener_descriptions is null then a.title || ' has no listener.'\n when b.name is not null then a.title || ' does not use certificates provided by ACM.'\n else a.title || ' uses certificates provided by ACM.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_classic_load_balancer as a\n left join detailed_classic_listeners as b on a.og_resource_id = b.og_resource_id;\n" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + WITH detailed_classic_listeners AS ( + SELECT + name, + og_resource_id + FROM + aws_ec2_classic_load_balancer, + jsonb_array_elements(listener_descriptions) AS listener_description + WHERE + listener_description -> 'Listener' ->> 'Protocol' IN ('HTTPS', 'SSL', 'TLS') + AND listener_description -> 'Listener' ->> 'SSLCertificateId' LIKE 'arn:aws:acm%' + ) + SELECT + 'arn:' || a.partition || ':elasticloadbalancing:' || a.region || ':' || a.account_id || ':loadbalancer/' || a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.listener_descriptions IS NULL THEN 'skip' + WHEN b.name IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.listener_descriptions IS NULL THEN a.title || ' has no listener.' + WHEN b.name IS NOT NULL THEN a.title || ' does not use certificates provided by ACM.' + ELSE a.title || ' uses certificates provided by ACM.' + END AS reason, + region, + account_id + FROM + aws_ec2_classic_load_balancer AS a + LEFT JOIN detailed_classic_listeners AS b ON a.og_resource_id = b.og_resource_id Severity: high Tags: category: @@ -28,12 +59,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +77,4 @@ Tags: - AWS/ELB soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: ELB classic load balancers should use SSL certificates \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_classic_lb_use_tls_https_listeners.yaml b/compliance/controls/aws/aws_elb_classic_lb_use_tls_https_listeners.yaml old mode 100755 new mode 100644 index 392b23539..e2fd9cb36 --- a/compliance/controls/aws/aws_elb_classic_lb_use_tls_https_listeners.yaml +++ b/compliance/controls/aws/aws_elb_classic_lb_use_tls_https_listeners.yaml @@ -1,13 +1,32 @@ +Description: Ensure that your Elastic Load Balancers (ELBs) are configured with SSL or HTTPS listeners. Because sensitive data can exist, enable encryption in transit to help protect that data. ID: aws_elb_classic_lb_use_tls_https_listeners -Title: "ELB classic load balancers should only use SSL or HTTPS listeners" -Description: "Ensure that your Elastic Load Balancers (ELBs) are configured with SSL or HTTPS listeners. Because sensitive data can exist, enable encryption in transit to help protect that data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':elasticloadbalancing:' || region || ':' || account_id || ':loadbalancer/' || title as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when listener_description -> 'Listener' ->> 'Protocol' in ('HTTPS', 'SSL', 'TLS') then 'ok'\n else 'alarm'\n end as status,\n case\n when listener_description -> 'Listener' ->> 'Protocol' = 'HTTPS' then title || ' configured with HTTPS protocol.'\n when listener_description -> 'Listener' ->> 'Protocol' = 'SSL' then title || ' configured with TLS protocol.'\n else title || ' configured with ' || (listener_description -> 'Listener' ->> 'Protocol') || ' protocol.'\n end as reason\n \n , region, account_id\nfrom\n aws_ec2_classic_load_balancer,\n jsonb_array_elements(listener_descriptions) as listener_description;\n" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + SELECT + 'arn:' || partition || ':elasticloadbalancing:' || region || ':' || account_id || ':loadbalancer/' || title AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN listener_description -> 'Listener' ->> 'Protocol' IN ('HTTPS', 'SSL', 'TLS') THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN listener_description -> 'Listener' ->> 'Protocol' = 'HTTPS' THEN title || ' configured with HTTPS protocol.' + WHEN listener_description -> 'Listener' ->> 'Protocol' = 'SSL' THEN title || ' configured with TLS protocol.' + ELSE title || ' configured with ' || (listener_description -> 'Listener' ->> 'Protocol') || ' protocol.' + END AS reason, + region, + account_id + FROM + aws_ec2_classic_load_balancer, + jsonb_array_elements(listener_descriptions) AS listener_description; Severity: high Tags: category: @@ -28,12 +47,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +65,4 @@ Tags: - AWS/ELB soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: ELB classic load balancers should only use SSL or HTTPS listeners \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_classic_lb_with_inbound_rule.yaml b/compliance/controls/aws/aws_elb_classic_lb_with_inbound_rule.yaml old mode 100755 new mode 100644 index 3b620ce7e..5562d8d0e --- a/compliance/controls/aws/aws_elb_classic_lb_with_inbound_rule.yaml +++ b/compliance/controls/aws/aws_elb_classic_lb_with_inbound_rule.yaml @@ -1,53 +1,53 @@ +Description: Ensure classic load balancer have at least one inbound rule in all the attached security groups. ID: aws_elb_classic_lb_with_inbound_rule -Title: "ELB classic load balancers should have at least one inbound rule" -Description: "Ensure classic load balancer have at least one inbound rule in all the attached security groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with sg_with_inbound as ( - select + ListOfTables: + - aws_ec2_classic_load_balancer + - aws_vpc_security_group_rule + Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + WITH sg_with_inbound AS ( + SELECT arn, sg - from + FROM aws_ec2_classic_load_balancer, - jsonb_array_elements_text(security_groups) as sg - left join aws_vpc_security_group_rule as sgr on sg = sgr.group_id - where + jsonb_array_elements_text(security_groups) AS sg + LEFT JOIN aws_vpc_security_group_rule AS sgr ON sg = sgr.group_id + WHERE sgr.type = 'ingress' - group by + GROUP BY sg, arn - ), classic_lb_without_inbound as ( - select - distinct arn - from + ), classic_lb_without_inbound AS ( + SELECT + DISTINCT arn + FROM aws_ec2_classic_load_balancer, - jsonb_array_elements_text(security_groups) as s - where - s not in ( select sg from sg_with_inbound) + jsonb_array_elements_text(security_groups) AS s + WHERE + s NOT IN (SELECT sg FROM sg_with_inbound) ) - select - distinct c.arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when c.security_groups is null then 'alarm' - when i.arn is not null then 'alarm' - else 'ok' - end as status, - case - when c.security_groups is null then c.title || ' does not have security group attached.' - when i.arn is not null then c.title || ' all attached security groups do not have inbound rule(s).' - else c.title || ' all attached security groups have inbound rule(s).' - end as reason - from - aws_ec2_classic_load_balancer as c - left join classic_lb_without_inbound as i on c.arn = i.arn; - PrimaryTable: aws_ec2_classic_load_balancer - ListOfTables: - - aws_ec2_classic_load_balancer - - aws_vpc_security_group_rule - Parameters: [] + SELECT + DISTINCT c.arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.security_groups IS NULL THEN 'alarm' + WHEN i.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.security_groups IS NULL THEN c.title || ' does not have security group attached.' + WHEN i.arn IS NOT NULL THEN c.title || ' all attached security groups do not have inbound rule(s).' + ELSE c.title || ' all attached security groups have inbound rule(s).' + END AS reason + FROM + aws_ec2_classic_load_balancer AS c + LEFT JOIN classic_lb_without_inbound AS i ON c.arn = i.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB classic load balancers should have at least one inbound rule \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_classic_lb_with_outbound_rule.yaml b/compliance/controls/aws/aws_elb_classic_lb_with_outbound_rule.yaml old mode 100755 new mode 100644 index 7910be51e..a3d760d7e --- a/compliance/controls/aws/aws_elb_classic_lb_with_outbound_rule.yaml +++ b/compliance/controls/aws/aws_elb_classic_lb_with_outbound_rule.yaml @@ -1,53 +1,54 @@ +Description: Ensure classic load balancers have at least one outbound rule in all the attached security groups. A security group without any outbound rule rejects all outgoing traffic. This means that all outgoing traffic originating from your cloud assets (instances, containers, etc.) will be dropped when it reaches the ELB layer. ID: aws_elb_classic_lb_with_outbound_rule -Title: "ELB classic load balancers should have at least one outbound rule" -Description: "Ensure classic load balancers have at least one outbound rule in all the attached security groups. A security group without any outbound rule rejects all outgoing traffic. This means that all outgoing traffic originating from your cloud assets (instances, containers, etc.) will be dropped when it reaches the ELB layer." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with sg_with_outbound as ( - select + ListOfTables: + - aws_ec2_classic_load_balancer + - aws_vpc_security_group_rule + Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + WITH sg_with_outbound AS ( + SELECT arn, sg - from + FROM aws_ec2_classic_load_balancer, - jsonb_array_elements_text(security_groups) as sg - left join aws_vpc_security_group_rule as sgr on sg = sgr.group_id - where + JSONB_ARRAY_ELEMENTS_TEXT(security_groups) AS sg + LEFT JOIN aws_vpc_security_group_rule AS sgr ON sg = sgr.group_id + WHERE sgr.type = 'egress' - group by - sg, arn - ), classic_lb_without_outbound as ( - select - distinct arn - from + GROUP BY + sg, + arn + ), classic_lb_without_outbound AS ( + SELECT + DISTINCT arn + FROM aws_ec2_classic_load_balancer, - jsonb_array_elements_text(security_groups) as s - where - s not in ( select sg from sg_with_outbound) + JSONB_ARRAY_ELEMENTS_TEXT(security_groups) AS s + WHERE + s NOT IN (SELECT sg FROM sg_with_outbound) ) - select - distinct c.arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when c.security_groups is null then 'alarm' - when o.arn is not null then 'alarm' - else 'ok' - end as status, - case - when c.security_groups is null then c.title || ' does not have security group attached.' - when o.arn is not null then c.title || ' all attached security groups do not have outbound rule(s).' - else c.title || ' all attached security groups have outbound rule(s).' - end as reason - from - aws_ec2_classic_load_balancer as c - left join classic_lb_without_outbound as o on c.arn = o.arn; - PrimaryTable: aws_ec2_classic_load_balancer - ListOfTables: - - aws_ec2_classic_load_balancer - - aws_vpc_security_group_rule - Parameters: [] + SELECT + DISTINCT c.arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.security_groups IS NULL THEN 'alarm' + WHEN o.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.security_groups IS NULL THEN c.title || ' does not have security group attached.' + WHEN o.arn IS NOT NULL THEN c.title || ' all attached security groups do not have outbound rule(s).' + ELSE c.title || ' all attached security groups have outbound rule(s).' + END AS reason + FROM + aws_ec2_classic_load_balancer AS c + LEFT JOIN classic_lb_without_outbound AS o ON c.arn = o.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB classic load balancers should have at least one outbound rule \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_listener_use_secure_ssl_cipher.yaml b/compliance/controls/aws/aws_elb_listener_use_secure_ssl_cipher.yaml old mode 100755 new mode 100644 index 79bcf1f9c..92af577f7 --- a/compliance/controls/aws/aws_elb_listener_use_secure_ssl_cipher.yaml +++ b/compliance/controls/aws/aws_elb_listener_use_secure_ssl_cipher.yaml @@ -1,28 +1,28 @@ +Description: Ensure that ELB listeners do not have any insecure SSL ciphers. Using insecure and deprecated ciphers for your ELB Predefined Security Policy or Custom Security Policy could make the SSL connection between the client and the load balancer vulnerable to exploits. ID: aws_elb_listener_use_secure_ssl_cipher -Title: "ELB listeners should use secure SSL cipher" -Description: "Ensure that ELB listeners do not have any insecure SSL ciphers. Using insecure and deprecated ciphers for your ELB Predefined Security Policy or Custom Security Policy could make the SSL connection between the client and the load balancer vulnerable to exploits." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - load_balancer_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when ssl_policy like any(array['ELBSecurityPolicy-TLS-1-2-2017-01', 'ELBSecurityPolicy-TLS-1-1-2017-01']) then 'ok' - else 'alarm' - end as status, - case - when ssl_policy like any (array['ELBSecurityPolicy-TLS-1-2-2017-01', 'ELBSecurityPolicy-TLS-1-1-2017-01']) then title || ' uses secure SSL cipher.' - else title || ' uses insecure SSL cipher.' - end as reason - from - aws_ec2_load_balancer_listener; - PrimaryTable: aws_ec2_load_balancer_listener ListOfTables: - aws_ec2_load_balancer_listener Parameters: [] + PrimaryTable: aws_ec2_load_balancer_listener + QueryToExecute: | + SELECT + load_balancer_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ssl_policy LIKE ANY(ARRAY['ELBSecurityPolicy-TLS-1-2-2017-01', 'ELBSecurityPolicy-TLS-1-1-2017-01']) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ssl_policy LIKE ANY(ARRAY['ELBSecurityPolicy-TLS-1-2-2017-01', 'ELBSecurityPolicy-TLS-1-1-2017-01']) THEN title || ' uses secure SSL cipher.' + ELSE title || ' uses insecure SSL cipher.' + END AS reason + FROM + aws_ec2_load_balancer_listener; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB listeners should use secure SSL cipher \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_network_lb_tls_listener_security_policy_configured.yaml b/compliance/controls/aws/aws_elb_network_lb_tls_listener_security_policy_configured.yaml old mode 100755 new mode 100644 index ba483bc7e..6fd07f4c1 --- a/compliance/controls/aws/aws_elb_network_lb_tls_listener_security_policy_configured.yaml +++ b/compliance/controls/aws/aws_elb_network_lb_tls_listener_security_policy_configured.yaml @@ -1,53 +1,60 @@ +Description: Ensure that your Network Load Balancers (NLBs) are configured with a TLS listener security policy. Using insecure ciphers for your NLB Predefined or Custom Security Policy could make the TLS connection between the client and the load balancer vulnerable to exploits. ID: aws_elb_network_lb_tls_listener_security_policy_configured -Title: "ELB network load balancers should have TLS listener security policy configured" -Description: "Ensure that your Network Load Balancers (NLBs) are configured with a TLS listener security policy. Using insecure ciphers for your NLB Predefined or Custom Security Policy could make the TLS connection between the client and the load balancer vulnerable to exploits." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with tls_listeners as ( - select - distinct load_balancer_arn - from - aws_ec2_load_balancer_listener - where - protocol = 'TLS' - and ssl_policy not in ('ELBSecurityPolicy-2016-08', 'ELBSecurityPolicy-FS-2018-0', 'ELBSecurityPolicy-TLS13-1-2-Ext1-2021-06', 'ELBSecurityPolicy-TLS13-1-2-2021-06') - group by - load_balancer_arn - ), nwl_without_tls_listener as ( - select - load_balancer_arn, - count(*) - from - aws_ec2_load_balancer_listener - where - protocol = 'TLS' - group by - load_balancer_arn - ) - select - lb.arn as resource, - lb.og_account_id as og_account_id, - lb.og_resource_id as og_resource_id, - case - when l.load_balancer_arn is not null and lb.arn in (select load_balancer_arn from tls_listeners) then 'alarm' - when l.load_balancer_arn is not null then 'ok' - else 'info' - end as status, - case - when l.load_balancer_arn is not null and lb.arn in (select load_balancer_arn from tls_listeners) then lb.title || ' TLS listener security policy not updated.' - when l.load_balancer_arn is not null then lb.title || ' TLS listener security policy updated.' - else lb.title || ' does not use TLS listener.' - end as reason - from - aws_ec2_network_load_balancer as lb - left join nwl_without_tls_listener as l on l.load_balancer_arn = lb.arn; - PrimaryTable: aws_ec2_network_load_balancer ListOfTables: - aws_ec2_load_balancer_listener - aws_ec2_network_load_balancer Parameters: [] + PrimaryTable: aws_ec2_network_load_balancer + QueryToExecute: | + WITH tls_listeners AS ( + SELECT + DISTINCT load_balancer_arn + FROM + aws_ec2_load_balancer_listener + WHERE + protocol = 'TLS' + AND ssl_policy NOT IN ( + 'ELBSecurityPolicy-2016-08', + 'ELBSecurityPolicy-FS-2018-0', + 'ELBSecurityPolicy-TLS13-1-2-Ext1-2021-06', + 'ELBSecurityPolicy-TLS13-1-2-2021-06' + ) + GROUP BY + load_balancer_arn + ), nwl_without_tls_listener AS ( + SELECT + load_balancer_arn, + COUNT(*) + FROM + aws_ec2_load_balancer_listener + WHERE + protocol = 'TLS' + GROUP BY + load_balancer_arn + ) + SELECT + lb.arn AS resource, + lb.og_account_id AS og_account_id, + lb.og_resource_id AS og_resource_id, + CASE + WHEN l.load_balancer_arn IS NOT NULL + AND lb.arn IN (SELECT load_balancer_arn FROM tls_listeners) THEN 'alarm' + WHEN l.load_balancer_arn IS NOT NULL THEN 'ok' + ELSE 'info' + END AS status, + CASE + WHEN l.load_balancer_arn IS NOT NULL + AND lb.arn IN (SELECT load_balancer_arn FROM tls_listeners) THEN lb.title || ' TLS listener security policy not updated.' + WHEN l.load_balancer_arn IS NOT NULL THEN lb.title || ' TLS listener security policy updated.' + ELSE lb.title || ' does not use TLS listener.' + END AS reason + FROM + aws_ec2_network_load_balancer AS lb + LEFT JOIN nwl_without_tls_listener AS l ON l.load_balancer_arn = lb.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB network load balancers should have TLS listener security policy configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_elb_tls_listener_protocol_version.yaml b/compliance/controls/aws/aws_elb_tls_listener_protocol_version.yaml old mode 100755 new mode 100644 index 6672cce2f..534d42f62 --- a/compliance/controls/aws/aws_elb_tls_listener_protocol_version.yaml +++ b/compliance/controls/aws/aws_elb_tls_listener_protocol_version.yaml @@ -1,30 +1,30 @@ +Description: Using insecure ciphers for your ELB Predefined or Custom Security Policy, could make the SSL connection between the client and the load balancer vulnerable to exploits. TLS 1.0 was recommended to be disabled by PCI Council after June 30, 2016. ID: aws_elb_tls_listener_protocol_version -Title: "ELB listeners SSL/TLS protocol version should be checked" -Description: "Using insecure ciphers for your ELB Predefined or Custom Security Policy, could make the SSL connection between the client and the load balancer vulnerable to exploits. TLS 1.0 was recommended to be disabled by PCI Council after June 30, 2016." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - load_balancer_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when protocol <> 'HTTPS' then 'skip' - when protocol = 'HTTPS' and ssl_policy like any(array['Protocol-SSLv3', 'Protocol-TLSv1']) then 'alarm' - else 'ok' - end as status, - case - when protocol <> 'HTTPS' then title || ' uses protocol ' || protocol || '.' - when ssl_policy like any (array['Protocol-SSLv3', 'Protocol-TLSv1']) then title || ' uses insecure SSL or TLS cipher.' - else title || ' uses secure SSL or TLS cipher.' - end as reason - from - aws_ec2_load_balancer_listener; - PrimaryTable: aws_ec2_load_balancer_listener ListOfTables: - aws_ec2_load_balancer_listener Parameters: [] + PrimaryTable: aws_ec2_load_balancer_listener + QueryToExecute: | + SELECT + load_balancer_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN protocol <> 'HTTPS' THEN 'skip' + WHEN protocol = 'HTTPS' AND ssl_policy LIKE ANY (ARRAY['Protocol-SSLv3', 'Protocol-TLSv1']) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN protocol <> 'HTTPS' THEN title || ' uses protocol ' || protocol || '.' + WHEN ssl_policy LIKE ANY (ARRAY['Protocol-SSLv3', 'Protocol-TLSv1']) THEN title || ' uses insecure SSL or TLS cipher.' + ELSE title || ' uses secure SSL or TLS cipher.' + END AS reason + FROM + aws_ec2_load_balancer_listener; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB listeners SSL/TLS protocol version should be checked \ No newline at end of file diff --git a/compliance/controls/aws/aws_emr_account_public_access_blocked.yaml b/compliance/controls/aws/aws_emr_account_public_access_blocked.yaml old mode 100755 new mode 100644 index af4acca8b..942960859 --- a/compliance/controls/aws/aws_emr_account_public_access_blocked.yaml +++ b/compliance/controls/aws/aws_emr_account_public_access_blocked.yaml @@ -1,43 +1,44 @@ +Description: The block public access feature prevents a cluster in a public subnet from launching when any security group associated with the cluster has a rule that allows inbound traffic from IPv4 0.0.0.0/0 or IPv6 ::/0 (public access) on a port, unless the port has been specified as an exception - port 22 is an exception by default. This feature is enabled by default for each AWS Region in your AWS account and is not recommended to be turned off. ID: aws_emr_account_public_access_blocked -Title: "EMR public access should be blocked at account level" -Description: "The block public access feature prevents a cluster in a public subnet from launching when any security group associated with the cluster has a rule that allows inbound traffic from IPv4 0.0.0.0/0 or IPv6 ::/0 (public access) on a port, unless the port has been specified as an exception - port 22 is an exception by default. This feature is enabled by default for each AWS Region in your AWS account and is not recommended to be turned off." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with emr_port_configuration as( - select + ListOfTables: + - aws_emr_block_public_access_configuration + Parameters: [] + PrimaryTable: aws_emr_block_public_access_configuration + QueryToExecute: | + WITH emr_port_configuration AS ( + SELECT region, account_id - from + FROM aws_emr_block_public_access_configuration, - jsonb_array_elements(permitted_public_security_group_rule_ranges) as r - where + jsonb_array_elements(permitted_public_security_group_rule_ranges) AS r + WHERE (r -> 'MaxRange')::int = 22 - and (r-> 'MinRange')::int = 22 - and block_public_security_group_rules + AND (r -> 'MinRange')::int = 22 + AND block_public_security_group_rules ) - select - 'arn:' || c.partition || '::' || c.region || ':' || c.account_id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when not block_public_security_group_rules then 'alarm' - when block_public_security_group_rules and p.region is not null then 'ok' - else 'alarm' - end as status, - case - when not block_public_security_group_rules then c.region || ' EMR block public access disabled.' - when block_public_security_group_rules and p.region is not null then c.region || ' EMR block public access enabled.' - else c.region || ' EMR block public access enabled for ports other than 22.' - end as reason - from - aws_emr_block_public_access_configuration as c - left join emr_port_configuration as p on p.region = c.region and p.account_id = c.account_id - PrimaryTable: aws_emr_block_public_access_configuration - ListOfTables: - - aws_emr_block_public_access_configuration - Parameters: [] + SELECT + 'arn:' || c.partition || '::' || c.region || ':' || c.account_id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN NOT block_public_security_group_rules THEN 'alarm' + WHEN block_public_security_group_rules AND p.region IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT block_public_security_group_rules THEN c.region || ' EMR block public access disabled.' + WHEN block_public_security_group_rules AND p.region IS NOT NULL THEN c.region || ' EMR block public access enabled.' + ELSE c.region || ' EMR block public access enabled for ports other than 22.' + END AS reason + FROM + aws_emr_block_public_access_configuration AS c + LEFT JOIN emr_port_configuration AS p + ON p.region = c.region AND p.account_id = c.account_id Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EMR public access should be blocked at account level \ No newline at end of file diff --git a/compliance/controls/aws/aws_emr_cluster_encryption_at_rest_with_sse_kms.yaml b/compliance/controls/aws/aws_emr_cluster_encryption_at_rest_with_sse_kms.yaml old mode 100755 new mode 100644 index 6deb1057f..1e7bc2c7d --- a/compliance/controls/aws/aws_emr_cluster_encryption_at_rest_with_sse_kms.yaml +++ b/compliance/controls/aws/aws_emr_cluster_encryption_at_rest_with_sse_kms.yaml @@ -1,34 +1,39 @@ +Description: This control checks whether EMR clusters server side encryption (SSE KMS) is enabled with KMS. The check fails if encryption at rest is not enabled with SSE-KMS. ID: aws_emr_cluster_encryption_at_rest_with_sse_kms -Title: "EMR clusters server side encryption (SSE KMS) enabled with KMS" -Description: "This control checks whether EMR clusters server side encryption (SSE KMS) is enabled with KMS. The check fails if encryption at rest is not enabled with SSE-KMS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - cluster_arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when s.name is null then 'alarm' - when not (encryption_configuration -> 'EnableAtRestEncryption')::bool then 'alarm' - when (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'S3EncryptionConfiguration' ->> 'EncryptionMode') = 'SSE-KMS' then 'ok' - else 'alarm' - end as status, - case - when s.name is null then c.title || ' security configuration disabled.' - when not (encryption_configuration -> 'EnableAtRestEncryption')::bool then c.title || ' encryption at rest disabled.' - when (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'S3EncryptionConfiguration' ->> 'EncryptionMode') = 'SSE-KMS' then c.title || ' encryption at rest enabled with SSE KMS.' - else c.title || ' encryption at rest not enabled with SSE KMS.' - end as reason - from - aws_emr_cluster as c - left join aws_emr_security_configuration as s on c.security_configuration = s.name and s.region = s.region and s.account_id = c.account_id; - PrimaryTable: aws_emr_cluster ListOfTables: - aws_emr_cluster - aws_emr_security_configuration Parameters: [] + PrimaryTable: aws_emr_cluster + QueryToExecute: | + SELECT + cluster_arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN s.name IS NULL THEN 'alarm' + WHEN NOT (encryption_configuration -> 'EnableAtRestEncryption')::bool THEN 'alarm' + WHEN (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'S3EncryptionConfiguration' ->> 'EncryptionMode') = 'SSE-KMS' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.name IS NULL THEN c.title || ' security configuration disabled.' + WHEN NOT (encryption_configuration -> 'EnableAtRestEncryption')::bool THEN c.title || ' encryption at rest disabled.' + WHEN (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'S3EncryptionConfiguration' ->> 'EncryptionMode') = 'SSE-KMS' THEN c.title || ' encryption at rest enabled with SSE KMS.' + ELSE c.title || ' encryption at rest not enabled with SSE KMS.' + END AS reason + FROM + aws_emr_cluster AS c + LEFT JOIN + aws_emr_security_configuration AS s + ON + c.security_configuration = s.name + AND s.region = s.region + AND s.account_id = c.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EMR clusters server side encryption (SSE KMS) enabled with KMS \ No newline at end of file diff --git a/compliance/controls/aws/aws_emr_cluster_kerberos_enabled.yaml b/compliance/controls/aws/aws_emr_cluster_kerberos_enabled.yaml old mode 100755 new mode 100644 index f4c8c83ad..c2920603b --- a/compliance/controls/aws/aws_emr_cluster_kerberos_enabled.yaml +++ b/compliance/controls/aws/aws_emr_cluster_kerberos_enabled.yaml @@ -1,13 +1,30 @@ +Description: The access permissions and authorizations can be managed and incorporated with the principles of least privilege and separation of duties, by enabling Kerberos for AWS EMR clusters. ID: aws_emr_cluster_kerberos_enabled -Title: "EMR cluster Kerberos should be enabled" -Description: "The access permissions and authorizations can be managed and incorporated with the principles of least privilege and separation of duties, by enabling Kerberos for AWS EMR clusters." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n cluster_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kerberos_attributes is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kerberos_attributes is null then title || ' Kerberos not enabled.'\n else title || ' Kerberos enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_emr_cluster;\n" - PrimaryTable: aws_emr_cluster ListOfTables: - aws_emr_cluster Parameters: [] + PrimaryTable: aws_emr_cluster + QueryToExecute: | + SELECT + cluster_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kerberos_attributes IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kerberos_attributes IS NULL THEN title || ' Kerberos not enabled.' + ELSE title || ' Kerberos enabled.' + END AS reason, + region, + account_id + FROM + aws_emr_cluster; Severity: medium Tags: category: @@ -22,10 +39,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -34,5 +51,4 @@ Tags: - AWS/EMR soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EMR cluster Kerberos should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_emr_cluster_local_disk_encrypted_with_cmk.yaml b/compliance/controls/aws/aws_emr_cluster_local_disk_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index c353ea38e..dc09cdc93 --- a/compliance/controls/aws/aws_emr_cluster_local_disk_encrypted_with_cmk.yaml +++ b/compliance/controls/aws/aws_emr_cluster_local_disk_encrypted_with_cmk.yaml @@ -1,38 +1,41 @@ +Description: Ensure EMR cluster local disk are encrypted using CMK. This control fails if an EMR cluster local disk isn't encrypted with CMK. ID: aws_emr_cluster_local_disk_encrypted_with_cmk -Title: "EMR cluster local disks should be encrypted with CMK" -Description: "Ensure EMR cluster local disk are encrypted using CMK. This control fails if an EMR cluster local disk isn't encrypted with CMK." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - cluster_arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when s.name is null then 'alarm' - when (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') is null then 'alarm' - when s.name is not null - and (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') is not null - and (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration' ->> 'EncryptionKeyProviderType') = 'Custom' then 'ok' - else 'alarm' - end as status, - case - when s.name is null then c.title || ' security configuration disabled.' - when (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') is null then c.title || ' local disk not encrypted.' - when s.name is not null - and (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') is not null - and (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration' ->> 'EncryptionKeyProviderType') = 'Custom' then c.title || ' local disk encrypted with CMK.' - else c.title || ' local disk not encrypted with CMK.' - end as reason - from - aws_emr_cluster as c - left join aws_emr_security_configuration as s on c.security_configuration = s.name and s.region = s.region and s.account_id = c.account_id; - PrimaryTable: aws_emr_cluster ListOfTables: - aws_emr_cluster - aws_emr_security_configuration Parameters: [] + PrimaryTable: aws_emr_cluster + QueryToExecute: | + SELECT + cluster_arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN s.name IS NULL THEN 'alarm' + WHEN (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') IS NULL THEN 'alarm' + WHEN s.name IS NOT NULL + AND (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') IS NOT NULL + AND (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration' ->> 'EncryptionKeyProviderType') = 'Custom' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.name IS NULL THEN c.title || ' security configuration disabled.' + WHEN (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') IS NULL THEN c.title || ' local disk not encrypted.' + WHEN s.name IS NOT NULL + AND (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') IS NOT NULL + AND (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration' ->> 'EncryptionKeyProviderType') = 'Custom' THEN c.title || ' local disk encrypted with CMK.' + ELSE c.title || ' local disk not encrypted with CMK.' + END AS reason + FROM + aws_emr_cluster AS c + LEFT JOIN aws_emr_security_configuration AS s + ON c.security_configuration = s.name + AND s.region = s.region + AND s.account_id = c.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EMR cluster local disks should be encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/aws/aws_emr_cluster_master_nodes_no_public_ip.yaml b/compliance/controls/aws/aws_emr_cluster_master_nodes_no_public_ip.yaml old mode 100755 new mode 100644 index 672aab6c7..30a064dfc --- a/compliance/controls/aws/aws_emr_cluster_master_nodes_no_public_ip.yaml +++ b/compliance/controls/aws/aws_emr_cluster_master_nodes_no_public_ip.yaml @@ -1,14 +1,37 @@ +Description: Manage access to the AWS Cloud by ensuring AWS EMR cluster master nodes cannot be publicly accessed. ID: aws_emr_cluster_master_nodes_no_public_ip -Title: "EMR cluster master nodes should not have public IP addresses" -Description: "Manage access to the AWS Cloud by ensuring AWS EMR cluster master nodes cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n c.cluster_arn as resource,\n c.og_account_id as og_account_id,\n c.og_resource_id as og_resource_id,\n case\n when c.status ->> 'State' not in ('RUNNING', 'WAITING') then 'skip'\n when s.map_public_ip_on_launch then 'alarm'\n else 'ok'\n end as status,\n case\n when c.status ->> 'State' not in ('RUNNING', 'WAITING') then c.title || ' is in ' || (c.status ->> 'State') || ' state.'\n when s.map_public_ip_on_launch then c.title || ' master nodes assigned with public IP.'\n else c.title || ' master nodes not assigned with public IP.'\n end as reason\n \n , c.region, c.account_id\nfrom\n aws_emr_cluster as c\n left join aws_vpc_subnet as s on c.ec2_instance_attributes ->> 'Ec2SubnetId' = s.subnet_id;\n" - PrimaryTable: aws_emr_cluster ListOfTables: - aws_emr_cluster - aws_vpc_subnet Parameters: [] + PrimaryTable: aws_emr_cluster + QueryToExecute: | + SELECT + c.cluster_arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.status ->> 'State' NOT IN ('RUNNING', 'WAITING') THEN 'skip' + WHEN s.map_public_ip_on_launch THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.status ->> 'State' NOT IN ('RUNNING', 'WAITING') THEN c.title || ' is in ' || (c.status ->> 'State') || ' state.' + WHEN s.map_public_ip_on_launch THEN c.title || ' master nodes assigned with public IP.' + ELSE c.title || ' master nodes not assigned with public IP.' + END AS reason, + c.region, + c.account_id + FROM + aws_emr_cluster AS c + LEFT JOIN + aws_vpc_subnet AS s + ON + c.ec2_instance_attributes ->> 'Ec2SubnetId' = s.subnet_id; Severity: high Tags: category: @@ -29,12 +52,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -47,5 +70,4 @@ Tags: - AWS/EMR soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: EMR cluster master nodes should not have public IP addresses \ No newline at end of file diff --git a/compliance/controls/aws/aws_emr_cluster_security_configuration_enabled.yaml b/compliance/controls/aws/aws_emr_cluster_security_configuration_enabled.yaml old mode 100755 new mode 100644 index 2625eccb4..62f7bdbb8 --- a/compliance/controls/aws/aws_emr_cluster_security_configuration_enabled.yaml +++ b/compliance/controls/aws/aws_emr_cluster_security_configuration_enabled.yaml @@ -1,14 +1,28 @@ +Description: Ensure EMR cluster have security configuration enabled. This control fails if security configuration is not enabled for EMR cluster. ID: aws_emr_cluster_security_configuration_enabled -Title: "EMR clusters should have security configuration enabled" -Description: "Ensure EMR cluster have security configuration enabled. This control fails if security configuration is not enabled for EMR cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n cluster_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when security_configuration is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when security_configuration is not null then title || ' security configuration enabled.'\n else title || ' security configuration disabled.'\n end as reason\n \n \nfrom\n aws_emr_cluster;" - PrimaryTable: aws_emr_cluster ListOfTables: - aws_emr_cluster Parameters: [] + PrimaryTable: aws_emr_cluster + QueryToExecute: | + SELECT + cluster_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN security_configuration IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN security_configuration IS NOT NULL THEN title || ' security configuration enabled.' + ELSE title || ' security configuration disabled.' + END AS reason + FROM + aws_emr_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EMR clusters should have security configuration enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_audit_logging_enabled.yaml b/compliance/controls/aws/aws_es_domain_audit_logging_enabled.yaml old mode 100755 new mode 100644 index 5caea0706..cd4e4968d --- a/compliance/controls/aws/aws_es_domain_audit_logging_enabled.yaml +++ b/compliance/controls/aws/aws_es_domain_audit_logging_enabled.yaml @@ -1,13 +1,36 @@ +Description: This control checks whether Elasticsearch domains have audit logging enabled. This control fails if an Elasticsearch domain does not have audit logging enabled. ID: aws_es_domain_audit_logging_enabled -Title: "Elasticsearch domains should have audit logging enabled" -Description: "This control checks whether Elasticsearch domains have audit logging enabled. This control fails if an Elasticsearch domain does not have audit logging enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when\n log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when\n log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null then title || ' audit logging enabled.'\n else title || ' audit logging disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_elasticsearch_domain;\n" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN + log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN + log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL + THEN title || ' audit logging enabled.' + ELSE title || ' audit logging disabled.' + END AS reason, + region, + account_id + FROM + aws_elasticsearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +45,4 @@ Tags: - aws service: - AWS/ES -IntegrationType: - - aws_cloud_account +Title: Elasticsearch domains should have audit logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_cognito_authentication_enabled.yaml b/compliance/controls/aws/aws_es_domain_cognito_authentication_enabled.yaml old mode 100755 new mode 100644 index 7201b9080..0d898a88f --- a/compliance/controls/aws/aws_es_domain_cognito_authentication_enabled.yaml +++ b/compliance/controls/aws/aws_es_domain_cognito_authentication_enabled.yaml @@ -1,28 +1,29 @@ +Description: AWS Elasticsearch service uses AWS Cognito to offer user name and password protection for Kibana. + This control is non-compliant if AWS Cognito authentication is not enabled. ID: aws_es_domain_cognito_authentication_enabled -Title: "Elasticsearch domains should have cognito authentication enabled" -Description: "AWS Elasticsearch service uses AWS Cognito to offer user name and password protection for Kibana. This control is non-compliant if AWS Cognito authentication is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when cognito_options ->> 'Enabled' = 'true' then 'ok' - else 'alarm' - end as status, - case - when cognito_options ->> 'Enabled' = 'true' then title || ' AWS Cognito authentication for Kibana enabled.' - else title || ' AWS Cognito authentication for Kibana disabled.' - end as reason - from - aws_elasticsearch_domain; - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cognito_options ->> 'Enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cognito_options ->> 'Enabled' = 'true' THEN title || ' AWS Cognito authentication for Kibana enabled.' + ELSE title || ' AWS Cognito authentication for Kibana disabled.' + END AS reason + FROM + aws_elasticsearch_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Elasticsearch domains should have cognito authentication enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_data_nodes_min_3.yaml b/compliance/controls/aws/aws_es_domain_data_nodes_min_3.yaml old mode 100755 new mode 100644 index 4e87c1764..9e03b00bf --- a/compliance/controls/aws/aws_es_domain_data_nodes_min_3.yaml +++ b/compliance/controls/aws/aws_es_domain_data_nodes_min_3.yaml @@ -1,13 +1,32 @@ +Description: This control checks whether Elasticsearch domains are configured with at least three data nodes and zoneAwarenessEnabled is true. ID: aws_es_domain_data_nodes_min_3 -Title: "Elasticsearch domains should have at least three data nodes" -Description: "This control checks whether Elasticsearch domains are configured with at least three data nodes and zoneAwarenessEnabled is true." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'false' then 'alarm'\n when\n elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'true'\n and (elasticsearch_cluster_config ->> 'InstanceCount')::integer >= 3 then 'ok'\n else 'alarm'\n end status,\n case\n when elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'false' then title || ' zone awareness disabled.'\n else title || ' has ' || (elasticsearch_cluster_config ->> 'InstanceCount') || ' data node(s).'\n end as reason\n \n , region, account_id\nfrom\n aws_elasticsearch_domain;\n" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'false' THEN 'alarm' + WHEN elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'true' + AND (elasticsearch_cluster_config ->> 'InstanceCount')::integer >= 3 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'false' THEN title || ' zone awareness disabled.' + ELSE title || ' has ' || (elasticsearch_cluster_config ->> 'InstanceCount') || ' data node(s).' + END AS reason, + region, + account_id + FROM + aws_elasticsearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +41,4 @@ Tags: - aws service: - AWS/ES -IntegrationType: - - aws_cloud_account +Title: Elasticsearch domains should have at least three data nodes \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_dedicated_master_nodes_min_3.yaml b/compliance/controls/aws/aws_es_domain_dedicated_master_nodes_min_3.yaml old mode 100755 new mode 100644 index d11062aec..08f5968c6 --- a/compliance/controls/aws/aws_es_domain_dedicated_master_nodes_min_3.yaml +++ b/compliance/controls/aws/aws_es_domain_dedicated_master_nodes_min_3.yaml @@ -1,13 +1,33 @@ +Description: This control checks whether Elasticsearch domains are configured with at least three dedicated master nodes. This control fails if the domain does not use dedicated master nodes. This control passes if Elasticsearch domains have five dedicated master nodes. However, using more than three master nodes might be unnecessary to mitigate the availability risk, and will result in additional cost. ID: aws_es_domain_dedicated_master_nodes_min_3 -Title: "Elasticsearch domains should be configured with at least three dedicated master nodes" -Description: "This control checks whether Elasticsearch domains are configured with at least three dedicated master nodes. This control fails if the domain does not use dedicated master nodes. This control passes if Elasticsearch domains have five dedicated master nodes. However, using more than three master nodes might be unnecessary to mitigate the availability risk, and will result in additional cost." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'false' then 'alarm'\n when\n elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'true'\n and (elasticsearch_cluster_config ->> 'DedicatedMasterCount')::integer >= 3 then 'ok'\n else 'alarm'\n end status,\n case\n when elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'false' then title || ' dedicated master nodes disabled.'\n else title || ' has ' || (elasticsearch_cluster_config ->> 'DedicatedMasterCount') || ' dedicated master node(s).'\n end as reason\n \n , region, account_id\nfrom\n aws_elasticsearch_domain;\n" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'false' THEN 'alarm' + WHEN + elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'true' + AND (elasticsearch_cluster_config ->> 'DedicatedMasterCount')::integer >= 3 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'false' THEN title || ' dedicated master nodes disabled.' + ELSE title || ' has ' || (elasticsearch_cluster_config ->> 'DedicatedMasterCount') || ' dedicated master node(s).' + END AS reason, + region, + account_id + FROM + aws_elasticsearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +42,4 @@ Tags: - aws service: - AWS/ES -IntegrationType: - - aws_cloud_account +Title: Elasticsearch domains should be configured with at least three dedicated master nodes \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_encrypted_using_tls_1_2.yaml b/compliance/controls/aws/aws_es_domain_encrypted_using_tls_1_2.yaml old mode 100755 new mode 100644 index 413af388f..b8414daa9 --- a/compliance/controls/aws/aws_es_domain_encrypted_using_tls_1_2.yaml +++ b/compliance/controls/aws/aws_es_domain_encrypted_using_tls_1_2.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether connections to Elasticsearch domains are required to use TLS 1.2. The check fails if the Elasticsearch domain TLSSecurityPolicy is not Policy-Min-TLS-1-2-2019-07. ID: aws_es_domain_encrypted_using_tls_1_2 -Title: "Connections to Elasticsearch domains should be encrypted using TLS 1.2" -Description: "This control checks whether connections to Elasticsearch domains are required to use TLS 1.2. The check fails if the Elasticsearch domain TLSSecurityPolicy is not Policy-Min-TLS-1-2-2019-07." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when domain_endpoint_options ->> 'TLSSecurityPolicy' = 'Policy-Min-TLS-1-2-2019-07' then 'ok'\n else 'alarm'\n end status,\n case\n when domain_endpoint_options ->> 'TLSSecurityPolicy' = 'Policy-Min-TLS-1-2-2019-07' then title || ' encrypted using TLS 1.2.'\n else title || ' not encrypted using TLS 1.2.'\n end as reason\n \n , region, account_id\nfrom\n aws_elasticsearch_domain;\n" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN domain_endpoint_options ->> 'TLSSecurityPolicy' = 'Policy-Min-TLS-1-2-2019-07' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN domain_endpoint_options ->> 'TLSSecurityPolicy' = 'Policy-Min-TLS-1-2-2019-07' THEN title || ' encrypted using TLS 1.2.' + ELSE title || ' not encrypted using TLS 1.2.' + END AS reason, + region, + account_id + FROM + aws_elasticsearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/ES -IntegrationType: - - aws_cloud_account +Title: Connections to Elasticsearch domains should be encrypted using TLS 1.2 \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_es_domain_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index a2a4420d5..94a53809c --- a/compliance/controls/aws/aws_es_domain_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_es_domain_encryption_at_rest_enabled.yaml @@ -1,13 +1,30 @@ +Description: Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your AWS Elasticsearch Service (AWS ES) domains. ID: aws_es_domain_encryption_at_rest_enabled -Title: "ES domain encryption at rest should be enabled" -Description: "Because sensitive data can exist and to help protect data at rest, ensure encryption is enabled for your AWS Elasticsearch Service (AWS ES) domains." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encryption_at_rest_options ->> 'Enabled' = 'false' then 'alarm'\n else 'ok'\n end status,\n case\n when encryption_at_rest_options ->> 'Enabled' = 'false' then title || ' encryption at rest not enabled.'\n else title || ' encryption at rest enabled.'\n end reason\n \n , region, account_id\nfrom\n aws_elasticsearch_domain;\n" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encryption_at_rest_options ->> 'Enabled' = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption_at_rest_options ->> 'Enabled' = 'false' THEN title || ' encryption at rest not enabled.' + ELSE title || ' encryption at rest enabled.' + END AS reason, + region, + account_id + FROM + aws_elasticsearch_domain; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/ES soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: ES domain encryption at rest should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_error_logging_enabled.yaml b/compliance/controls/aws/aws_es_domain_error_logging_enabled.yaml old mode 100755 new mode 100644 index ebd0002d0..56e1b2935 --- a/compliance/controls/aws/aws_es_domain_error_logging_enabled.yaml +++ b/compliance/controls/aws/aws_es_domain_error_logging_enabled.yaml @@ -1,13 +1,36 @@ +Description: This control checks whether Elasticsearch domains are configured to send error logs to CloudWatch Logs. ID: aws_es_domain_error_logging_enabled -Title: "Elasticsearch domain error logging to CloudWatch Logs should be enabled" -Description: "This control checks whether Elasticsearch domains are configured to send error logs to CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when\n log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when\n log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null then title || ' error logging enabled.'\n else title || ' error logging disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_elasticsearch_domain;\n" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN + log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL THEN 'ok' + ELSE + 'alarm' + END AS status, + CASE + WHEN + log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL THEN title || ' error logging enabled.' + ELSE + title || ' error logging disabled.' + END AS reason, + region, + account_id + FROM + aws_elasticsearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +45,4 @@ Tags: - aws service: - AWS/ES -IntegrationType: - - aws_cloud_account +Title: Elasticsearch domain error logging to CloudWatch Logs should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_in_vpc.yaml b/compliance/controls/aws/aws_es_domain_in_vpc.yaml old mode 100755 new mode 100644 index 614f63d88..4123cbf23 --- a/compliance/controls/aws/aws_es_domain_in_vpc.yaml +++ b/compliance/controls/aws/aws_es_domain_in_vpc.yaml @@ -1,13 +1,30 @@ +Description: Manage access to the AWS Cloud by ensuring AWS Elasticsearch Service (AWS ES) Domains are within an AWS Virtual Private Cloud (AWS VPC). ID: aws_es_domain_in_vpc -Title: "ES domains should be in a VPC" -Description: "Manage access to the AWS Cloud by ensuring AWS Elasticsearch Service (AWS ES) Domains are within an AWS Virtual Private Cloud (AWS VPC)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when vpc_options ->> 'VPCId' is null then 'alarm'\n else 'ok'\n end status,\n case\n when vpc_options ->> 'VPCId' is null then title || ' not in VPC.'\n else title || ' in VPC ' || (vpc_options ->> 'VPCId') || '.'\n end reason\n \n , region, account_id\nfrom\n aws_elasticsearch_domain;\n" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_options ->> 'VPCId' IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vpc_options ->> 'VPCId' IS NULL THEN title || ' not in VPC.' + ELSE title || ' in VPC ' || (vpc_options ->> 'VPCId') || '.' + END AS reason, + region, + account_id + FROM + aws_elasticsearch_domain; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/ES soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: ES domains should be in a VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_internal_user_database_enabled.yaml b/compliance/controls/aws/aws_es_domain_internal_user_database_enabled.yaml old mode 100755 new mode 100644 index 4d0118310..a563439f6 --- a/compliance/controls/aws/aws_es_domain_internal_user_database_enabled.yaml +++ b/compliance/controls/aws/aws_es_domain_internal_user_database_enabled.yaml @@ -1,14 +1,28 @@ +Description: Ensure Elasticsearch domains have internal user database enabled. This control is non-compliant if a domain's internal user database is not enabled. ID: aws_es_domain_internal_user_database_enabled -Title: "Elasticsearch domains should have internal user database enabled" -Description: "Ensure Elasticsearch domains have internal user database enabled. This control is non-compliant if a domain's internal user database is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when advanced_security_options ->> 'InternalUserDatabaseEnabled' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when advanced_security_options ->> 'InternalUserDatabaseEnabled' = 'true' then title || ' internal user database enabled.'\n else title || ' internal user database disabled.'\n end as reason\n \n \nfrom\n aws_elasticsearch_domain;" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN advanced_security_options ->> 'InternalUserDatabaseEnabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN advanced_security_options ->> 'InternalUserDatabaseEnabled' = 'true' THEN title || ' internal user database enabled.' + ELSE title || ' internal user database disabled.' + END AS reason + FROM + aws_elasticsearch_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Elasticsearch domains should have internal user database enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_logs_to_cloudwatch.yaml b/compliance/controls/aws/aws_es_domain_logs_to_cloudwatch.yaml old mode 100755 new mode 100644 index 450a9cd45..fb355d5df --- a/compliance/controls/aws/aws_es_domain_logs_to_cloudwatch.yaml +++ b/compliance/controls/aws/aws_es_domain_logs_to_cloudwatch.yaml @@ -1,13 +1,54 @@ +Description: Ensure that AWS OpenSearch Service (OpenSearch Service) domains are configured to send logs to AWS CloudWatch Logs. The rule is compliant if a log is enabled for an OpenSearch Service domain. This rule is non-compliant if logging is not configured. ID: aws_es_domain_logs_to_cloudwatch -Title: "Elasticsearch domain should send logs to CloudWatch" -Description: "Ensure that AWS OpenSearch Service (OpenSearch Service) domains are configured to send logs to AWS CloudWatch Logs. The rule is compliant if a log is enabled for an OpenSearch Service domain. This rule is non-compliant if logging is not configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when\n ( log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null\n )\n and\n ( log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null\n )\n and\n ( log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null\n )\n then 'ok'\n else 'alarm'\n end as status,\n case\n when\n ( log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null\n )\n and\n ( log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null\n )\n and\n ( log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null\n ) then title || ' logging enabled for search , index and error.'\n else title || ' logging not enabled for all search, index and error.'\n end as reason\n \n , region, account_id\nfrom\n aws_elasticsearch_domain;\n" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN + ( log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL + ) + AND + ( log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL + ) + AND + ( log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL + ) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN + ( log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL + ) + AND + ( log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL + ) + AND + ( log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL + ) + THEN title || ' logging enabled for search, index, and error.' + ELSE title || ' logging not enabled for all search, index, and error.' + END AS reason, + region, + account_id + FROM + aws_elasticsearch_domain; Severity: high Tags: category: @@ -26,10 +67,10 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -42,5 +83,4 @@ Tags: - AWS/ES soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Elasticsearch domain should send logs to CloudWatch \ No newline at end of file diff --git a/compliance/controls/aws/aws_es_domain_node_to_node_encryption_enabled.yaml b/compliance/controls/aws/aws_es_domain_node_to_node_encryption_enabled.yaml old mode 100755 new mode 100644 index 930f8e117..fdc6e48cf --- a/compliance/controls/aws/aws_es_domain_node_to_node_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_es_domain_node_to_node_encryption_enabled.yaml @@ -1,13 +1,32 @@ +Description: Ensure node-to-node encryption for AWS Elasticsearch Service is enabled. Node-to-node encryption enables TLS 1.2 encryption for all communications within the AWS Virtual Private Cloud (AWS VPC). ID: aws_es_domain_node_to_node_encryption_enabled -Title: "Elasticsearch domain node-to-node encryption should be enabled" -Description: "Ensure node-to-node encryption for AWS Elasticsearch Service is enabled. Node-to-node encryption enables TLS 1.2 encryption for all communications within the AWS Virtual Private Cloud (AWS VPC)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) then 'skip'\n when not enabled then 'alarm'\n else 'ok'\n end as status,\n case\n when region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) then title || ' node-to-node encryption not supported in ' || region || '.'\n when not enabled then title || ' node-to-node encryption disabled.'\n else title || ' node-to-node encryption enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_elasticsearch_domain;\n" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) THEN 'skip' + WHEN NOT enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) THEN title || ' node-to-node encryption not supported in ' || region || '.' + WHEN NOT enabled THEN title || ' node-to-node encryption disabled.' + ELSE title || ' node-to-node encryption enabled.' + END AS reason, + region, + account_id + FROM + aws_elasticsearch_domain; Severity: high Tags: category: @@ -28,12 +47,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +65,4 @@ Tags: - AWS/ES soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Elasticsearch domain node-to-node encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_eventbridge_custom_bus_resource_based_policy_attached.yaml b/compliance/controls/aws/aws_eventbridge_custom_bus_resource_based_policy_attached.yaml old mode 100755 new mode 100644 index 7dfd82ce8..7c4fa6d62 --- a/compliance/controls/aws/aws_eventbridge_custom_bus_resource_based_policy_attached.yaml +++ b/compliance/controls/aws/aws_eventbridge_custom_bus_resource_based_policy_attached.yaml @@ -1,30 +1,31 @@ +Description: This control checks if an Amazon EventBridge custom event bus has a resource-based policy attached. + This control fails if the custom event bus doesn't have a resource-based policy. ID: aws_eventbridge_custom_bus_resource_based_policy_attached -Title: "EventBridge custom event buses should have a resource-based policy attached" -Description: "This control checks if an Amazon EventBridge custom event bus has a resource-based policy attached. This control fails if the custom event bus doesn't have a resource-based policy.." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when name = 'default' then 'skip' - when policy_std is not null then 'ok' - else 'alarm' - end as status, - case - when name = 'default' then title || ' is default event bus.' - when policy_std is not null then title || ' has resource based policy attached.' - else title || ' does not have resource based policy attached.' - end as reason - from - aws_eventbridge_bus; - PrimaryTable: aws_eventbridge_bus ListOfTables: - aws_eventbridge_bus Parameters: [] + PrimaryTable: aws_eventbridge_bus + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN name = 'default' THEN 'skip' + WHEN policy_std IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN name = 'default' THEN title || ' is default event bus.' + WHEN policy_std IS NOT NULL THEN title || ' has resource based policy attached.' + ELSE title || ' does not have resource based policy attached.' + END AS reason + FROM + aws_eventbridge_bus; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EventBridge custom event buses should have a resource-based policy attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_account_1.yaml b/compliance/controls/aws/aws_foundational_security_account_1.yaml old mode 100755 new mode 100644 index ef6347fe1..df1abb4a8 --- a/compliance/controls/aws/aws_foundational_security_account_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_account_1.yaml @@ -1,15 +1,53 @@ +Description: This control checks if an Amazon Web Services (AWS) account has security contact information. The control fails if security contact information is not provided for the account. ID: aws_foundational_security_account_1 -Title: "1 Security contact information should be provided for an AWS account" -Description: "This control checks if an Amazon Web Services (AWS) account has security contact information. The control fails if security contact information is not provided for the account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alternate_security_contact as (\n select\n name,\n account_id\n from\n aws_account_alternate_contact\n where\n contact_type = 'SECURITY'\n),\naccount as (\n select\n arn,\n partition,\n title,\n account_id,\n _ctx\n from\n aws_account\n)\nselect\n arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.partition = 'aws-us-gov' then 'info'\n -- Name is a required field if setting a security contact\n when c.name is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.partition = 'aws-us-gov' then a.title || ' in GovCloud, manual verification required.'\n when c.name is not null then a.title || ' has security contact ' || c.name || ' registered.'\n else a.title || ' security contact not registered.'\n end as reason\n \nfrom\n account as a,\n alternate_security_contact as c\nwhere\n c.account_id = a.account_id;" - PrimaryTable: aws_account ListOfTables: - aws_account_alternate_contact - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH alternate_security_contact AS ( + SELECT + name, + account_id + FROM + aws_account_alternate_contact + WHERE + contact_type = 'SECURITY' + ), + account AS ( + SELECT + arn, + partition, + title, + account_id, + _ctx + FROM + aws_account + ) + SELECT + arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.partition = 'aws-us-gov' THEN 'info' + WHEN c.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.partition = 'aws-us-gov' THEN a.title || ' in GovCloud, manual verification required.' + WHEN c.name IS NOT NULL THEN a.title || ' has security contact ' || c.name || ' registered.' + ELSE a.title || ' security contact not registered.' + END AS reason + FROM + account AS a, + alternate_security_contact AS c + WHERE + c.account_id = a.account_id Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Security contact information should be provided for an AWS account \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_acm_1.yaml b/compliance/controls/aws/aws_foundational_security_acm_1.yaml old mode 100755 new mode 100644 index fd2336087..e437d18f9 --- a/compliance/controls/aws/aws_foundational_security_acm_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_acm_1.yaml @@ -1,14 +1,29 @@ +Description: This control checks whether ACM certificates in your account are marked for expiration within 30 days. It checks both imported certificates and certificates provided by AWS Certificate Manager. ID: aws_foundational_security_acm_1 -Title: "1 Imported ACM certificates should be renewed after a specified time period" -Description: "This control checks whether ACM certificates in your account are marked for expiration within 30 days. It checks both imported certificates and certificates provided by AWS Certificate Manager." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n certificate_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when renewal_eligibility = 'INELIGIBLE' then 'skip'\n when date(not_after) - date(current_date) >= 30 then 'ok'\n else 'alarm'\n end as status,\n case\n when renewal_eligibility = 'INELIGIBLE' then title || ' not eligible for renewal.'\n else title || ' expires ' || to_char(not_after, 'DD-Mon-YYYY') ||\n ' (' || extract(day from not_after - current_date) || ' days).'\n end as reason\n \n \nfrom\n aws_acm_certificate;" - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN renewal_eligibility = 'INELIGIBLE' THEN 'skip' + WHEN DATE(not_after) - DATE(current_date) >= 30 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN renewal_eligibility = 'INELIGIBLE' THEN title || ' not eligible for renewal.' + ELSE title || ' expires ' || TO_CHAR(not_after, 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM not_after - current_date) || ' days).' + END AS reason + FROM + aws_acm_certificate; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Imported ACM certificates should be renewed after a specified time period \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_acm_2.yaml b/compliance/controls/aws/aws_foundational_security_acm_2.yaml old mode 100755 new mode 100644 index 9b15a058c..1bccde925 --- a/compliance/controls/aws/aws_foundational_security_acm_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_acm_2.yaml @@ -1,30 +1,30 @@ +Description: This control checks whether RSA certificates managed by AWS Certificate Manager use a key length of at least 2,048 bits. The control fails if the key length is smaller than 2,048 bits. ID: aws_foundational_security_acm_2 -Title: "2 RSA certificates managed by ACM should use a key length of at least 2,048 bits" -Description: "This control checks whether RSA certificates managed by AWS Certificate Manager use a key length of at least 2,048 bits. The control fails if the key length is smaller than 2,048 bits." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - certificate_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not key_algorithm like 'RSA-%' then 'skip' - when key_algorithm = 'RSA_1024' then 'alarm' - else 'ok' - end as status, - case - when not key_algorithm like 'RSA-%' then title || ' is not a RSA certificate.' - when key_algorithm = 'RSA_1024' then title || ' is using 1024 bits key length.' - else title || ' is using ' || split_part(key_algorithm, '-', 2) || ' bits key length.' - end as reason - from - aws_acm_certificate; - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT key_algorithm LIKE 'RSA-%' THEN 'skip' + WHEN key_algorithm = 'RSA_1024' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT key_algorithm LIKE 'RSA-%' THEN title || ' is not a RSA certificate.' + WHEN key_algorithm = 'RSA_1024' THEN title || ' is using 1024 bits key length.' + ELSE title || ' is using ' || SPLIT_PART(key_algorithm, '-', 2) || ' bits key length.' + END AS reason + FROM + aws_acm_certificate; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: RSA certificates managed by ACM should use a key length of at least 2,048 bits \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_apigateway_1.yaml b/compliance/controls/aws/aws_foundational_security_apigateway_1.yaml old mode 100755 new mode 100644 index 0079a8b95..8ae6301fd --- a/compliance/controls/aws/aws_foundational_security_apigateway_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_apigateway_1.yaml @@ -1,54 +1,54 @@ +Description: This control checks whether all stages of an Amazon API Gateway REST or WebSocket API have logging enabled. The control fails if logging is not enabled for all methods of a stage or if loggingLevel is neither ERROR nor INFO. ID: aws_foundational_security_apigateway_1 -Title: "1 API Gateway REST and WebSocket API logging should be enabled" -Description: "This control checks whether all stages of an Amazon API Gateway REST or WebSocket API have logging enabled. The control fails if logging is not enabled for all methods of a stage or if loggingLevel is neither ERROR nor INFO." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with all_stages as ( - select - name as stage_name, - 'arn:' || partition || ':apigateway:' || region || '::/apis/' || rest_api_id || '/stages/' || name as arn, - method_settings -> '*/*' ->> 'LoggingLevel' as log_level, + ListOfTables: + - aws_api_gateway_stage + - aws_api_gatewayv2_stage + Parameters: [] + PrimaryTable: aws_api_gateway_stage + QueryToExecute: | + WITH all_stages AS ( + SELECT + name AS stage_name, + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || rest_api_id || '/stages/' || name AS arn, + method_settings -> '*/*' ->> 'LoggingLevel' AS log_level, title, region, account_id, tags, _ctx - from + FROM aws_api_gateway_stage - union - select + UNION + SELECT stage_name, - 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/stages/' || stage_name as arn, - default_route_logging_level as log_level, + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/stages/' || stage_name AS arn, + default_route_logging_level AS log_level, title, region, account_id, tags, _ctx - from + FROM aws_api_gatewayv2_stage ) - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_level is null or log_level = '' or log_level = 'OFF' then 'alarm' - else 'ok' - end as status, - case - when log_level is null or log_level = '' or log_level = 'OFF' then title || ' logging not enabled.' - else title || ' logging enabled.' - end as reason - from + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_level IS NULL OR log_level = '' OR log_level = 'OFF' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN log_level IS NULL OR log_level = '' OR log_level = 'OFF' THEN title || ' logging not enabled.' + ELSE title || ' logging enabled.' + END AS reason + FROM all_stages; - PrimaryTable: aws_api_gateway_stage - ListOfTables: - - aws_api_gateway_stage - - aws_api_gatewayv2_stage - Parameters: [] Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 API Gateway REST and WebSocket API logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_apigateway_2.yaml b/compliance/controls/aws/aws_foundational_security_apigateway_2.yaml old mode 100755 new mode 100644 index acfc42857..a7ea134d5 --- a/compliance/controls/aws/aws_foundational_security_apigateway_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_apigateway_2.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether Amazon API Gateway REST API stages have SSL certificates configured. Backend systems use these certificates to authenticate that incoming requests are from API Gateway. ID: aws_foundational_security_apigateway_2 -Title: "2 API Gateway REST API stages should be configured to use SSL certificates for backend authentication" -Description: "This control checks whether Amazon API Gateway REST API stages have SSL certificates configured. Backend systems use these certificates to authenticate that incoming requests are from API Gateway." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when client_certificate_id is null then 'alarm' - else 'ok' - end as status, - case - when client_certificate_id is null then title || ' does not use SSL certificate.' - else title || ' uses SSL certificate.' - end as reason - from - aws_api_gateway_stage; - PrimaryTable: aws_api_gateway_stage ListOfTables: - aws_api_gateway_stage Parameters: [] + PrimaryTable: aws_api_gateway_stage + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN client_certificate_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN client_certificate_id IS NULL THEN title || ' does not use SSL certificate.' + ELSE title || ' uses SSL certificate.' + END AS reason + FROM + aws_api_gateway_stage; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 API Gateway REST API stages should be configured to use SSL certificates for backend authentication \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_apigateway_3.yaml b/compliance/controls/aws/aws_foundational_security_apigateway_3.yaml old mode 100755 new mode 100644 index b8bb2a59f..7df78462a --- a/compliance/controls/aws/aws_foundational_security_apigateway_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_apigateway_3.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether AWS X-Ray active tracing is enabled for your Amazon API Gateway REST API stages. ID: aws_foundational_security_apigateway_3 -Title: "3 API Gateway REST API stages should have AWS X-Ray tracing enabled" -Description: "This control checks whether AWS X-Ray active tracing is enabled for your Amazon API Gateway REST API stages." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when tracing_enabled then 'ok' - else 'alarm' - end as status, - case - when tracing_enabled then title || ' X-Ray tracing enabled.' - else title || ' X-Ray tracing disabled.' - end as reason - from - aws_api_gateway_stage; - PrimaryTable: aws_api_gateway_stage ListOfTables: - aws_api_gateway_stage Parameters: [] + PrimaryTable: aws_api_gateway_stage + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN tracing_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN tracing_enabled THEN title || ' X-Ray tracing enabled.' + ELSE title || ' X-Ray tracing disabled.' + END AS reason + FROM + aws_api_gateway_stage; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 API Gateway REST API stages should have AWS X-Ray tracing enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_apigateway_4.yaml b/compliance/controls/aws/aws_foundational_security_apigateway_4.yaml old mode 100755 new mode 100644 index af0d00c59..9a74b1f8a --- a/compliance/controls/aws/aws_foundational_security_apigateway_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_apigateway_4.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an API Gateway stage uses an AWS WAF web access control list (ACL). This control fails if an AWS WAF web ACL is not attached to a REST API Gateway stage. ID: aws_foundational_security_apigateway_4 -Title: "4 API Gateway should be associated with an AWS WAF web ACL" -Description: "This control checks whether an API Gateway stage uses an AWS WAF web access control list (ACL). This control fails if an AWS WAF web ACL is not attached to a REST API Gateway stage." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when web_acl_arn is not null then 'ok' - else 'alarm' - end as status, - case - when web_acl_arn is not null then title || ' associated with WAF web ACL.' - else title || ' not associated with WAF web ACL.' - end as reason - from - aws_api_gateway_stage; - PrimaryTable: aws_api_gateway_stage ListOfTables: - aws_api_gateway_stage Parameters: [] + PrimaryTable: aws_api_gateway_stage + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN web_acl_arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN web_acl_arn IS NOT NULL THEN title || ' associated with WAF web ACL.' + ELSE title || ' not associated with WAF web ACL.' + END AS reason + FROM + aws_api_gateway_stage; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 API Gateway should be associated with an AWS WAF web ACL \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_apigateway_5.yaml b/compliance/controls/aws/aws_foundational_security_apigateway_5.yaml old mode 100755 new mode 100644 index a1488ac73..086bcd0cc --- a/compliance/controls/aws/aws_foundational_security_apigateway_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_apigateway_5.yaml @@ -1,31 +1,31 @@ +Description: This control checks whether all methods in API Gateway REST API stages that have cache enabled are encrypted. The control fails if any method in an API Gateway REST API stage is configured to cache and the cache is not encrypted. ID: aws_foundational_security_apigateway_5 -Title: "5 API Gateway REST API cache data should be encrypted at rest" -Description: "This control checks whether all methods in API Gateway REST API stages that have cache enabled are encrypted. The control fails if any method in an API Gateway REST API stage is configured to cache and the cache is not encrypted." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || partition || ':apigateway:' || region || '::/apis/' || rest_api_id || '/stages/' || name as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when method_settings -> '*/*' ->> 'CachingEnabled' = 'true' - and method_settings -> '*/*' ->> 'CacheDataEncrypted' = 'true' then 'ok' - else 'alarm' - end as status, - case - when method_settings -> '*/*' ->> 'CachingEnabled' = 'true' - and method_settings -> '*/*' ->> 'CacheDataEncrypted' = 'true' - then title || ' API cache and encryption enabled.' - else title || ' API cache and encryption not enabled.' - end as reason - from - aws_api_gateway_stage; - PrimaryTable: aws_api_gateway_stage ListOfTables: - aws_api_gateway_stage Parameters: [] + PrimaryTable: aws_api_gateway_stage + QueryToExecute: | + SELECT + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || rest_api_id || '/stages/' || name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN method_settings -> '*/*' ->> 'CachingEnabled' = 'true' + AND method_settings -> '*/*' ->> 'CacheDataEncrypted' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN method_settings -> '*/*' ->> 'CachingEnabled' = 'true' + AND method_settings -> '*/*' ->> 'CacheDataEncrypted' = 'true' + THEN title || ' API cache and encryption enabled.' + ELSE title || ' API cache and encryption not enabled.' + END AS reason + FROM + aws_api_gateway_stage; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 API Gateway REST API cache data should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_apigateway_8.yaml b/compliance/controls/aws/aws_foundational_security_apigateway_8.yaml old mode 100755 new mode 100644 index 32b65c163..2bb3e0971 --- a/compliance/controls/aws/aws_foundational_security_apigateway_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_apigateway_8.yaml @@ -1,14 +1,28 @@ +Description: This control checks if Amazon API Gateway routes have an authorization type. The control fails if the API Gateway route does not specify an authorization type. ID: aws_foundational_security_apigateway_8 -Title: "8 API Gateway routes should specify an authorization type" -Description: "This control checks if Amazon API Gateway routes have an authorization type. The control fails if the API Gateway route does not specify an authorization type." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/routes/' || route_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when authorization_type is null then 'alarm'\n else 'ok'\n end as status,\n case\n when authorization_type is null then route_id || ' authorization type not configured.'\n else route_id || ' authorization type ' || authorization_type || ' configured.'\n end as reason\n \nfrom\n aws_api_gatewayv2_route;" - PrimaryTable: aws_api_gatewayv2_route ListOfTables: - aws_api_gatewayv2_route Parameters: [] + PrimaryTable: aws_api_gatewayv2_route + QueryToExecute: | + SELECT + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/routes/' || route_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN authorization_type IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN authorization_type IS NULL THEN route_id || ' authorization type not configured.' + ELSE route_id || ' authorization type ' || authorization_type || ' configured.' + END AS reason + FROM + aws_api_gatewayv2_route; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 API Gateway routes should specify an authorization type \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_apigateway_9.yaml b/compliance/controls/aws/aws_foundational_security_apigateway_9.yaml old mode 100755 new mode 100644 index cdf88d328..3f95343f9 --- a/compliance/controls/aws/aws_foundational_security_apigateway_9.yaml +++ b/compliance/controls/aws/aws_foundational_security_apigateway_9.yaml @@ -1,28 +1,28 @@ +Description: This control checks if Amazon API Gateway V2 stages have access logging configured. This control fails if access log settings aren't defined. ID: aws_foundational_security_apigateway_9 -Title: "9 Access logging should be configured for API Gateway V2 Stages" -Description: "This control checks if Amazon API Gateway V2 stages have access logging configured. This control fails if access log settings aren't defined." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/stages/' || stage_name as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when access_log_settings is null then 'alarm' - else 'ok' - end as status, - case - when access_log_settings is null then title || ' access logging disabled.' - else title || ' access logging enabled.' - end as reason - from - aws_api_gatewayv2_stage; - PrimaryTable: aws_api_gatewayv2_stage ListOfTables: - aws_api_gatewayv2_stage Parameters: [] + PrimaryTable: aws_api_gatewayv2_stage + QueryToExecute: | + SELECT + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/stages/' || stage_name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN access_log_settings IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN access_log_settings IS NULL THEN title || ' access logging disabled.' + ELSE title || ' access logging enabled.' + END AS reason + FROM + aws_api_gatewayv2_stage; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 Access logging should be configured for API Gateway V2 Stages \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_appsync_2.yaml b/compliance/controls/aws/aws_foundational_security_appsync_2.yaml old mode 100755 new mode 100644 index a6a7c5a80..8ea1c56cf --- a/compliance/controls/aws/aws_foundational_security_appsync_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_appsync_2.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an AWS AppSync API has field-level logging turned on. The control fails if the field resolver log level is set to None. Unless you provide custom parameter values to indicate that a specific log type should be enabled, Security Hub produces a passed finding if the field resolver log level is either ERROR or ALL. ID: aws_foundational_security_appsync_2 -Title: "2 AWS AppSync should have field-level logging enabled" -Description: "This control checks whether an AWS AppSync API has field-level logging turned on. The control fails if the field resolver log level is set to None. Unless you provide custom parameter values to indicate that a specific log type should be enabled, Security Hub produces a passed finding if the field resolver log level is either ERROR or ALL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - name as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_config ->> 'FieldLogLevel' in ('ERROR', 'ALL') then 'ok' - else 'alarm' - end as status, - case - when log_config ->> 'FieldLogLevel' in ('ERROR', 'ALL') then title || ' field level logging enabled.' - else name || ' field level logging disabled.' - end as reason - from - aws_appsync_graphql_api; - PrimaryTable: aws_appsync_graphql_api ListOfTables: - aws_appsync_graphql_api Parameters: [] + PrimaryTable: aws_appsync_graphql_api + QueryToExecute: | + SELECT + name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_config ->> 'FieldLogLevel' IN ('ERROR', 'ALL') THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_config ->> 'FieldLogLevel' IN ('ERROR', 'ALL') THEN title || ' field level logging enabled.' + ELSE name || ' field level logging disabled.' + END AS reason + FROM + aws_appsync_graphql_api; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 AWS AppSync should have field-level logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_athena_1.yaml b/compliance/controls/aws/aws_foundational_security_athena_1.yaml old mode 100755 new mode 100644 index b19415cad..880b880fe --- a/compliance/controls/aws/aws_foundational_security_athena_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_athena_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks if an Athena workgroup is encrypted at rest. The control fails if an Athena workgroup isn't encrypted at rest. ID: aws_foundational_security_athena_1 -Title: "1 Athena workgroups should be encrypted at rest" -Description: "This control checks if an Athena workgroup is encrypted at rest. The control fails if an Athena workgroup isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - name as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when encryption_option is not null then 'ok' - else 'alarm' - end as status, - case - when encryption_option is not null then name || ' encryption at rest enabled.' - else name || ' encryption at rest disabled.' - end as reason - from - aws_athena_workgroup; - PrimaryTable: aws_athena_workgroup ListOfTables: - aws_athena_workgroup Parameters: [] + PrimaryTable: aws_athena_workgroup + QueryToExecute: | + SELECT + name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encryption_option IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_option IS NOT NULL THEN name || ' encryption at rest enabled.' + ELSE name || ' encryption at rest disabled.' + END AS reason + FROM + aws_athena_workgroup; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Athena workgroups should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_autoscaling_1.yaml b/compliance/controls/aws/aws_foundational_security_autoscaling_1.yaml old mode 100755 new mode 100644 index 0831dc8c3..7b3dcd13b --- a/compliance/controls/aws/aws_foundational_security_autoscaling_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_autoscaling_1.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether your Auto Scaling groups that are associated with a load balancer are using Elastic Load Balancing health checks. This ensures that the group can determine an instance's health based on additional tests provided by the load balancer. Using Elastic Load Balancing health checks can help support the availability of applications that use EC2 Auto Scaling groups. ID: aws_foundational_security_autoscaling_1 -Title: "1 Auto Scaling groups associated with a load balancer should use load balancer health checks" -Description: "This control checks whether your Auto Scaling groups that are associated with a load balancer are using Elastic Load Balancing health checks. This ensures that the group can determine an instance's health based on additional tests provided by the load balancer. Using Elastic Load Balancing health checks can help support the availability of applications that use EC2 Auto Scaling groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n autoscaling_group_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when load_balancer_names is null and target_group_arns is null then 'alarm'\n when health_check_type != 'ELB' then 'alarm'\n else 'ok'\n end as status,\n case\n when load_balancer_names is null and target_group_arns is null then title || ' not associated with a load balancer.'\n when health_check_type != 'ELB' then title || ' does not use ELB health check.'\n else title || ' uses ELB health check.'\n end as reason\n \n \nfrom\n aws_ec2_autoscaling_group;" - PrimaryTable: aws_ec2_autoscaling_group ListOfTables: - aws_ec2_autoscaling_group Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + SELECT + autoscaling_group_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN load_balancer_names IS NULL AND target_group_arns IS NULL THEN 'alarm' + WHEN health_check_type != 'ELB' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN load_balancer_names IS NULL AND target_group_arns IS NULL THEN title || ' not associated with a load balancer.' + WHEN health_check_type != 'ELB' THEN title || ' does not use ELB health check.' + ELSE title || ' uses ELB health check.' + END AS reason + FROM + aws_ec2_autoscaling_group; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Auto Scaling groups associated with a load balancer should use load balancer health checks \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_autoscaling_2.yaml b/compliance/controls/aws/aws_foundational_security_autoscaling_2.yaml old mode 100755 new mode 100644 index 4b1f0b80c..083d68d24 --- a/compliance/controls/aws/aws_foundational_security_autoscaling_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_autoscaling_2.yaml @@ -1,14 +1,25 @@ +Description: This control checks whether an Auto Scaling group spans multiple Availability Zones. The control fails if an Auto Scaling group does not span multiple availability zones. ID: aws_foundational_security_autoscaling_2 -Title: "2 Amazon EC2 Auto Scaling group should cover multiple Availability Zones" -Description: "This control checks whether an Auto Scaling group spans multiple Availability Zones. The control fails if an Auto Scaling group does not span multiple availability zones." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n autoscaling_group_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(availability_zones) > 1 then 'ok'\n else 'alarm'\n end as status,\n title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason\n \n \nfrom\n aws_ec2_autoscaling_group;" - PrimaryTable: aws_ec2_autoscaling_group ListOfTables: - aws_ec2_autoscaling_group Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + SELECT + autoscaling_group_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(availability_zones) > 1 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason + FROM + aws_ec2_autoscaling_group; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Amazon EC2 Auto Scaling group should cover multiple Availability Zones \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_autoscaling_3.yaml b/compliance/controls/aws/aws_foundational_security_autoscaling_3.yaml old mode 100755 new mode 100644 index f8280edfe..6a8885d3a --- a/compliance/controls/aws/aws_foundational_security_autoscaling_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_autoscaling_3.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether IMDSv2 is enabled on all instances launched by Amazon EC2 Auto Scaling groups. The control fails if the Instance Metadata Service (IMDS) version is not included in the launch configuration or if both IMDSv1 and IMDSv2 are enabled. ID: aws_foundational_security_autoscaling_3 -Title: "3 Auto Scaling group should configure EC2 instances to require Instance Metadata Service Version 2 (IMDSv2)" -Description: "This control checks whether IMDSv2 is enabled on all instances launched by Amazon EC2 Auto Scaling groups. The control fails if the Instance Metadata Service (IMDS) version is not included in the launch configuration or if both IMDSv1 and IMDSv2 are enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - launch_configuration_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when metadata_options_http_tokens = 'required' then 'ok' - else 'alarm' - end as status, - case - when metadata_options_http_tokens = 'required' then title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' - else title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' - end as reason - from - aws_ec2_launch_configuration; - PrimaryTable: aws_ec2_launch_configuration ListOfTables: - aws_ec2_launch_configuration Parameters: [] + PrimaryTable: aws_ec2_launch_configuration + QueryToExecute: | + SELECT + launch_configuration_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN metadata_options_http_tokens = 'required' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN metadata_options_http_tokens = 'required' THEN title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' + ELSE title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' + END AS reason + FROM + aws_ec2_launch_configuration; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Auto Scaling group should configure EC2 instances to require Instance Metadata Service Version 2 (IMDSv2) \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_autoscaling_4.yaml b/compliance/controls/aws/aws_foundational_security_autoscaling_4.yaml old mode 100755 new mode 100644 index 097e733da..25ebf8636 --- a/compliance/controls/aws/aws_foundational_security_autoscaling_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_autoscaling_4.yaml @@ -1,30 +1,29 @@ +Description: This control checks the number of network hops that a metadata token can travel. The control fails if the metadata response hop limit is greater than 1. ID: aws_foundational_security_autoscaling_4 -Title: "4 Auto Scaling group launch configuration should not have metadata response hop limit greater than 1" -Description: "This control checks the number of network hops that a metadata token can travel. The control fails if the metadata response hop limit is greater than 1." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - launch_configuration_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when metadata_options_put_response_hop_limit is null then 'ok' - when metadata_options_put_response_hop_limit > 1 then 'alarm' - else 'ok' - end as status, - case - --If you do not specify a value, the hop limit default is 1. - when metadata_options_put_response_hop_limit is null then title || ' metadata response hop limit set to default.' - else title || ' has a metadata response hop limit of ' || metadata_options_put_response_hop_limit || '.' - end as reason - from - aws_ec2_launch_configuration; - PrimaryTable: aws_ec2_launch_configuration ListOfTables: - aws_ec2_launch_configuration Parameters: [] + PrimaryTable: aws_ec2_launch_configuration + QueryToExecute: | + SELECT + launch_configuration_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN metadata_options_put_response_hop_limit IS NULL THEN 'ok' + WHEN metadata_options_put_response_hop_limit > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN metadata_options_put_response_hop_limit IS NULL THEN title || ' metadata response hop limit set to default.' + ELSE title || ' has a metadata response hop limit of ' || metadata_options_put_response_hop_limit || '.' + END AS reason + FROM + aws_ec2_launch_configuration; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 Auto Scaling group launch configuration should not have metadata response hop limit greater than 1 \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_autoscaling_5.yaml b/compliance/controls/aws/aws_foundational_security_autoscaling_5.yaml old mode 100755 new mode 100644 index ba11b5b8a..ff2b2eff7 --- a/compliance/controls/aws/aws_foundational_security_autoscaling_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_autoscaling_5.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an Auto Scaling groups associated launch configuration assigns a public IP address to the group's instances. ID: aws_foundational_security_autoscaling_5 -Title: "5 Amazon EC2 instances launched using Auto Scaling group launch configurations should not have Public IP addresses" -Description: "This control checks whether an Auto Scaling groups associated launch configuration assigns a public IP address to the group's instances." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - launch_configuration_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when associate_public_ip_address then 'alarm' - else 'ok' - end as status, - case - when associate_public_ip_address then title || ' public IP enabled.' - else title || ' public IP disabled.' - end as reason - from - aws_ec2_launch_configuration; - PrimaryTable: aws_ec2_launch_configuration ListOfTables: - aws_ec2_launch_configuration Parameters: [] + PrimaryTable: aws_ec2_launch_configuration + QueryToExecute: | + SELECT + launch_configuration_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN associate_public_ip_address THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN associate_public_ip_address THEN title || ' public IP enabled.' + ELSE title || ' public IP disabled.' + END AS reason + FROM + aws_ec2_launch_configuration; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 Amazon EC2 instances launched using Auto Scaling group launch configurations should not have Public IP addresses \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_autoscaling_6.yaml b/compliance/controls/aws/aws_foundational_security_autoscaling_6.yaml old mode 100755 new mode 100644 index 09a1c01ce..fa5b32d87 --- a/compliance/controls/aws/aws_foundational_security_autoscaling_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_autoscaling_6.yaml @@ -1,11 +1,16 @@ +Description: This control checks whether an Amazon EC2 Auto Scaling group uses multiple instance types. The control fails if the Auto Scaling group has only one instance type defined. ID: aws_foundational_security_autoscaling_6 -Title: "6 Auto Scaling groups should use multiple instance types in multiple Availability Zones" -Description: "This control checks whether an Amazon EC2 Auto Scaling group uses multiple instance types. The control fails if the Auto Scaling group has only one instance type defined." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with autoscaling_groups as ( - select + ListOfTables: + - aws_ec2_autoscaling_group + Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + WITH autoscaling_groups AS ( + SELECT autoscaling_group_arn, title, mixed_instances_policy_launch_template_overrides, @@ -13,41 +18,36 @@ Query: tags, _ctx, account_id - from + FROM aws_ec2_autoscaling_group ), - distinct_instance_types_count as ( - select + distinct_instance_types_count AS ( + SELECT autoscaling_group_arn, - count(distinct(e -> 'InstanceType')) as distinct_instance_types - from + COUNT(DISTINCT(e -> 'InstanceType')) AS distinct_instance_types + FROM autoscaling_groups, - jsonb_array_elements(mixed_instances_policy_launch_template_overrides) as e - group by + jsonb_array_elements(mixed_instances_policy_launch_template_overrides) AS e + GROUP BY autoscaling_group_arn, title, mixed_instances_policy_launch_template_overrides ) - select - a.autoscaling_group_arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.distinct_instance_types > 1 then 'ok' - else 'alarm' - end as status, - case - when b.distinct_instance_types > 1 then title || ' uses ' || b.distinct_instance_types || ' instance types.' - else title || ' does not use multiple instance types.' - end as reason - from - autoscaling_groups as a - left join distinct_instance_types_count as b on a.autoscaling_group_arn = b.autoscaling_group_arn; - PrimaryTable: aws_ec2_autoscaling_group - ListOfTables: - - aws_ec2_autoscaling_group - Parameters: [] + SELECT + a.autoscaling_group_arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.distinct_instance_types > 1 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.distinct_instance_types > 1 THEN title || ' uses ' || b.distinct_instance_types || ' instance types.' + ELSE title || ' does not use multiple instance types.' + END AS reason + FROM + autoscaling_groups AS a + LEFT JOIN distinct_instance_types_count AS b ON a.autoscaling_group_arn = b.autoscaling_group_arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 Auto Scaling groups should use multiple instance types in multiple Availability Zones \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_autoscaling_9.yaml b/compliance/controls/aws/aws_foundational_security_autoscaling_9.yaml old mode 100755 new mode 100644 index 678313597..76cf41c82 --- a/compliance/controls/aws/aws_foundational_security_autoscaling_9.yaml +++ b/compliance/controls/aws/aws_foundational_security_autoscaling_9.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an Amazon EC2 Auto Scaling group is created from an EC2 launch template. This control fails if an Amazon EC2 Auto Scaling group is not created with a launch template or if a launch template is not specified in a mixed instances policy. ID: aws_foundational_security_autoscaling_9 -Title: "9 EC2 Auto Scaling groups should use EC2 launch templates" -Description: "This control checks whether an Amazon EC2 Auto Scaling group is created from an EC2 launch template. This control fails if an Amazon EC2 Auto Scaling group is not created with a launch template or if a launch template is not specified in a mixed instances policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - autoscaling_group_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when launch_template_id is not null then 'ok' - else 'alarm' - end as status, - case - when launch_template_id is not null then title || ' using an EC2 launch template.' - else title || ' not using an EC2 launch template.' - end as reason - from - aws_ec2_autoscaling_group; - PrimaryTable: aws_ec2_autoscaling_group ListOfTables: - aws_ec2_autoscaling_group Parameters: [] + PrimaryTable: aws_ec2_autoscaling_group + QueryToExecute: | + SELECT + autoscaling_group_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN launch_template_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN launch_template_id IS NOT NULL THEN title || ' using an EC2 launch template.' + ELSE title || ' not using an EC2 launch template.' + END AS reason + FROM + aws_ec2_autoscaling_group; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 EC2 Auto Scaling groups should use EC2 launch templates \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_backup_1.yaml b/compliance/controls/aws/aws_foundational_security_backup_1.yaml old mode 100755 new mode 100644 index 77f00e991..7e6ab1719 --- a/compliance/controls/aws/aws_foundational_security_backup_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_backup_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks if an AWS Backup recovery point is encrypted at rest. The control fails if the recovery point isn't encrypted at rest. ID: aws_foundational_security_backup_1 -Title: "1 AWS Backup recovery points should be encrypted at rest" -Description: "This control checks if an AWS Backup recovery point is encrypted at rest. The control fails if the recovery point isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - recovery_point_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when is_encrypted then 'ok' - else 'alarm' - end as status, - case - when is_encrypted then recovery_point_arn || ' encryption enabled.' - else recovery_point_arn || ' encryption disabled.' - end as reason - from - aws_backup_recovery_point; - PrimaryTable: aws_backup_recovery_point ListOfTables: - aws_backup_recovery_point Parameters: [] + PrimaryTable: aws_backup_recovery_point + QueryToExecute: | + SELECT + recovery_point_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN is_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN is_encrypted THEN recovery_point_arn || ' encryption enabled.' + ELSE recovery_point_arn || ' encryption disabled.' + END AS reason + FROM + aws_backup_recovery_point; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 AWS Backup recovery points should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudformation_1.yaml b/compliance/controls/aws/aws_foundational_security_cloudformation_1.yaml old mode 100755 new mode 100644 index 4415d56f5..aab13114c --- a/compliance/controls/aws/aws_foundational_security_cloudformation_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudformation_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an Amazon Simple Notification Service notification is integrated with a CloudFormation stack. The control fails for a CloudFormation stack if there is no SNS notification associated with it. ID: aws_foundational_security_cloudformation_1 -Title: "1 CloudFormation stacks should be integrated with Simple Notification Service (SNS)" -Description: "This control checks whether an Amazon Simple Notification Service notification is integrated with a CloudFormation stack. The control fails for a CloudFormation stack if there is no SNS notification associated with it." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when jsonb_array_length(notification_arns) > 0 then 'ok' - else 'alarm' - end as status, - case - when jsonb_array_length(notification_arns) > 0 then title || ' notifications enabled.' - else title || ' notifications disabled.' - end as reason - from - aws_cloudformation_stack; - PrimaryTable: aws_cloudformation_stack ListOfTables: - aws_cloudformation_stack Parameters: [] + PrimaryTable: aws_cloudformation_stack + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(notification_arns) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(notification_arns) > 0 THEN title || ' notifications enabled.' + ELSE title || ' notifications disabled.' + END AS reason + FROM + aws_cloudformation_stack; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 CloudFormation stacks should be integrated with Simple Notification Service (SNS) \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudfront_1.yaml b/compliance/controls/aws/aws_foundational_security_cloudfront_1.yaml old mode 100755 new mode 100644 index 43bf112e1..012dd1623 --- a/compliance/controls/aws/aws_foundational_security_cloudfront_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudfront_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an Amazon CloudFront distribution is configured to return a specific object that is the default root object. The control fails if the CloudFront distribution does not have a default root object configured. ID: aws_foundational_security_cloudfront_1 -Title: "1 CloudFront distributions should have a default root object configured" -Description: "This control checks whether an Amazon CloudFront distribution is configured to return a specific object that is the default root object. The control fails if the CloudFront distribution does not have a default root object configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when default_root_object = '' then 'alarm' - else 'ok' - end as status, - case - when default_root_object = '' then title || ' default root object not configured.' - else title || ' default root object configured.' - end as reason - from - aws_cloudfront_distribution; - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN default_root_object = '' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN default_root_object = '' THEN title || ' default root object not configured.' + ELSE title || ' default root object configured.' + END AS reason + FROM + aws_cloudfront_distribution; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 CloudFront distributions should have a default root object configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudfront_10.yaml b/compliance/controls/aws/aws_foundational_security_cloudfront_10.yaml old mode 100755 new mode 100644 index b8cbcf4b4..6ba2755be --- a/compliance/controls/aws/aws_foundational_security_cloudfront_10.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudfront_10.yaml @@ -1,39 +1,39 @@ +Description: This control checks if Amazon CloudFront distributions are using deprecated SSL protocols for HTTPS communication between CloudFront edge locations and your custom origins. This control fails if a CloudFront distribution has a CustomOriginConfig where OriginSslProtocols includes SSLv3. ID: aws_foundational_security_cloudfront_10 -Title: "10 CloudFront distributions should not use deprecated SSL protocols between edge locations and custom origins" -Description: "This control checks if Amazon CloudFront distributions are using deprecated SSL protocols for HTTPS communication between CloudFront edge locations and your custom origins. This control fails if a CloudFront distribution has a CustomOriginConfig where OriginSslProtocols includes SSLv3." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with origin_ssl_protocols as ( - select - distinct arn, - o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' as origin_protocol_policy - from - aws_cloudfront_distribution, - jsonb_array_elements(origins) as o - where - o -> 'CustomOriginConfig' -> 'OriginSslProtocols' -> 'Items' @> '["SSLv3"]' - ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when o.arn is null then 'ok' - else 'alarm' - end as status, - case - when o.arn is null then title || ' does not have deprecated SSL protocols.' - else title || ' has deprecated SSL protocols.' - end as reason - from - aws_cloudfront_distribution as b - left join origin_ssl_protocols as o on b.arn = o.arn; - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + WITH origin_ssl_protocols AS ( + SELECT + DISTINCT arn, + o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' AS origin_protocol_policy + FROM + aws_cloudfront_distribution, + jsonb_array_elements(origins) AS o + WHERE + o -> 'CustomOriginConfig' -> 'OriginSslProtocols' -> 'Items' @> '["SSLv3"]' + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN o.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN o.arn IS NULL THEN title || ' does not have deprecated SSL protocols.' + ELSE title || ' has deprecated SSL protocols.' + END AS reason + FROM + aws_cloudfront_distribution AS b + LEFT JOIN origin_ssl_protocols AS o ON b.arn = o.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 10 CloudFront distributions should not use deprecated SSL protocols between edge locations and custom origins \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudfront_12.yaml b/compliance/controls/aws/aws_foundational_security_cloudfront_12.yaml old mode 100755 new mode 100644 index 2429c2b7a..939af10db --- a/compliance/controls/aws/aws_foundational_security_cloudfront_12.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudfront_12.yaml @@ -1,15 +1,52 @@ +Description: This control checks whether Amazon CloudFront distributions are pointing to non-existent Amazon S3 origins. The control fails for a CloudFront distribution if the origin is configured to point to a non-existent bucket. This control only applies to CloudFront distributions where an S3 bucket without static website hosting is the S3 origin. ID: aws_foundational_security_cloudfront_12 -Title: "12 CloudFront distributions should not point to non-existent S3 origins" -Description: "This control checks whether Amazon CloudFront distributions are pointing to non-existent Amazon S3 origins. The control fails for a CloudFront distribution if the origin is configured to point to a non-existent bucket. This control only applies to CloudFront distributions where an S3 bucket without static website hosting is the S3 origin." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with distribution_with_non_existent_bucket as (\n select\n distinct d.arn as arn,\n to_jsonb(string_to_array((string_agg(split_part(o ->> 'Id', '.s3', 1), ',')),',')) as bucket_name_list\n from\n aws_cloudfront_distribution as d,\n jsonb_array_elements(d.origins) as o\n left join aws_s3_bucket as b on b.name = split_part(o ->> 'Id', '.s3', 1)\n where\n b.name is null\n and o ->> 'DomainName' like '%.s3.%'\n group by\n d.arn\n)\nselect\n distinct b.arn as resource,\nd.og_account_id as og_account_id,\nd.og_resource_id as og_resource_id,\n case\n when b.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is null then title || ' does not point to any non-existent S3 origins.'\n when jsonb_array_length(b.bucket_name_list) > 0\n then title ||\n case\n when jsonb_array_length(b.bucket_name_list) > 2\n then concat(' point to non-existent S3 origins ', b.bucket_name_list #>> '{0}', ', ', b.bucket_name_list #>> '{1}', ' and ' || (jsonb_array_length(b.bucket_name_list) - 2)::text || ' more.' )\n when jsonb_array_length(b.bucket_name_list) = 2\n then concat(' point to non-existent S3 origins ', b.bucket_name_list #>> '{0}', ' and ', b.bucket_name_list #>> '{1}', '.')\n else concat(' point to non-existent S3 origin ', b.bucket_name_list #>> '{0}', '.')\n end\n end as reason\n \n \nfrom\n aws_cloudfront_distribution as d\n left join distribution_with_non_existent_bucket as b on b.arn = d.arn;" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution - aws_s3_bucket Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + WITH distribution_with_non_existent_bucket AS ( + SELECT + DISTINCT d.arn AS arn, + TO_JSONB(STRING_TO_ARRAY((STRING_AGG(SPLIT_PART(o ->> 'Id', '.s3', 1), ',')), ',')) AS bucket_name_list + FROM + aws_cloudfront_distribution AS d, + JSONB_ARRAY_ELEMENTS(d.origins) AS o + LEFT JOIN aws_s3_bucket AS b ON b.name = SPLIT_PART(o ->> 'Id', '.s3', 1) + WHERE + b.name IS NULL + AND o ->> 'DomainName' LIKE '%.s3.%' + GROUP BY + d.arn + ) + SELECT + DISTINCT b.arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NULL THEN title || ' does not point to any non-existent S3 origins.' + WHEN JSONB_ARRAY_LENGTH(b.bucket_name_list) > 0 + THEN title || + CASE + WHEN JSONB_ARRAY_LENGTH(b.bucket_name_list) > 2 + THEN CONCAT(' point to non-existent S3 origins ', b.bucket_name_list #>> '{0}', ', ', b.bucket_name_list #>> '{1}', ' and ' || (JSONB_ARRAY_LENGTH(b.bucket_name_list) - 2)::TEXT || ' more.' ) + WHEN JSONB_ARRAY_LENGTH(b.bucket_name_list) = 2 + THEN CONCAT(' point to non-existent S3 origins ', b.bucket_name_list #>> '{0}', ' and ', b.bucket_name_list #>> '{1}', '.') + ELSE CONCAT(' point to non-existent S3 origin ', b.bucket_name_list #>> '{0}', '.') + END + END AS reason + FROM + aws_cloudfront_distribution AS d + LEFT JOIN distribution_with_non_existent_bucket AS b ON b.arn = d.arn; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 12 CloudFront distributions should not point to non-existent S3 origins \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudfront_3.yaml b/compliance/controls/aws/aws_foundational_security_cloudfront_3.yaml old mode 100755 new mode 100644 index f4b42cc35..1073274f0 --- a/compliance/controls/aws/aws_foundational_security_cloudfront_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudfront_3.yaml @@ -1,42 +1,43 @@ +Description: This control checks whether an Amazon CloudFront distribution requires viewers to use HTTPS directly or whether it uses redirection. The control fails if ViewerProtocolPolicy is set to allow-all for defaultCacheBehavior or for cacheBehaviors. ID: aws_foundational_security_cloudfront_3 -Title: "3 CloudFront distributions should require encryption in transit" -Description: "This control checks whether an Amazon CloudFront distribution requires viewers to use HTTPS directly or whether it uses redirection. The control fails if ViewerProtocolPolicy is set to allow-all for defaultCacheBehavior or for cacheBehaviors." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with data as ( - select - distinct arn - from - aws_cloudfront_distribution, - jsonb_array_elements( - case jsonb_typeof(cache_behaviors -> 'Items') - when 'array' then (cache_behaviors -> 'Items') - else null end - ) as cb - where - cb ->> 'ViewerProtocolPolicy' = 'allow-all' - ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when d.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') then 'alarm' - else 'ok' - end as status, - case - when d.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') then title || ' data not encrypted in transit.' - else title || ' data encrypted in transit.' - end as reason - from - aws_cloudfront_distribution as b - left join data as d on b.arn = d.arn; - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + WITH data AS ( + SELECT + DISTINCT arn + FROM + aws_cloudfront_distribution, + jsonb_array_elements( + CASE jsonb_typeof(cache_behaviors -> 'Items') + WHEN 'array' THEN (cache_behaviors -> 'Items') + ELSE NULL + END + ) AS cb + WHERE + cb ->> 'ViewerProtocolPolicy' = 'allow-all' + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN d.arn IS NOT NULL OR (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.arn IS NOT NULL OR (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') THEN title || ' data not encrypted in transit.' + ELSE title || ' data encrypted in transit.' + END AS reason + FROM + aws_cloudfront_distribution AS b + LEFT JOIN data AS d ON b.arn = d.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 CloudFront distributions should require encryption in transit \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudfront_4.yaml b/compliance/controls/aws/aws_foundational_security_cloudfront_4.yaml old mode 100755 new mode 100644 index baa1a7328..2ba0aff63 --- a/compliance/controls/aws/aws_foundational_security_cloudfront_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudfront_4.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an Amazon CloudFront distribution is configured with an origin group that has two or more origins. CloudFront origin failover can increase availability. Origin failover automatically redirects traffic to a secondary origin if the primary origin is unavailable or if it returns specific HTTP response status codes. ID: aws_foundational_security_cloudfront_4 -Title: "4 CloudFront distributions should have origin failover configured" -Description: "This control checks whether an Amazon CloudFront distribution is configured with an origin group that has two or more origins. CloudFront origin failover can increase availability. Origin failover automatically redirects traffic to a secondary origin if the primary origin is unavailable or if it returns specific HTTP response status codes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when origin_groups ->> 'Items' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when origin_groups ->> 'Items' is not null then title || ' origin group is configured.'\n else title || ' origin group not configured.'\n end as reason\n \n \nfrom\n aws_cloudfront_distribution;" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN origin_groups ->> 'Items' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN origin_groups ->> 'Items' IS NOT NULL THEN title || ' origin group is configured.' + ELSE title || ' origin group not configured.' + END AS reason + FROM + aws_cloudfront_distribution; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 CloudFront distributions should have origin failover configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudfront_5.yaml b/compliance/controls/aws/aws_foundational_security_cloudfront_5.yaml old mode 100755 new mode 100644 index 1ac52b823..5447529c9 --- a/compliance/controls/aws/aws_foundational_security_cloudfront_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudfront_5.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether server access logging is enabled on CloudFront distributions. The control fails if access logging is not enabled for a distribution. ID: aws_foundational_security_cloudfront_5 -Title: "5 CloudFront distributions should have logging enabled" -Description: "This control checks whether server access logging is enabled on CloudFront distributions. The control fails if access logging is not enabled for a distribution." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when logging ->> 'Enabled' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when logging ->> 'Enabled' = 'true' then title || ' logging enabled.'\n else title || ' logging disabled.'\n end as reason\n \n \nfrom\n aws_cloudfront_distribution;" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logging ->> 'Enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN logging ->> 'Enabled' = 'true' THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason + FROM + aws_cloudfront_distribution; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 CloudFront distributions should have logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudfront_6.yaml b/compliance/controls/aws/aws_foundational_security_cloudfront_6.yaml old mode 100755 new mode 100644 index 21f66238f..8d072d313 --- a/compliance/controls/aws/aws_foundational_security_cloudfront_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudfront_6.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether CloudFront distributions are associated with either AWS WAF or AWS WAFv2 web ACLs. The control fails if the distribution is not associated with a web ACL. ID: aws_foundational_security_cloudfront_6 -Title: "6 CloudFront distributions should have AWS WAF enabled" -Description: "This control checks whether CloudFront distributions are associated with either AWS WAF or AWS WAFv2 web ACLs. The control fails if the distribution is not associated with a web ACL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when web_acl_id <> '' then 'ok' - else 'alarm' - end as status, - case - when web_acl_id <> '' then title || ' associated with WAF.' - else title || ' not associated with WAF.' - end as reason - from - aws_cloudfront_distribution; - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN web_acl_id <> '' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN web_acl_id <> '' THEN title || ' associated with WAF.' + ELSE title || ' not associated with WAF.' + END AS reason + FROM + aws_cloudfront_distribution; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 CloudFront distributions should have AWS WAF enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudfront_7.yaml b/compliance/controls/aws/aws_foundational_security_cloudfront_7.yaml old mode 100755 new mode 100644 index 9ff7c51d9..85eeb275a --- a/compliance/controls/aws/aws_foundational_security_cloudfront_7.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudfront_7.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether CloudFront distributions are using the default SSL/TLS certificate CloudFront provides. This control passes if the CloudFront distribution uses a custom SSL/TLS certificate. This control fails if the CloudFront distribution uses the default SSL/TLS certificate. ID: aws_foundational_security_cloudfront_7 -Title: "7 CloudFront distributions should use custom SSL/TLS certificates" -Description: "This control checks whether CloudFront distributions are using the default SSL/TLS certificate CloudFront provides. This control passes if the CloudFront distribution uses a custom SSL/TLS certificate. This control fails if the CloudFront distribution uses the default SSL/TLS certificate." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when viewer_certificate ->> 'ACMCertificateArn' is not null and viewer_certificate ->> 'Certificate' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when viewer_certificate ->> 'ACMCertificateArn' is not null and viewer_certificate ->> 'Certificate' is not null then title || ' uses custom SSL certificate.'\n else title || ' does not use custom SSL certificate.'\n end as reason\n \n \nfrom\n aws_cloudfront_distribution;" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN viewer_certificate ->> 'ACMCertificateArn' IS NOT NULL + AND viewer_certificate ->> 'Certificate' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN viewer_certificate ->> 'ACMCertificateArn' IS NOT NULL + AND viewer_certificate ->> 'Certificate' IS NOT NULL THEN title || ' uses custom SSL certificate.' + ELSE title || ' does not use custom SSL certificate.' + END AS reason + FROM + aws_cloudfront_distribution; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 CloudFront distributions should use custom SSL/TLS certificates \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudfront_8.yaml b/compliance/controls/aws/aws_foundational_security_cloudfront_8.yaml old mode 100755 new mode 100644 index fba0cd032..950d6fad5 --- a/compliance/controls/aws/aws_foundational_security_cloudfront_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudfront_8.yaml @@ -1,28 +1,28 @@ +Description: This control checks if Amazon CloudFront distributions are using a custom SSL/TLS certificate and are configured to use SNI to serve HTTPS requests. This control fails if a custom SSL/TLS certificate is associated but the SSL/TLS support method is a dedicated IP address. ID: aws_foundational_security_cloudfront_8 -Title: "8 CloudFront distributions should use SNI to serve HTTPS requests" -Description: "This control checks if Amazon CloudFront distributions are using a custom SSL/TLS certificate and are configured to use SNI to serve HTTPS requests. This control fails if a custom SSL/TLS certificate is associated but the SSL/TLS support method is a dedicated IP address." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when viewer_certificate ->> 'SSLSupportMethod' = 'sni-only' then 'ok' - else 'alarm' - end as status, - case - when viewer_certificate ->> 'SSLSupportMethod' = 'sni-only' then title || ' SNI enabled.' - else title || ' SNI disabled.' - end as reason - from - aws_cloudfront_distribution; - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: [] + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN viewer_certificate ->> 'SSLSupportMethod' = 'sni-only' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN viewer_certificate ->> 'SSLSupportMethod' = 'sni-only' THEN title || ' SNI enabled.' + ELSE title || ' SNI disabled.' + END AS reason + FROM + aws_cloudfront_distribution; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 CloudFront distributions should use SNI to serve HTTPS requests \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudtrail_1.yaml b/compliance/controls/aws/aws_foundational_security_cloudtrail_1.yaml old mode 100755 new mode 100644 index f0d3faeb1..65d77d3e5 --- a/compliance/controls/aws/aws_foundational_security_cloudtrail_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudtrail_1.yaml @@ -1,15 +1,59 @@ +Description: This control checks that there is at least one multi-Region CloudTrail trail. ID: aws_foundational_security_cloudtrail_1 -Title: "1 CloudTrail should be enabled and configured with at least one multi-Region trail" -Description: "This control checks that there is at least one multi-Region CloudTrail trail." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with multi_region_trails as (\n select\n account_id,\n count(account_id) as num_multregion_trails\n from\n aws_cloudtrail_trail\n where\n is_multi_region_trail and region = home_region\n and is_logging\n group by\n account_id,\n is_multi_region_trail\n), organization_trails as (\n select\n is_organization_trail,\n is_logging,\n is_multi_region_trail,\n account_id\n from\n aws_cloudtrail_trail\n where\n is_organization_trail\n)\nselect\n distinct a.arn as resource,\na.og_account_id as og_account_id,\na.og_resource_id as og_resource_id,\n case\n when coalesce(num_multregion_trails, 0) >= 1 then 'ok'\n when o.is_organization_trail and o.is_logging and o.is_multi_region_trail then 'ok'\n when o.is_organization_trail and o.is_multi_region_trail and o.is_logging is null then 'info'\n else 'alarm'\n end as status,\n case\n when coalesce(num_multregion_trails, 0) >= 1 then a.title || ' has ' || coalesce(num_multregion_trails, 0) || ' multi-region trail(s).'\n when o.is_organization_trail and o.is_logging and o.is_multi_region_trail then a.title || ' has multi-region trail(s).'\n when o.is_organization_trail and o.is_multi_region_trail and o.is_logging is null then a.title || ' has organization trail, check organization account for cloudtrail logging status.'\n else a.title || ' does not have multi-region trail(s).'\n end as reason\n \nfrom\n aws_account as a\n left join multi_region_trails as b on a.account_id = b.account_id\n left join organization_trails as o on a.account_id = o.account_id;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail - aws_account Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH multi_region_trails AS ( + SELECT + account_id, + COUNT(account_id) AS num_multregion_trails + FROM + aws_cloudtrail_trail + WHERE + is_multi_region_trail + AND region = home_region + AND is_logging + GROUP BY + account_id, + is_multi_region_trail + ), organization_trails AS ( + SELECT + is_organization_trail, + is_logging, + is_multi_region_trail, + account_id + FROM + aws_cloudtrail_trail + WHERE + is_organization_trail + ) + SELECT + DISTINCT a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN COALESCE(num_multregion_trails, 0) >= 1 THEN 'ok' + WHEN o.is_organization_trail AND o.is_logging AND o.is_multi_region_trail THEN 'ok' + WHEN o.is_organization_trail AND o.is_multi_region_trail AND o.is_logging IS NULL THEN 'info' + ELSE 'alarm' + END AS status, + CASE + WHEN COALESCE(num_multregion_trails, 0) >= 1 THEN a.title || ' has ' || COALESCE(num_multregion_trails, 0) || ' multi-region trail(s).' + WHEN o.is_organization_trail AND o.is_logging AND o.is_multi_region_trail THEN a.title || ' has multi-region trail(s).' + WHEN o.is_organization_trail AND o.is_multi_region_trail AND o.is_logging IS NULL THEN a.title || ' has organization trail, check organization account for cloudtrail logging status.' + ELSE a.title || ' does not have multi-region trail(s).' + END AS reason + FROM + aws_account AS a + LEFT JOIN multi_region_trails AS b ON a.account_id = b.account_id + LEFT JOIN organization_trails AS o ON a.account_id = o.account_id Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 CloudTrail should be enabled and configured with at least one multi-Region trail \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudtrail_2.yaml b/compliance/controls/aws/aws_foundational_security_cloudtrail_2.yaml old mode 100755 new mode 100644 index 403a31daf..0c951732e --- a/compliance/controls/aws/aws_foundational_security_cloudtrail_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudtrail_2.yaml @@ -1,30 +1,30 @@ +Description: This control checks whether CloudTrail is configured to use the server-side encryption (SSE) AWS Key Management Service customer master key (CMK) encryption. The check passes if the KmsKeyId is defined. ID: aws_foundational_security_cloudtrail_2 -Title: "2 CloudTrail should have encryption at rest enabled" -Description: "This control checks whether CloudTrail is configured to use the server-side encryption (SSE) AWS Key Management Service customer master key (CMK) encryption. The check passes if the KmsKeyId is defined." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when kms_key_id is null then 'alarm' - else 'ok' - end as status, - case - when kms_key_id is null then title || ' logs are not encrypted at rest.' - else title || ' logs are encrypted at rest.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' logs are not encrypted at rest.' + ELSE title || ' logs are encrypted at rest.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 CloudTrail should have encryption at rest enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudtrail_4.yaml b/compliance/controls/aws/aws_foundational_security_cloudtrail_4.yaml old mode 100755 new mode 100644 index eee478ecc..517c77826 --- a/compliance/controls/aws/aws_foundational_security_cloudtrail_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudtrail_4.yaml @@ -1,30 +1,30 @@ +Description: This control checks whether log file integrity validation is enabled on a CloudTrail trail. CloudTrail log file validation creates a digitally signed digest file that contains a hash of each log that CloudTrail writes to Amazon S3. You can use these digest files to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. ID: aws_foundational_security_cloudtrail_4 -Title: "4 Ensure CloudTrail log file validation is enabled" -Description: "This control checks whether log file integrity validation is enabled on a CloudTrail trail. CloudTrail log file validation creates a digitally signed digest file that contains a hash of each log that CloudTrail writes to Amazon S3. You can use these digest files to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when log_file_validation_enabled then 'ok' - else 'alarm' - end as status, - case - when log_file_validation_enabled then title || ' log file validation enabled.' - else title || ' log file validation disabled.' - end as reason - from - aws_cloudtrail_trail - where - region = home_region; - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_file_validation_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_file_validation_enabled THEN title || ' log file validation enabled.' + ELSE title || ' log file validation disabled.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 Ensure CloudTrail log file validation is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_cloudtrail_5.yaml b/compliance/controls/aws/aws_foundational_security_cloudtrail_5.yaml old mode 100755 new mode 100644 index 25f25d9cd..f1dfc3040 --- a/compliance/controls/aws/aws_foundational_security_cloudtrail_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_cloudtrail_5.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether CloudTrail trails are configured to send logs to CloudWatch Logs. The control fails if the CloudWatchLogsLogGroupArn property of the trail is empty. ID: aws_foundational_security_cloudtrail_5 -Title: "5 Ensure CloudTrail trails are integrated with Amazon CloudWatch Logs" -Description: "This control checks whether CloudTrail trails are configured to send logs to CloudWatch Logs. The control fails if the CloudWatchLogsLogGroupArn property of the trail is empty." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then 'ok'\n else 'alarm'\n end as status,\n case\n when log_group_arn != 'null' and ((latest_delivery_time) > current_date - 1) then title || ' integrated with CloudWatch logs.'\n else title || ' not integrated with CloudWatch logs.'\n end as reason\n \n \nfrom\n aws_cloudtrail_trail\nwhere\n region = home_region;" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: [] + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > current_date - 1) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_group_arn != 'null' AND (latest_delivery_time > current_date - 1) THEN title || ' integrated with CloudWatch logs.' + ELSE title || ' not integrated with CloudWatch logs.' + END AS reason + FROM + aws_cloudtrail_trail + WHERE + region = home_region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 Ensure CloudTrail trails are integrated with Amazon CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_codebuild_1.yaml b/compliance/controls/aws/aws_foundational_security_codebuild_1.yaml old mode 100755 new mode 100644 index f300d4dc3..430fb0706 --- a/compliance/controls/aws/aws_foundational_security_codebuild_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_codebuild_1.yaml @@ -1,33 +1,33 @@ +Description: Authentication credentials should never be stored or transmitted in clear text or appear in the repository URL. Instead of personal access tokens or user name and password, you should use OAuth to grant authorization for accessing GitHub or Bitbucket repositories. Using personal access tokens or a user name and password could expose your credentials to unintended data exposure and unauthorized access. ID: aws_foundational_security_codebuild_1 -Title: "1 CodeBuild Bitbucket source repository URLs should not contain sensitive credentials" -Description: "Authentication credentials should never be stored or transmitted in clear text or appear in the repository URL. Instead of personal access tokens or user name and password, you should use OAuth to grant authorization for accessing GitHub or Bitbucket repositories. Using personal access tokens or a user name and password could expose your credentials to unintended data exposure and unauthorized access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when p.source ->> 'Type' not in ('GITHUB', 'BITBUCKET') then 'skip' - when c.auth_type = 'OAUTH' then 'ok' - else 'alarm' - end as status, - case - when p.source ->> 'Type' = 'NO_SOURCE' then p.title || ' doesn''t have input source code.' - when p.source ->> 'Type' not in ('GITHUB', 'BITBUCKET') then p.title || ' source code isn''t in GitHub/Bitbucket repository.' - when c.auth_type = 'OAUTH' then p.title || ' using OAuth to connect source repository.' - else p.title || ' not using OAuth to connect source repository.' - end as reason - from - aws_codebuild_project as p - left join aws_codebuild_source_credential as c on (p.region = c.region and p.source ->> 'Type' = c.server_type); - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project - aws_codebuild_source_credential Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.source ->> 'Type' NOT IN ('GITHUB', 'BITBUCKET') THEN 'skip' + WHEN c.auth_type = 'OAUTH' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.source ->> 'Type' = 'NO_SOURCE' THEN p.title || ' doesn''t have input source code.' + WHEN p.source ->> 'Type' NOT IN ('GITHUB', 'BITBUCKET') THEN p.title || ' source code isn''t in GitHub/Bitbucket repository.' + WHEN c.auth_type = 'OAUTH' THEN p.title || ' using OAuth to connect source repository.' + ELSE p.title || ' not using OAuth to connect source repository.' + END AS reason + FROM + aws_codebuild_project AS p + LEFT JOIN aws_codebuild_source_credential AS c ON (p.region = c.region AND p.source ->> 'Type' = c.server_type); Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 CodeBuild Bitbucket source repository URLs should not contain sensitive credentials \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_codebuild_2.yaml b/compliance/controls/aws/aws_foundational_security_codebuild_2.yaml old mode 100755 new mode 100644 index 968bad268..13b028bb5 --- a/compliance/controls/aws/aws_foundational_security_codebuild_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_codebuild_2.yaml @@ -1,14 +1,40 @@ +Description: This control checks whether the project contains the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Authentication credentials AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY should never be stored in clear text, as this could lead to unintended data exposure and unauthorized access. ID: aws_foundational_security_codebuild_2 -Title: "2 CodeBuild project environment variables should not contain clear text credentials" -Description: "This control checks whether the project contains the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Authentication credentials AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY should never be stored in clear text, as this could lead to unintended data exposure and unauthorized access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with invalid_key_name as (\n select\n distinct arn,\n name\n from\n aws_codebuild_project,\n jsonb_array_elements(environment -> 'EnvironmentVariables') as env\n where\n env ->> 'Name' ilike any(array['%AWS_ACCESS_KEY_ID%', '%AWS_SECRET_ACCESS_KEY%', '%PASSWORD%'])\n and env ->> 'Type' = 'PLAINTEXT'\n)\nselect\n a.arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is null then a.title || ' has no plaintext environment variables with sensitive AWS values.'\n else a.title || ' has plaintext environment variables with sensitive AWS values.'\n end as reason\n \n \nfrom\n aws_codebuild_project as a\n left join invalid_key_name b on a.arn = b.arn;" - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + WITH invalid_key_name AS ( + SELECT + DISTINCT arn, + name + FROM + aws_codebuild_project, + jsonb_array_elements(environment -> 'EnvironmentVariables') AS env + WHERE + env ->> 'Name' ILIKE ANY(ARRAY['%AWS_ACCESS_KEY_ID%', '%AWS_SECRET_ACCESS_KEY%', '%PASSWORD%']) + AND env ->> 'Type' = 'PLAINTEXT' + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NULL THEN a.title || ' has no plaintext environment variables with sensitive AWS values.' + ELSE a.title || ' has plaintext environment variables with sensitive AWS values.' + END AS reason + FROM + aws_codebuild_project AS a + LEFT JOIN invalid_key_name b ON a.arn = b.arn; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 CodeBuild project environment variables should not contain clear text credentials \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_codebuild_3.yaml b/compliance/controls/aws/aws_foundational_security_codebuild_3.yaml old mode 100755 new mode 100644 index ab922d57c..cbcb29a44 --- a/compliance/controls/aws/aws_foundational_security_codebuild_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_codebuild_3.yaml @@ -1,28 +1,28 @@ +Description: This control checks if Amazon S3 logs for an AWS CodeBuild project are encrypted. The control fails if encryption is deactivated for S3 logs for a CodeBuild project. ID: aws_foundational_security_codebuild_3 -Title: "3 CodeBuild S3 logs should be encrypted" -Description: "This control checks if Amazon S3 logs for an AWS CodeBuild project are encrypted. The control fails if encryption is deactivated for S3 logs for a CodeBuild project." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not (logs_config -> 'S3Logs' ->> 'EncryptionDisabled')::bool then 'ok' - else 'alarm' - end as status, - case - when not (logs_config -> 'S3Logs' ->> 'EncryptionDisabled')::bool then title || ' S3Logs encryption enabled.' - else title || ' S3Logs encryption disabled.' - end as reason - from - aws_codebuild_project; - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT (logs_config -> 'S3Logs' ->> 'EncryptionDisabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT (logs_config -> 'S3Logs' ->> 'EncryptionDisabled')::bool THEN title || ' S3Logs encryption enabled.' + ELSE title || ' S3Logs encryption disabled.' + END AS reason + FROM + aws_codebuild_project; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 CodeBuild S3 logs should be encrypted \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_codebuild_4.yaml b/compliance/controls/aws/aws_foundational_security_codebuild_4.yaml old mode 100755 new mode 100644 index e7f0e5346..fcbdaf880 --- a/compliance/controls/aws/aws_foundational_security_codebuild_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_codebuild_4.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether a CodeBuild project environment has at least one log option, either to S3 or CloudWatch logs enabled. This control fails if a CodeBuild project environment does not have at least one log option enabled. ID: aws_foundational_security_codebuild_4 -Title: "4 CodeBuild project environments should have a logging configuration" -Description: "This control checks whether a CodeBuild project environment has at least one log option, either to S3 or CloudWatch logs enabled. This control fails if a CodeBuild project environment does not have at least one log option enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when logs_config -> 'CloudWatchLogs' ->> 'Status' = 'ENABLED' or logs_config -> 'S3Logs' ->> 'Status' = 'ENABLED' then 'ok' - else 'alarm' - end as status, - case - when logs_config -> 'CloudWatchLogs' ->> 'Status' = 'ENABLED' or logs_config -> 'S3Logs' ->> 'Status' = 'ENABLED' then title || ' logging enabled.' - else title || ' logging disabled.' - end as reason - from - aws_codebuild_project; - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logs_config -> 'CloudWatchLogs' ->> 'Status' = 'ENABLED' OR logs_config -> 'S3Logs' ->> 'Status' = 'ENABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN logs_config -> 'CloudWatchLogs' ->> 'Status' = 'ENABLED' OR logs_config -> 'S3Logs' ->> 'Status' = 'ENABLED' THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason + FROM + aws_codebuild_project; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 CodeBuild project environments should have a logging configuration \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_codebuild_5.yaml b/compliance/controls/aws/aws_foundational_security_codebuild_5.yaml old mode 100755 new mode 100644 index 74b20cf40..a13b8b39a --- a/compliance/controls/aws/aws_foundational_security_codebuild_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_codebuild_5.yaml @@ -1,28 +1,28 @@ +Description: This control checks if an AWS CodeBuild project environment has privileged mode enabled. This control fails when an AWS CodeBuild project environment has privileged mode enabled. ID: aws_foundational_security_codebuild_5 -Title: "5 CodeBuild project environments should not have privileged mode enabled" -Description: "This control checks if an AWS CodeBuild project environment has privileged mode enabled. This control fails when an AWS CodeBuild project environment has privileged mode enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when environment ->> 'PrivilegedMode' = 'true' then 'alarm' - else 'ok' - end as status, - case - when environment ->> 'PrivilegedMode' = 'true' then title || ' environment privileged mode enabled.' - else title || ' environment privileged mode disabled.' - end as reason - from - aws_codebuild_project; - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: [] + PrimaryTable: aws_codebuild_project + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN environment ->> 'PrivilegedMode' = 'true' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN environment ->> 'PrivilegedMode' = 'true' THEN title || ' environment privileged mode enabled.' + ELSE title || ' environment privileged mode disabled.' + END AS reason + FROM + aws_codebuild_project; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 CodeBuild project environments should not have privileged mode enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_config_1.yaml b/compliance/controls/aws/aws_foundational_security_config_1.yaml old mode 100755 new mode 100644 index 29c3efe11..6f899dd1a --- a/compliance/controls/aws/aws_foundational_security_config_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_config_1.yaml @@ -1,15 +1,70 @@ +Description: This control checks whether AWS Config is enabled in the account for the local Region and is recording all resources. The AWS Config service performs configuration management of supported AWS resources in your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items, and any configuration changes between resources. ID: aws_foundational_security_config_1 -Title: "1 AWS Config should be enabled" -Description: "This control checks whether AWS Config is enabled in the account for the local Region and is recording all resources. The AWS Config service performs configuration management of supported AWS resources in your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items, and any configuration changes between resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "-- pgFormatter-ignore\n-- Get count for any region with all matching criteria\nwith global_recorders as (\n select\n count(*) as global_config_recorders\n from\n aws_config_configuration_recorder\n where\n recording_group -> 'IncludeGlobalResourceTypes' = 'true'\n and recording_group -> 'AllSupported' = 'true'\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n)\nselect\n 'arn:aws::' || a.region || ':' || a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n -- When any of the region satisfies with above CTE\n -- In left join of table, regions now having\n -- 'Recording' and 'LastStatus' matching criteria can be considered as OK\n when\n g.global_config_recorders >= 1\n and status ->> 'Recording' = 'true'\n and status ->> 'LastStatus' = 'SUCCESS'\n then 'ok'\n -- Skip any regions that are disabled in the account.\n when a.opt_in_status = 'not-opted-in' then 'skip'\n else 'alarm'\n end as status,\n -- Below cases are for citing respective reasons for control state\n case\n when a.opt_in_status = 'not-opted-in' then a.region || ' region is disabled.'\n else\n case\n when recording_group -> 'IncludeGlobalResourceTypes' = 'true' then a.region || ' IncludeGlobalResourceTypes enabled,'\n else a.region || ' IncludeGlobalResourceTypes disabled,'\n end ||\n case\n when recording_group -> 'AllSupported' = 'true' then ' AllSupported enabled,'\n else ' AllSupported disabled,'\n end ||\n case\n when status ->> 'Recording' = 'true' then ' Recording enabled'\n else ' Recording disabled'\n end ||\n case\n when status ->> 'LastStatus' = 'SUCCESS' then ' and LastStatus is SUCCESS.'\n else ' and LastStatus is not SUCCESS.'\n end\n end as reason\n \nfrom\n global_recorders as g,\n aws_region as a\n left join aws_config_configuration_recorder as r on r.account_id = a.account_id and r.region = a.name;" - PrimaryTable: aws_config_configuration_recorder ListOfTables: - aws_config_configuration_recorder - aws_region Parameters: [] + PrimaryTable: aws_config_configuration_recorder + QueryToExecute: | + WITH global_recorders AS ( + SELECT + COUNT(*) AS global_config_recorders + FROM + aws_config_configuration_recorder + WHERE + recording_group -> 'IncludeGlobalResourceTypes' = 'true' + AND recording_group -> 'AllSupported' = 'true' + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + ) + SELECT + 'arn:aws::' || a.region || ':' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN g.global_config_recorders >= 1 + AND status ->> 'Recording' = 'true' + AND status ->> 'LastStatus' = 'SUCCESS' + THEN 'ok' + WHEN a.opt_in_status = 'not-opted-in' + THEN 'skip' + ELSE 'alarm' + END AS status, + CASE + WHEN a.opt_in_status = 'not-opted-in' + THEN a.region || ' region is disabled.' + ELSE + CASE + WHEN recording_group -> 'IncludeGlobalResourceTypes' = 'true' + THEN a.region || ' IncludeGlobalResourceTypes enabled,' + ELSE a.region || ' IncludeGlobalResourceTypes disabled,' + END || + CASE + WHEN recording_group -> 'AllSupported' = 'true' + THEN ' AllSupported enabled,' + ELSE ' AllSupported disabled,' + END || + CASE + WHEN status ->> 'Recording' = 'true' + THEN ' Recording enabled' + ELSE ' Recording disabled' + END || + CASE + WHEN status ->> 'LastStatus' = 'SUCCESS' + THEN ' and LastStatus is SUCCESS.' + ELSE ' and LastStatus is not SUCCESS.' + END + END AS reason + FROM + global_recorders AS g, + aws_region AS a + LEFT JOIN aws_config_configuration_recorder AS r + ON r.account_id = a.account_id + AND r.region = a.name Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 AWS Config should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_dms_1.yaml b/compliance/controls/aws/aws_foundational_security_dms_1.yaml old mode 100755 new mode 100644 index 6d6d054c9..60ae749f6 --- a/compliance/controls/aws/aws_foundational_security_dms_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_dms_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether AWS DMS replication instances are public. To do this, it examines the value of the PubliclyAccessible field. A private replication instance has a private IP address that you cannot access outside of the replication network. A replication instance should have a private IP address when the source and target databases are in the same network. The network must also be connected to the replication instance's VPC using a VPN, AWS Direct Connect, or VPC peering. To learn more about public and private replication instances, see Public and private replication instances in the AWS Database Migration Service User Guide. ID: aws_foundational_security_dms_1 -Title: "1 AWS Database Migration Service replication instances should not be public" -Description: "This control checks whether AWS DMS replication instances are public. To do this, it examines the value of the PubliclyAccessible field. A private replication instance has a private IP address that you cannot access outside of the replication network. A replication instance should have a private IP address when the source and target databases are in the same network. The network must also be connected to the replication instance's VPC using a VPN, AWS Direct Connect, or VPC peering. To learn more about public and private replication instances, see Public and private replication instances in the AWS Database Migration Service User Guide." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when publicly_accessible then 'alarm' - else 'ok' - end as status, - case - when publicly_accessible then title || ' publicly accessible.' - else title || ' not publicly accessible.' - end as reason - from - aws_dms_replication_instance; - PrimaryTable: aws_dms_replication_instance ListOfTables: - aws_dms_replication_instance Parameters: [] + PrimaryTable: aws_dms_replication_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_dms_replication_instance; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 AWS Database Migration Service replication instances should not be public \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_dms_6.yaml b/compliance/controls/aws/aws_foundational_security_dms_6.yaml old mode 100755 new mode 100644 index e08cbc250..eb6bf87ac --- a/compliance/controls/aws/aws_foundational_security_dms_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_dms_6.yaml @@ -1,14 +1,28 @@ +Description: This control checks if automatic minor version upgrade is enabled for an AWS DMS replication instance. The control fails if automatic minor version upgrade isn't enabled for a DMS replication instance. ID: aws_foundational_security_dms_6 -Title: "6 DMS replication instances should have automatic minor version upgrade enabled" -Description: "This control checks if automatic minor version upgrade is enabled for an AWS DMS replication instance. The control fails if automatic minor version upgrade isn't enabled for a DMS replication instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when auto_minor_version_upgrade then 'ok'\n else 'alarm'\n end as status,\n case\n when auto_minor_version_upgrade then title || ' automatic minor version upgrade enabled.'\n else title || ' automatic minor version upgrade disabled.'\n end as reason\n \n \nfrom\n aws_dms_replication_instance;" - PrimaryTable: aws_dms_replication_instance ListOfTables: - aws_dms_replication_instance Parameters: [] + PrimaryTable: aws_dms_replication_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrade enabled.' + ELSE title || ' automatic minor version upgrade disabled.' + END AS reason + FROM + aws_dms_replication_instance; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 DMS replication instances should have automatic minor version upgrade enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_dms_8.yaml b/compliance/controls/aws/aws_foundational_security_dms_8.yaml old mode 100755 new mode 100644 index 9e37e54ea..7e7a84b56 --- a/compliance/controls/aws/aws_foundational_security_dms_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_dms_8.yaml @@ -1,41 +1,45 @@ +Description: This control checks whether logging is enabled with the minimum severity level of LOGGER_SEVERITY_DEFAULT for DMS replication tasks SOURCE_CAPTURE and SOURCE_UNLOAD. The control fails if logging isn't enabled for these tasks or if the minimum severity level is less than LOGGER_SEVERITY_DEFAULT. ID: aws_foundational_security_dms_8 -Title: "8 DMS replication tasks for the source database should have logging enabled" -Description: "This control checks whether logging is enabled with the minimum severity level of LOGGER_SEVERITY_DEFAULT for DMS replication tasks SOURCE_CAPTURE and SOURCE_UNLOAD. The control fails if logging isn't enabled for these tasks or if the minimum severity level is less than LOGGER_SEVERITY_DEFAULT." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with replication_task_logging as ( - select + ListOfTables: + - aws_dms_replication_task + Parameters: [] + PrimaryTable: aws_dms_replication_task + QueryToExecute: | + WITH replication_task_logging AS ( + SELECT arn, - bool_or(o ->> 'Id' = 'SOURCE_CAPTURE' and o ->> 'Severity' in ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')) as capture_logging_enabled, - bool_or(o ->> 'Id' = 'SOURCE_UNLOAD' and o ->> 'Severity' in ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')) as unload_logging_enabled - from + BOOL_OR(o ->> 'Id' = 'SOURCE_CAPTURE' AND o ->> 'Severity' IN ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')) AS capture_logging_enabled, + BOOL_OR(o ->> 'Id' = 'SOURCE_UNLOAD' AND o ->> 'Severity' IN ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')) AS unload_logging_enabled + FROM aws_dms_replication_task, - jsonb_array_elements(replication_task_settings -> 'Logging' -> 'LogComponents') as o - group by + JSONB_ARRAY_ELEMENTS(replication_task_settings -> 'Logging' -> 'LogComponents') AS o + GROUP BY arn ) - select - t.arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool as logging_enabled, - case - when (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool and l.capture_logging_enabled and l.unload_logging_enabled then 'ok' - else 'alarm' - end as status, - case - when (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool and l.capture_logging_enabled and l.unload_logging_enabled then title || ' source database logging enabled.' - else title || ' source database logging disabled.' - end as reason - from - aws_dms_replication_task as t - left join replication_task_logging as l on l.arn = t.arn; - PrimaryTable: aws_dms_replication_task - ListOfTables: - - aws_dms_replication_task - Parameters: [] + SELECT + t.arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + (replication_task_settings -> 'Logging' ->> 'EnableLogging')::BOOL AS logging_enabled, + CASE + WHEN (replication_task_settings -> 'Logging' ->> 'EnableLogging')::BOOL + AND l.capture_logging_enabled + AND l.unload_logging_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (replication_task_settings -> 'Logging' ->> 'EnableLogging')::BOOL + AND l.capture_logging_enabled + AND l.unload_logging_enabled THEN title || ' source database logging enabled.' + ELSE title || ' source database logging disabled.' + END AS reason + FROM + aws_dms_replication_task AS t + LEFT JOIN replication_task_logging AS l ON l.arn = t.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 DMS replication tasks for the source database should have logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_dms_9.yaml b/compliance/controls/aws/aws_foundational_security_dms_9.yaml old mode 100755 new mode 100644 index 2229b27ea..2ccfe12e4 --- a/compliance/controls/aws/aws_foundational_security_dms_9.yaml +++ b/compliance/controls/aws/aws_foundational_security_dms_9.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an AWS DMS endpoint uses an SSL connection. The control fails if the endpoint doesn't use SSL. ID: aws_foundational_security_dms_9 -Title: "9 DMS endpoints should use SSL" -Description: "This control checks whether an AWS DMS endpoint uses an SSL connection. The control fails if the endpoint doesn't use SSL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when ssl_mode = 'none' then 'alarm' - else 'ok' - end as status, - case - when ssl_mode = 'none' then title || ' SSL not configured.' - else title || ' SSL configured.' - end as reason - from - aws_dms_endpoint; - PrimaryTable: aws_dms_endpoint ListOfTables: - aws_dms_endpoint Parameters: [] + PrimaryTable: aws_dms_endpoint + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ssl_mode = 'none' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_mode = 'none' THEN title || ' SSL not configured.' + ELSE title || ' SSL configured.' + END AS reason + FROM + aws_dms_endpoint; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 DMS endpoints should use SSL \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_docdb_1.yaml b/compliance/controls/aws/aws_foundational_security_docdb_1.yaml old mode 100755 new mode 100644 index 4d4c34179..4c7bca6a2 --- a/compliance/controls/aws/aws_foundational_security_docdb_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_docdb_1.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an Amazon DocumentDB cluster is encrypted at rest. The control fails if an Amazon DocumentDB cluster isn't encrypted at rest. ID: aws_foundational_security_docdb_1 -Title: "1 Amazon DocumentDB clusters should be encrypted at rest" -Description: "This control checks whether an Amazon DocumentDB cluster is encrypted at rest. The control fails if an Amazon DocumentDB cluster isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_docdb_cluster;" - PrimaryTable: aws_docdb_cluster ListOfTables: - aws_docdb_cluster Parameters: [] + PrimaryTable: aws_docdb_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_docdb_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Amazon DocumentDB clusters should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_docdb_2.yaml b/compliance/controls/aws/aws_foundational_security_docdb_2.yaml old mode 100755 new mode 100644 index 95a9a7718..a16044988 --- a/compliance/controls/aws/aws_foundational_security_docdb_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_docdb_2.yaml @@ -1,25 +1,25 @@ +Description: This control checks whether an Amazon DocumentDB cluster has a backup retention period greater than or equal to 7 days. The control fails if the backup retention period is less than 7 days. ID: aws_foundational_security_docdb_2 -Title: "2 Amazon DocumentDB clusters should have an adequate backup retention period" -Description: "This control checks whether an Amazon DocumentDB cluster has a backup retention period greater than or equal to 7 days. The control fails if the backup retention period is less than 7 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when backup_retention_period >= 7 then 'ok' - else 'alarm' - end as status, - title || ' backup retention period is ' || backup_retention_period || ' day(s).' as reason - from - aws_docdb_cluster; - PrimaryTable: aws_docdb_cluster ListOfTables: - aws_docdb_cluster Parameters: [] + PrimaryTable: aws_docdb_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN backup_retention_period >= 7 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' backup retention period is ' || backup_retention_period || ' day(s).' AS reason + FROM + aws_docdb_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Amazon DocumentDB clusters should have an adequate backup retention period \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_docdb_4.yaml b/compliance/controls/aws/aws_foundational_security_docdb_4.yaml old mode 100755 new mode 100644 index 8340bac04..9d872f798 --- a/compliance/controls/aws/aws_foundational_security_docdb_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_docdb_4.yaml @@ -1,30 +1,30 @@ +Description: This control checks whether an Amazon DocumentDB cluster publishes audit logs to Amazon CloudWatch Logs. The control fails if the cluster doesn't publish audit logs to CloudWatch Logs. ID: aws_foundational_security_docdb_4 -Title: "4 Amazon DocumentDB clusters should publish audit logs to CloudWatch Logs" -Description: "This control checks whether an Amazon DocumentDB cluster publishes audit logs to Amazon CloudWatch Logs. The control fails if the cluster doesn't publish audit logs to CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - db_instance_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - engine, - case - when engine like 'docdb' and enabled_cloudwatch_logs_exports ?& array ['error', 'slowquery'] then 'ok' - else 'alarm' - end as status, - case - when engine like 'docdb' and enabled_cloudwatch_logs_exports ?& array ['error', 'slowquery'] - then title || ' ' || engine || ' logging enabled.' - else title || ' logging not enabled.' - end as reason - from - aws_docdb_cluster_instance; - PrimaryTable: aws_docdb_cluster_instance ListOfTables: - aws_docdb_cluster_instance Parameters: [] + PrimaryTable: aws_docdb_cluster_instance + QueryToExecute: | + SELECT + db_instance_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + engine, + CASE + WHEN engine LIKE 'docdb' AND enabled_cloudwatch_logs_exports ?& ARRAY ['error', 'slowquery'] THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine LIKE 'docdb' AND enabled_cloudwatch_logs_exports ?& ARRAY ['error', 'slowquery'] + THEN title || ' ' || engine || ' logging enabled.' + ELSE title || ' logging not enabled.' + END AS reason + FROM + aws_docdb_cluster_instance; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 Amazon DocumentDB clusters should publish audit logs to CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_docdb_5.yaml b/compliance/controls/aws/aws_foundational_security_docdb_5.yaml old mode 100755 new mode 100644 index 0e240891e..cd7c3cdba --- a/compliance/controls/aws/aws_foundational_security_docdb_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_docdb_5.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an Amazon DocumentDB cluster has deletion protection enabled. The control fails if the cluster doesn't have deletion protection enabled. ID: aws_foundational_security_docdb_5 -Title: "5 Amazon DocumentDB clusters should have deletion protection enabled" -Description: "This control checks whether an Amazon DocumentDB cluster has deletion protection enabled. The control fails if the cluster doesn't have deletion protection enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when deletion_protection then 'ok' - else 'alarm' - end status, - case - when deletion_protection then title || ' deletion protection enabled.' - else title || ' deletion protection disabled.' - end reason - from - aws_docdb_cluster; - PrimaryTable: aws_docdb_cluster ListOfTables: - aws_docdb_cluster Parameters: [] + PrimaryTable: aws_docdb_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN deletion_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN deletion_protection THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection disabled.' + END AS reason + FROM + aws_docdb_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 Amazon DocumentDB clusters should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_dynamodb_1.yaml b/compliance/controls/aws/aws_foundational_security_dynamodb_1.yaml old mode 100755 new mode 100644 index 0673aa04e..1fb4078d1 --- a/compliance/controls/aws/aws_foundational_security_dynamodb_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_dynamodb_1.yaml @@ -1,42 +1,47 @@ +Description: This control checks whether an Amazon DynamoDB table can scale its read and write capacity as needed. This control passes if the table uses either on-demand capacity mode or provisioned mode with auto scaling configured. Scaling capacity with demand avoids throttling exceptions, which helps to maintain availability of your applications. ID: aws_foundational_security_dynamodb_1 -Title: "1 DynamoDB tables should automatically scale capacity with demand" -Description: "This control checks whether an Amazon DynamoDB table can scale its read and write capacity as needed. This control passes if the table uses either on-demand capacity mode or provisioned mode with auto scaling configured. Scaling capacity with demand avoids throttling exceptions, which helps to maintain availability of your applications." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with table_with_autocaling as ( - select - t.resource_id as resource_id, - count(t.resource_id) as count - from - aws_appautoscaling_target as t where service_namespace = 'dynamodb' - group by t.resource_id - ) - select - d.arn as resource, - d.og_account_id as og_account_id, - d.og_resource_id as og_resource_id, - case - when d.billing_mode = 'PAY_PER_REQUEST' then 'ok' - when t.resource_id is null then 'alarm' - when t.count < 2 then 'alarm' - else 'ok' - end as status, - case - when d.billing_mode = 'PAY_PER_REQUEST' then d.title || ' on-demand mode enabled.' - when t.resource_id is null then d.title || ' autoscaling not enabled.' - when t.count < 2 then d.title || ' auto scaling not enabled for both read and write capacity.' - else d.title || ' autoscaling enabled for both read and write capacity.' - end as reason - from - aws_dynamodb_table as d - left join table_with_autocaling as t on concat('table/', d.name) = t.resource_id; - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_appautoscaling_target - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + WITH table_with_autocaling AS ( + SELECT + t.resource_id AS resource_id, + COUNT(t.resource_id) AS count + FROM + aws_appautoscaling_target AS t + WHERE + service_namespace = 'dynamodb' + GROUP BY + t.resource_id + ) + SELECT + d.arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN d.billing_mode = 'PAY_PER_REQUEST' THEN 'ok' + WHEN t.resource_id IS NULL THEN 'alarm' + WHEN t.count < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.billing_mode = 'PAY_PER_REQUEST' THEN d.title || ' on-demand mode enabled.' + WHEN t.resource_id IS NULL THEN d.title || ' autoscaling not enabled.' + WHEN t.count < 2 THEN d.title || ' auto scaling not enabled for both read and write capacity.' + ELSE d.title || ' autoscaling enabled for both read and write capacity.' + END AS reason + FROM + aws_dynamodb_table AS d + LEFT JOIN + table_with_autocaling AS t + ON CONCAT('table/', d.name) = t.resource_id; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 DynamoDB tables should automatically scale capacity with demand \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_dynamodb_2.yaml b/compliance/controls/aws/aws_foundational_security_dynamodb_2.yaml old mode 100755 new mode 100644 index 1e971ef2e..167abd277 --- a/compliance/controls/aws/aws_foundational_security_dynamodb_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_dynamodb_2.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether point-in-time recovery (PITR) is enabled for an Amazon DynamoDB table. Backups help you to recover more quickly from a security incident. They also strengthen the resilience of your systems. DynamoDB point-in-time recovery automates backups for DynamoDB tables. It reduces the time to recover from accidental delete or write operations. DynamoDB tables that have PITR enabled can be restored to any point in time in the last 35 days. ID: aws_foundational_security_dynamodb_2 -Title: "2 DynamoDB tables should have point-in-time recovery enabled" -Description: "This control checks whether point-in-time recovery (PITR) is enabled for an Amazon DynamoDB table. Backups help you to recover more quickly from a security incident. They also strengthen the resilience of your systems. DynamoDB point-in-time recovery automates backups for DynamoDB tables. It reduces the time to recover from accidental delete or write operations. DynamoDB tables that have PITR enabled can be restored to any point in time in the last 35 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when lower( point_in_time_recovery_description ->> 'PointInTimeRecoveryStatus' ) = 'disabled' then 'alarm' - else 'ok' - end as status, - case - when lower( point_in_time_recovery_description ->> 'PointInTimeRecoveryStatus' ) = 'disabled' then title || ' point-in-time recovery not enabled.' - else title || ' point-in-time recovery enabled.' - end as reason - from - aws_dynamodb_table; - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN LOWER(point_in_time_recovery_description ->> 'PointInTimeRecoveryStatus') = 'disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(point_in_time_recovery_description ->> 'PointInTimeRecoveryStatus') = 'disabled' THEN title || ' point-in-time recovery not enabled.' + ELSE title || ' point-in-time recovery enabled.' + END AS reason + FROM + aws_dynamodb_table; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 DynamoDB tables should have point-in-time recovery enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_dynamodb_3.yaml b/compliance/controls/aws/aws_foundational_security_dynamodb_3.yaml old mode 100755 new mode 100644 index 5f426c56f..970a112d3 --- a/compliance/controls/aws/aws_foundational_security_dynamodb_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_dynamodb_3.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether a DAX cluster is encrypted at rest. Encrypting data at rest reduces the risk of data stored on disk being accessed by a user not authenticated to AWS. The encryption adds another set of access controls to limit the ability of unauthorized users to access to the data. For example, API permissions are required to decrypt the data before it can be read. ID: aws_foundational_security_dynamodb_3 -Title: "3 DynamoDB Accelerator (DAX) clusters should be encrypted at rest" -Description: "This control checks whether a DAX cluster is encrypted at rest. Encrypting data at rest reduces the risk of data stored on disk being accessed by a user not authenticated to AWS. The encryption adds another set of access controls to limit the ability of unauthorized users to access to the data. For example, API permissions are required to decrypt the data before it can be read." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when sse_description ->> 'Status' = 'ENABLED' then 'ok' - else 'alarm' - end as status, - case - when sse_description ->> 'Status' = 'ENABLED' then title || ' encryption at rest enabled.' - else title || ' encryption at rest not enabled.' - end as reason - from - aws_dax_cluster; - PrimaryTable: aws_dax_cluster ListOfTables: - aws_dax_cluster Parameters: [] + PrimaryTable: aws_dax_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN sse_description ->> 'Status' = 'ENABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sse_description ->> 'Status' = 'ENABLED' THEN title || ' encryption at rest enabled.' + ELSE title || ' encryption at rest not enabled.' + END AS reason + FROM + aws_dax_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 DynamoDB Accelerator (DAX) clusters should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_dynamodb_6.yaml b/compliance/controls/aws/aws_foundational_security_dynamodb_6.yaml old mode 100755 new mode 100644 index 827fdde9f..6b2bf3705 --- a/compliance/controls/aws/aws_foundational_security_dynamodb_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_dynamodb_6.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an Amazon DynamoDB table has deletion protection enabled. The control fails if a DynamoDB table doesn't have deletion protection enabled. ID: aws_foundational_security_dynamodb_6 -Title: "6 DynamoDB tables should have deletion protection enabled" -Description: "This control checks whether an Amazon DynamoDB table has deletion protection enabled. The control fails if a DynamoDB table doesn't have deletion protection enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when deletion_protection_enabled then 'ok' - else 'alarm' - end as status, - case - when deletion_protection_enabled then title || ' deletion protection enabled.' - else title || ' deletion protection disabled.' - end as reason - from - aws_dynamodb_table; - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN deletion_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN deletion_protection_enabled THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection disabled.' + END AS reason + FROM + aws_dynamodb_table; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 DynamoDB tables should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_1.yaml b/compliance/controls/aws/aws_foundational_security_ec2_1.yaml old mode 100755 new mode 100644 index 1887669c9..49a4ba7a3 --- a/compliance/controls/aws/aws_foundational_security_ec2_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_1.yaml @@ -1,14 +1,28 @@ +Description: Amazon EBS snapshots should not be public, determined by the ability to be restorable by anyone. EBS snapshots are used to back up the data on your EBS volumes to Amazon S3 at a specific point in time. You can use the snapshots to restore previous states of EBS volumes. It is rarely acceptable to share a snapshot with the public. Typically the decision to share a snapshot publicly was made in error or without a complete understanding of the implications. This check helps ensure that all such sharing was fully planned and intentional. ID: aws_foundational_security_ec2_1 -Title: "1 Amazon EBS snapshots should not be public, determined by the ability to be restorable by anyone" -Description: "Amazon EBS snapshots should not be public, determined by the ability to be restorable by anyone. EBS snapshots are used to back up the data on your EBS volumes to Amazon S3 at a specific point in time. You can use the snapshots to restore previous states of EBS volumes. It is rarely acceptable to share a snapshot with the public. Typically the decision to share a snapshot publicly was made in error or without a complete understanding of the implications. This check helps ensure that all such sharing was fully planned and intentional." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':snapshot/' || snapshot_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when create_volume_permissions @> '[{\"Group\": \"all\", \"UserId\": null}]' then 'alarm'\n else 'ok'\n end as status,\n case\n when create_volume_permissions @> '[{\"Group\": \"all\", \"UserId\": null}]' then title || ' is publicly restorable.'\n else title || ' is not publicly restorable.'\n end as reason\n \n \nfrom\n aws_ebs_snapshot;\n" - PrimaryTable: aws_ebs_snapshot ListOfTables: - aws_ebs_snapshot Parameters: [] + PrimaryTable: aws_ebs_snapshot + QueryToExecute: | + SELECT + 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':snapshot/' || snapshot_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_volume_permissions @> '[{"Group": "all", "UserId": null}]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN create_volume_permissions @> '[{"Group": "all", "UserId": null}]' THEN title || ' is publicly restorable.' + ELSE title || ' is not publicly restorable.' + END AS reason + FROM + aws_ebs_snapshot; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Amazon EBS snapshots should not be public, determined by the ability to be restorable by anyone \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_15.yaml b/compliance/controls/aws/aws_foundational_security_ec2_15.yaml old mode 100755 new mode 100644 index 4d9bee01d..952b9ba6c --- a/compliance/controls/aws/aws_foundational_security_ec2_15.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_15.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether the assignment of public IPs in Amazon Virtual Private Cloud (Amazon VPC) subnets have MapPublicIpOnLaunch set to FALSE. The control passes if the flag is set to FALSE. ID: aws_foundational_security_ec2_15 -Title: "15 EC2 subnets should not automatically assign public IP addresses" -Description: "This control checks whether the assignment of public IPs in Amazon Virtual Private Cloud (Amazon VPC) subnets have MapPublicIpOnLaunch set to FALSE. The control passes if the flag is set to FALSE." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - subnet_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when map_public_ip_on_launch = 'false' then 'ok' - else 'alarm' - end as status, - case - when map_public_ip_on_launch = 'false' then title || ' auto assign public IP disabled.' - else title || ' auto assign public IP enabled.' - end as reason - from - aws_vpc_subnet; - PrimaryTable: aws_vpc_subnet ListOfTables: - aws_vpc_subnet Parameters: [] + PrimaryTable: aws_vpc_subnet + QueryToExecute: | + SELECT + subnet_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN map_public_ip_on_launch = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN map_public_ip_on_launch = 'false' THEN title || ' auto assign public IP disabled.' + ELSE title || ' auto assign public IP enabled.' + END AS reason + FROM + aws_vpc_subnet; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 15 EC2 subnets should not automatically assign public IP addresses \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_16.yaml b/compliance/controls/aws/aws_foundational_security_ec2_16.yaml old mode 100755 new mode 100644 index 68c1f8222..5fca165b8 --- a/compliance/controls/aws/aws_foundational_security_ec2_16.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_16.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether there are any unused network access control lists (ACLs). The control checks the item configuration of the resource AWS::EC2::NetworkAcl and determines the relationships of the network ACL. ID: aws_foundational_security_ec2_16 -Title: "16 Unused network access control lists should be removed" -Description: "This control checks whether there are any unused network access control lists (ACLs). The control checks the item configuration of the resource AWS::EC2::NetworkAcl and determines the relationships of the network ACL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n network_acl_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(associations) >= 1 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(associations) >= 1 then title || ' associated with subnet.'\n else title || ' not associated with subnet.'\n end reason\n \n \nfrom\n aws_vpc_network_acl;" - PrimaryTable: aws_vpc_network_acl ListOfTables: - aws_vpc_network_acl Parameters: [] + PrimaryTable: aws_vpc_network_acl + QueryToExecute: | + SELECT + network_acl_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(associations) >= 1 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(associations) >= 1 THEN + title || ' associated with subnet.' + ELSE + title || ' not associated with subnet.' + END AS reason + FROM + aws_vpc_network_acl; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 16 Unused network access control lists should be removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_17.yaml b/compliance/controls/aws/aws_foundational_security_ec2_17.yaml old mode 100755 new mode 100644 index 1e097f1d7..de3980061 --- a/compliance/controls/aws/aws_foundational_security_ec2_17.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_17.yaml @@ -1,14 +1,25 @@ +Description: This control checks whether an EC2 instance uses multiple Elastic Network Interfaces (ENIs) or Elastic Fabric Adapters (EFAs). This control passes if a single network adapter is used. The control includes an optional parameter list to identify the allowed ENIs. ID: aws_foundational_security_ec2_17 -Title: "17 EC2 instances should not use multiple ENIs" -Description: "This control checks whether an EC2 instance uses multiple Elastic Network Interfaces (ENIs) or Elastic Fabric Adapters (EFAs). This control passes if a single network adapter is used. The control includes an optional parameter list to identify the allowed ENIs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(network_interfaces) = 1 then 'ok'\n else 'alarm'\n end status,\n title || ' has ' || jsonb_array_length(network_interfaces) || ' ENI(s) attached.'\n as reason\n \n \nfrom\n aws_ec2_instance;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(network_interfaces) = 1 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' has ' || jsonb_array_length(network_interfaces) || ' ENI(s) attached.' AS reason + FROM + aws_ec2_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 17 EC2 instances should not use multiple ENIs \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_18.yaml b/compliance/controls/aws/aws_foundational_security_ec2_18.yaml old mode 100755 new mode 100644 index a6d8face1..8851aec3b --- a/compliance/controls/aws/aws_foundational_security_ec2_18.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_18.yaml @@ -1,43 +1,43 @@ +Description: This control checks whether the security groups that are in use allow unrestricted incoming traffic. Optionally the rule checks whether the port numbers are listed in the authorizedTcpPorts parameter. The default values for authorizedTcpPorts are 80 and 443. ID: aws_foundational_security_ec2_18 -Title: "18 Security groups should only allow unrestricted incoming traffic for authorized ports" -Description: "This control checks whether the security groups that are in use allow unrestricted incoming traffic. Optionally the rule checks whether the port numbers are listed in the authorizedTcpPorts parameter. The default values for authorizedTcpPorts are 80 and 443." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ingress_unauthorized_ports as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_unauthorized_ports AS ( + SELECT group_id, - count(*) - from + COUNT(*) + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and cidr_ipv4 = '0.0.0.0/0' - and (from_port is null or from_port not in (80,443)) - group by + AND cidr_ipv4 = '0.0.0.0/0' + AND (from_port IS NULL OR from_port NOT IN (80, 443)) + GROUP BY group_id ) - select - sg.arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when ingress_unauthorized_ports.count > 0 then 'alarm' - else 'ok' - end as status, - case - when ingress_unauthorized_ports.count > 0 then sg.title || ' having unrestricted incoming traffic other than default ports from 0.0.0.0/0 ' - else sg.title || ' allows unrestricted incoming traffic for authorized default ports (80,443).' - end as reason - from - aws_vpc_security_group as sg - left join ingress_unauthorized_ports on ingress_unauthorized_ports.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + sg.arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN ingress_unauthorized_ports.count > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ingress_unauthorized_ports.count > 0 THEN sg.title || ' having unrestricted incoming traffic other than default ports from 0.0.0.0/0 ' + ELSE sg.title || ' allows unrestricted incoming traffic for authorized default ports (80, 443).' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_unauthorized_ports ON ingress_unauthorized_ports.group_id = sg.group_id; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 18 Security groups should only allow unrestricted incoming traffic for authorized ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_19.yaml b/compliance/controls/aws/aws_foundational_security_ec2_19.yaml old mode 100755 new mode 100644 index 57a0c22b1..a46f3149d --- a/compliance/controls/aws/aws_foundational_security_ec2_19.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_19.yaml @@ -1,123 +1,64 @@ +Description: This control checks whether unrestricted incoming traffic for the security groups is accessible to the specified ports that have the highest risk. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 for those ports. ID: aws_foundational_security_ec2_19 -Title: "19 Security groups should not allow unrestricted access to ports with high risk" -Description: "This control checks whether unrestricted incoming traffic for the security groups is accessible to the specified ports that have the highest risk. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 for those ports." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ingress_ssh_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_ssh_rules AS ( + SELECT group_id, - count(*) as num_ssh_rules - from + COUNT(*) AS num_ssh_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and cidr_ipv4 = '0.0.0.0/0' - and ( - ( ip_protocol = '-1' - and from_port is null - ) - or ( - from_port >= 22 - and to_port <= 22 - ) - or ( - from_port >= 3389 - and to_port <= 3389 - ) - or ( - from_port >= 21 - and to_port <= 21 - ) - or ( - from_port >= 20 - and to_port <= 20 - ) - or ( - from_port >= 3306 - and to_port <= 3306 - ) - or ( - from_port >= 4333 - and to_port <= 4333 - ) - or ( - from_port >= 23 - and to_port <= 23 - ) - or ( - from_port >= 25 - and to_port <= 25 - ) - or ( - from_port >= 445 - and to_port <= 445 - ) - or ( - from_port >= 110 - and to_port <= 110 - ) - or ( - from_port >= 135 - and to_port <= 135 - ) - or ( - from_port >= 143 - and to_port <= 143 - ) - or ( - from_port >= 1433 - and to_port <= 3389 - ) - or ( - from_port >= 3389 - and to_port <= 1434 - ) - or ( - from_port >= 5432 - and to_port <= 5432 - ) - or ( - from_port >= 5500 - and to_port <= 5500 - ) - or ( - from_port >= 5601 - and to_port <= 5601 - ) - or ( - from_port >= 9200 - and to_port <= 9300 - ) - or ( - from_port >= 8080 - and to_port <= 8080 - ) + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR (from_port >= 22 AND to_port <= 22) + OR (from_port >= 3389 AND to_port <= 3389) + OR (from_port >= 21 AND to_port <= 21) + OR (from_port >= 20 AND to_port <= 20) + OR (from_port >= 3306 AND to_port <= 3306) + OR (from_port >= 4333 AND to_port <= 4333) + OR (from_port >= 23 AND to_port <= 23) + OR (from_port >= 25 AND to_port <= 25) + OR (from_port >= 445 AND to_port <= 445) + OR (from_port >= 110 AND to_port <= 110) + OR (from_port >= 135 AND to_port <= 135) + OR (from_port >= 143 AND to_port <= 143) + OR (from_port >= 1433 AND to_port <= 3389) + OR (from_port >= 3389 AND to_port <= 1434) + OR (from_port >= 5432 AND to_port <= 5432) + OR (from_port >= 5500 AND to_port <= 5500) + OR (from_port >= 5601 AND to_port <= 5601) + OR (from_port >= 9200 AND to_port <= 9300) + OR (from_port >= 8080 AND to_port <= 8080) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when ingress_ssh_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when ingress_ssh_rules.group_id is null then sg.group_id || ' ingress restricted for common ports from 0.0.0.0/0..' - else sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for common ports from 0.0.0.0/0.' - end as reason - from - aws_vpc_security_group as sg - left join ingress_ssh_rules on ingress_ssh_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN sg.group_id || ' ingress restricted for common ports from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for common ports from 0.0.0.0/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_ssh_rules ON ingress_ssh_rules.group_id = sg.group_id; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 19 Security groups should not allow unrestricted access to ports with high risk \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_2.yaml b/compliance/controls/aws/aws_foundational_security_ec2_2.yaml old mode 100755 new mode 100644 index 7161f1760..fc7a90fde --- a/compliance/controls/aws/aws_foundational_security_ec2_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_2.yaml @@ -1,35 +1,35 @@ +Description: This control checks that the default security group of a VPC does not allow inbound or outbound traffic. The rules for the default security group allow all outbound and inbound traffic from network interfaces (and their associated instances) that are assigned to the same security group. ID: aws_foundational_security_ec2_2 -Title: "2 VPC default security groups should not allow inbound or outbound traffic" -Description: "This control checks that the default security group of a VPC does not allow inbound or outbound traffic. The rules for the default security group allow all outbound and inbound traffic from network interfaces (and their associated instances) that are assigned to the same security group." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) = 0 then 'ok' - else 'alarm' - end status, - case - when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) > 0 - then 'Default security group ' || group_id || ' has inbound and outbound rules.' - when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) = 0 - then 'Default security group ' || group_id || ' has inbound rules.' - when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) > 0 - then 'Default security group ' || group_id || ' has outbound rules.' - else 'Default security group ' || group_id || ' has no inbound or outbound rules.' - end reason - from - aws_vpc_security_group - where - group_name = 'default'; - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has inbound and outbound rules.' + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) = 0 + THEN 'Default security group ' || group_id || ' has inbound rules.' + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has outbound rules.' + ELSE 'Default security group ' || group_id || ' has no inbound or outbound rules.' + END AS reason + FROM + aws_vpc_security_group + WHERE + group_name = 'default'; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 VPC default security groups should not allow inbound or outbound traffic \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_20.yaml b/compliance/controls/aws/aws_foundational_security_ec2_20.yaml old mode 100755 new mode 100644 index 6f4c19283..8f8a7fa64 --- a/compliance/controls/aws/aws_foundational_security_ec2_20.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_20.yaml @@ -1,40 +1,45 @@ +Description: This control checks that both VPN tunnels provided by AWS Site-to-Site VPN are in UP status. The control fails if one or both tunnels are in DOWN status. ID: aws_foundational_security_ec2_20 -Title: "20 Both VPN tunnels for an AWS Site-to-Site VPN connection should be up" -Description: "This control checks that both VPN tunnels provided by AWS Site-to-Site VPN are in UP status. The control fails if one or both tunnels are in DOWN status." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with filter_data as ( - select - arn, - count(t ->> 'Status') - from - aws_vpc_vpn_connection, - jsonb_array_elements(vgw_telemetry) as t - where t ->> 'Status' = 'UP' - group by arn - ) - select - a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.count is null or b.count < 2 then 'alarm' - else 'ok' - end as status, - case - when b.count is null then a.title || ' has both tunnels offline.' - when b.count = 1 then a.title || ' has one tunnel offline.' - else a.title || ' has both tunnels online.' - end as reason - from - aws_vpc_vpn_connection as a - left join filter_data as b on a.arn = b.arn; - PrimaryTable: aws_vpc_vpn_connection ListOfTables: - aws_vpc_vpn_connection Parameters: [] + PrimaryTable: aws_vpc_vpn_connection + QueryToExecute: | + WITH filter_data AS ( + SELECT + arn, + COUNT(t ->> 'Status') + FROM + aws_vpc_vpn_connection, + jsonb_array_elements(vgw_telemetry) AS t + WHERE + t ->> 'Status' = 'UP' + GROUP BY + arn + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.count IS NULL OR b.count < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.count IS NULL THEN a.title || ' has both tunnels offline.' + WHEN b.count = 1 THEN a.title || ' has one tunnel offline.' + ELSE a.title || ' has both tunnels online.' + END AS reason + FROM + aws_vpc_vpn_connection AS a + LEFT JOIN + filter_data AS b + ON + a.arn = b.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 20 Both VPN tunnels for an AWS Site-to-Site VPN connection should be up \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_23.yaml b/compliance/controls/aws/aws_foundational_security_ec2_23.yaml old mode 100755 new mode 100644 index fe2c2aacd..cba79b2ca --- a/compliance/controls/aws/aws_foundational_security_ec2_23.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_23.yaml @@ -1,14 +1,28 @@ +Description: This control checks if EC2 Transit Gateways are automatically accepting shared VPC attachments. This control fails for a Transit Gateway that automatically accepts shared VPC attachment requests. ID: aws_foundational_security_ec2_23 -Title: "23 EC2 Transit Gateways should not automatically accept VPC attachment requests" -Description: "This control checks if EC2 Transit Gateways are automatically accepting shared VPC attachments. This control fails for a Transit Gateway that automatically accepts shared VPC attachment requests." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n transit_gateway_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when auto_accept_shared_attachments = 'enable' then 'alarm'\n else 'ok'\n end as status,\n case\n when auto_accept_shared_attachments = 'enable' then title || ' automatic shared account attachment enabled.'\n else title || ' automatic shared account attachment disabled.'\n end as reason\n \n \nfrom\n aws_ec2_transit_gateway;" - PrimaryTable: aws_ec2_transit_gateway ListOfTables: - aws_ec2_transit_gateway Parameters: [] + PrimaryTable: aws_ec2_transit_gateway + QueryToExecute: | + SELECT + transit_gateway_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_accept_shared_attachments = 'enable' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN auto_accept_shared_attachments = 'enable' THEN title || ' automatic shared account attachment enabled.' + ELSE title || ' automatic shared account attachment disabled.' + END AS reason + FROM + aws_ec2_transit_gateway; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 23 EC2 Transit Gateways should not automatically accept VPC attachment requests \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_24.yaml b/compliance/controls/aws/aws_foundational_security_ec2_24.yaml old mode 100755 new mode 100644 index 6d91bcb8c..4ea55c150 --- a/compliance/controls/aws/aws_foundational_security_ec2_24.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_24.yaml @@ -1,14 +1,25 @@ +Description: This control checks whether the virtualization type of an EC2 instance is paravirtual. The control fails if the virtualizationType of the EC2 instance is set to paravirtual. ID: aws_foundational_security_ec2_24 -Title: "24 Paravirtual EC2 instance types should not be used" -Description: "This control checks whether the virtualization type of an EC2 instance is paravirtual. The control fails if the virtualizationType of the EC2 instance is set to paravirtual." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when virtualization_type = 'paravirtual' then 'alarm'\n else 'ok'\n end as status,\n title || ' virtualization type is ' || virtualization_type || '.' as reason\n \n \nfrom\n aws_ec2_instance;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN virtualization_type = 'paravirtual' THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' virtualization type is ' || virtualization_type || '.' AS reason + FROM + aws_ec2_instance; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 24 Paravirtual EC2 instance types should not be used \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_3.yaml b/compliance/controls/aws/aws_foundational_security_ec2_3.yaml old mode 100755 new mode 100644 index f8993de78..e4d7a035f --- a/compliance/controls/aws/aws_foundational_security_ec2_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_3.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether the EBS volumes that are in an attached state are encrypted. To pass this check, EBS volumes must be in use and encrypted. If the EBS volume is not attached, then it is not subject to this check. ID: aws_foundational_security_ec2_3 -Title: "3 Attached EBS volumes should be encrypted at rest" -Description: "This control checks whether the EBS volumes that are in an attached state are encrypted. To pass this check, EBS volumes must be in use and encrypted. If the EBS volume is not attached, then it is not subject to this check." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when state != 'in-use' then 'skip'\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when state != 'in-use' then volume_id || ' not attached.'\n when encrypted then volume_id || ' encrypted.'\n else volume_id || ' not encrypted.'\n end as reason\n \n \nfrom\n aws_ebs_volume;" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN state != 'in-use' THEN 'skip' + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN state != 'in-use' THEN volume_id || ' not attached.' + WHEN encrypted THEN volume_id || ' encrypted.' + ELSE volume_id || ' not encrypted.' + END AS reason + FROM + aws_ebs_volume; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Attached EBS volumes should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_4.yaml b/compliance/controls/aws/aws_foundational_security_ec2_4.yaml old mode 100755 new mode 100644 index bdd98acc5..5375907ef --- a/compliance/controls/aws/aws_foundational_security_ec2_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_4.yaml @@ -1,29 +1,29 @@ +Description: This control checks whether any EC2 instances have been stopped for more than the allowed number of days. An EC2 instance fails this check if it is stopped for longer than the maximum allowed time period, which by default is 30 days. ID: aws_foundational_security_ec2_4 -Title: "4 Stopped EC2 instances should be removed after a specified time period" -Description: "This control checks whether any EC2 instances have been stopped for more than the allowed number of days. An EC2 instance fails this check if it is stopped for longer than the maximum allowed time period, which by default is 30 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when instance_state not in ('stopped', 'stopping') then 'skip' - when state_transition_time <= (current_date - interval '30' day) then 'alarm' - else 'ok' - end as status, - case - when instance_state not in ('stopped', 'stopping') then title || ' is in ' || instance_state || ' state.' - else title || ' stopped since ' || to_char(state_transition_time , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - state_transition_time) || ' days).' - end as reason - from - aws_ec2_instance; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN instance_state NOT IN ('stopped', 'stopping') THEN 'skip' + WHEN state_transition_time <= (CURRENT_DATE - INTERVAL '30' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN instance_state NOT IN ('stopped', 'stopping') THEN title || ' is in ' || instance_state || ' state.' + ELSE title || ' stopped since ' || TO_CHAR(state_transition_time , 'DD-Mon-YYYY') || ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - state_transition_time) || ' days).' + END AS reason + FROM + aws_ec2_instance; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 Stopped EC2 instances should be removed after a specified time period \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_51.yaml b/compliance/controls/aws/aws_foundational_security_ec2_51.yaml old mode 100755 new mode 100644 index f9be05827..a64659ff9 --- a/compliance/controls/aws/aws_foundational_security_ec2_51.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_51.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an AWS Client VPN endpoint has client connection logging enabled. The control fails if the endpoint doesn't have client connection logging enabled. ID: aws_foundational_security_ec2_51 -Title: "51 EC2 Client VPN endpoints should have client connection logging enabled" -Description: "This control checks whether an AWS Client VPN endpoint has client connection logging enabled. The control fails if the endpoint doesn't have client connection logging enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n client_vpn_endpoint_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when (connection_log_options ->> 'Enabled')::bool then 'ok'\n else 'alarm'\n end as status,\n case\n when (connection_log_options ->> 'Enabled')::bool then title || ' client connection logging enabled.'\n else title || ' client connection logging disabled.'\n end as reason\n \n \nfrom\n aws_ec2_client_vpn_endpoint;" - PrimaryTable: aws_ec2_client_vpn_endpoint ListOfTables: - aws_ec2_client_vpn_endpoint Parameters: [] + PrimaryTable: aws_ec2_client_vpn_endpoint + QueryToExecute: | + SELECT + client_vpn_endpoint_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (connection_log_options ->> 'Enabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (connection_log_options ->> 'Enabled')::bool THEN title || ' client connection logging enabled.' + ELSE title || ' client connection logging disabled.' + END AS reason + FROM + aws_ec2_client_vpn_endpoint; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 51 EC2 Client VPN endpoints should have client connection logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_7.yaml b/compliance/controls/aws/aws_foundational_security_ec2_7.yaml old mode 100755 new mode 100644 index 9a2bf7832..4123bb104 --- a/compliance/controls/aws/aws_foundational_security_ec2_7.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_7.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether account-level encryption is enabled by default for Amazon Elastic Block Store (Amazon EBS). The control fails if the account level encryption is not enabled. ID: aws_foundational_security_ec2_7 -Title: "7 EBS default encryption should be enabled" -Description: "This control checks whether account-level encryption is enabled by default for Amazon Elastic Block Store(Amazon EBS). The control fails if the account level encryption is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || '::' || region || ':' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when not default_ebs_encryption_enabled then 'alarm'\n else 'ok'\n end as status,\n case\n when not default_ebs_encryption_enabled then region || ' default EBS encryption disabled.'\n else region || ' default EBS encryption enabled.'\n end as reason\n \nfrom\n aws_ec2_regional_settings;" - PrimaryTable: aws_ec2_regional_settings ListOfTables: - aws_ec2_regional_settings Parameters: [] + PrimaryTable: aws_ec2_regional_settings + QueryToExecute: | + SELECT + 'arn:' || partition || '::' || region || ':' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT default_ebs_encryption_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT default_ebs_encryption_enabled THEN region || ' default EBS encryption disabled.' + ELSE region || ' default EBS encryption enabled.' + END AS reason + FROM + aws_ec2_regional_settings; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 EBS default encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_8.yaml b/compliance/controls/aws/aws_foundational_security_ec2_8.yaml old mode 100755 new mode 100644 index cce06b9aa..323dc9696 --- a/compliance/controls/aws/aws_foundational_security_ec2_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_8.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether your EC2 instance metadata version is configured with Instance Metadata Service Version 2 (IMDSv2). The control passes if HttpTokens is set to required for IMDSv2. The control fails if HttpTokens is set to optional. ID: aws_foundational_security_ec2_8 -Title: "8 EC2 instances should use IMDSv2" -Description: "This control checks whether your EC2 instance metadata version is configured with Instance Metadata Service Version 2 (IMDSv2). The control passes if HttpTokens is set to required for IMDSv2. The control fails if HttpTokens is set to optional." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when metadata_options ->> 'HttpTokens' = 'optional' then 'alarm' - else 'ok' - end as status, - case - when metadata_options ->> 'HttpTokens' = 'optional' then title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' - else title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' - end as reason - from - aws_ec2_instance; - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' + ELSE title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' + END AS reason + FROM + aws_ec2_instance; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 EC2 instances should use IMDSv2 \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ec2_9.yaml b/compliance/controls/aws/aws_foundational_security_ec2_9.yaml old mode 100755 new mode 100644 index 263d64be5..969e7e1ca --- a/compliance/controls/aws/aws_foundational_security_ec2_9.yaml +++ b/compliance/controls/aws/aws_foundational_security_ec2_9.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether EC2 instances have a public IP address. The control fails if the publicIp field is present in the EC2 instance configuration item. This control applies to IPv4 addresses only. ID: aws_foundational_security_ec2_9 -Title: "9 EC2 instances should not have a public IP address" -Description: "This control checks whether EC2 instances have a public IP address. The control fails if the publicIp field is present in the EC2 instance configuration item. This control applies to IPv4 addresses only." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when public_ip_address is null then 'ok'\n else 'alarm'\n end as status,\n case\n when public_ip_address is null then instance_id || ' not publicly accessible.'\n else instance_id || ' publicly accessible.'\n end as reason\n \n \nfrom\n aws_ec2_instance;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN public_ip_address IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN public_ip_address IS NULL THEN instance_id || ' not publicly accessible.' + ELSE instance_id || ' publicly accessible.' + END AS reason + FROM + aws_ec2_instance; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 EC2 instances should not have a public IP address \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecr_1.yaml b/compliance/controls/aws/aws_foundational_security_ecr_1.yaml old mode 100755 new mode 100644 index c0019f597..bbd3f3543 --- a/compliance/controls/aws/aws_foundational_security_ecr_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecr_1.yaml @@ -1,41 +1,43 @@ +Description: This control checks whether a private ECR repository has image scanning configured. This control fails if a private ECR repository doesn't have image scanning configured. ID: aws_foundational_security_ecr_1 -Title: "1 ECR private repositories should have image scanning configured" -Description: "This control checks whether a private ECR repository has image scanning configured. This control fails if a private ECR repository doesn't have image scanning configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with check_enhanced_scanning as ( - select + ListOfTables: + - aws_ecr_registry_scanning_configuration + - aws_ecr_repository + Parameters: [] + PrimaryTable: aws_ecr_repository + QueryToExecute: | + WITH check_enhanced_scanning AS ( + SELECT registry_id, region - from + FROM aws_ecr_registry_scanning_configuration, - jsonb_array_elements(scanning_configuration -> 'Rules') as r - where + jsonb_array_elements(scanning_configuration -> 'Rules') AS r + WHERE r ->> 'ScanFrequency' = 'CONTINUOUS_SCAN' - or r ->> 'ScanFrequency' = 'SCAN_ON_PUSH' + OR r ->> 'ScanFrequency' = 'SCAN_ON_PUSH' ) - select - arn as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - when image_scanning_configuration ->> 'ScanOnPush' = 'true' or s.registry_id is not null then 'ok' - else 'alarm' - end as status, - case - when image_scanning_configuration ->> 'ScanOnPush' = 'true' or s.registry_id is not null then title || ' scan on push enabled.' - else title || ' scan on push disabled.' - end as reason - from - aws_ecr_repository as r - left join check_enhanced_scanning as s on s.registry_id = r.account_id and s.region = r.region; - PrimaryTable: aws_ecr_repository - ListOfTables: - - aws_ecr_registry_scanning_configuration - - aws_ecr_repository - Parameters: [] + SELECT + arn AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN image_scanning_configuration ->> 'ScanOnPush' = 'true' OR s.registry_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN image_scanning_configuration ->> 'ScanOnPush' = 'true' OR s.registry_id IS NOT NULL THEN title || ' scan on push enabled.' + ELSE title || ' scan on push disabled.' + END AS reason + FROM + aws_ecr_repository AS r + LEFT JOIN check_enhanced_scanning AS s + ON s.registry_id = r.account_id + AND s.region = r.region; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 ECR private repositories should have image scanning configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecr_2.yaml b/compliance/controls/aws/aws_foundational_security_ecr_2.yaml old mode 100755 new mode 100644 index 5c49c4398..bf0896c6e --- a/compliance/controls/aws/aws_foundational_security_ecr_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecr_2.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether a private ECR repository has tag immutability enabled. This control fails if a private ECR repository has tag immutability disabled. This rule passes if tag immutability is enabled and has the value IMMUTABLE. ID: aws_foundational_security_ecr_2 -Title: "2 ECR private repositories should have tag immutability configured" -Description: "This control checks whether a private ECR repository has tag immutability enabled. This control fails if a private ECR repository has tag immutability disabled. This rule passes if tag immutability is enabled and has the value IMMUTABLE." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when image_tag_mutability = 'IMMUTABLE' then 'ok' - else 'alarm' - end as status, - case - when image_tag_mutability = 'IMMUTABLE' then title || ' tag immutability enabled.' - else title || ' tag immutability disabled.' - end as reason - from - aws_ecr_repository; - PrimaryTable: aws_ecr_repository ListOfTables: - aws_ecr_repository Parameters: [] + PrimaryTable: aws_ecr_repository + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN image_tag_mutability = 'IMMUTABLE' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN image_tag_mutability = 'IMMUTABLE' THEN title || ' tag immutability enabled.' + ELSE title || ' tag immutability disabled.' + END AS reason + FROM + aws_ecr_repository; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 ECR private repositories should have tag immutability configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecr_3.yaml b/compliance/controls/aws/aws_foundational_security_ecr_3.yaml old mode 100755 new mode 100644 index e324d1d8e..d61e9771d --- a/compliance/controls/aws/aws_foundational_security_ecr_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecr_3.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an Amazon ECR repository has at least one lifecycle policy configured. This control fails if an ECR repository does not have any lifecycle policies configured. ID: aws_foundational_security_ecr_3 -Title: "3 ECR repositories should have at least one lifecycle policy configured" -Description: "This control checks whether an Amazon ECR repository has at least one lifecycle policy configured. This control fails if an ECR repository does not have any lifecycle policies configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when lifecycle_policy -> 'rules' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when lifecycle_policy -> 'rules' is not null then title || ' lifecycle policy configured.'\n else title || ' lifecycle policy not configured.'\n end as reason\n \n \nfrom\n aws_ecr_repository;" - PrimaryTable: aws_ecr_repository ListOfTables: - aws_ecr_repository Parameters: [] + PrimaryTable: aws_ecr_repository + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN lifecycle_policy -> 'rules' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN lifecycle_policy -> 'rules' IS NOT NULL THEN title || ' lifecycle policy configured.' + ELSE title || ' lifecycle policy not configured.' + END AS reason + FROM + aws_ecr_repository; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 ECR repositories should have at least one lifecycle policy configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecs_1.yaml b/compliance/controls/aws/aws_foundational_security_ecs_1.yaml old mode 100755 new mode 100644 index ae05c8428..61834a5dc --- a/compliance/controls/aws/aws_foundational_security_ecs_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecs_1.yaml @@ -1,48 +1,48 @@ +Description: This control checks whether an Amazon ECS task definition that has host networking mode also has 'privileged' or 'user' container definitions. The control fails for task definitions that have host network mode and container definitions where privileged ID: aws_foundational_security_ecs_1 -Title: "1 Amazon ECS task definitions should have secure networking modes and user definitions" -Description: "This control checks whether an Amazon ECS task definition that has host networking mode also has 'privileged' or 'user' container definitions. The control fails for task definitions that have host network mode and container definitions where privileged" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with host_network_task_definition as ( - select - distinct task_definition_arn as arn - from - aws_ecs_task_definition, - jsonb_array_elements(container_definitions) as c - where - network_mode = 'host' - and - (c ->> 'Privileged' is not null - and c ->> 'Privileged' <> 'false' - ) - and - ( c ->> 'User' is not null - and c ->> 'User' <> 'root' - ) - ) - select - a.task_definition_arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.network_mode is null or a.network_mode <> 'host' then 'skip' - when b.arn is not null then 'ok' - else 'alarm' - end as status, - case - when a.network_mode is null or a.network_mode <> 'host' then a.title || ' not host network mode.' - when b.arn is not null then a.title || ' have secure host network mode.' - else a.title || ' not have secure host network mode.' - end as reason - from - aws_ecs_task_definition as a - left join host_network_task_definition as b on a.task_definition_arn = b.arn; - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH host_network_task_definition AS ( + SELECT + DISTINCT task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c + WHERE + network_mode = 'host' + AND ( + c ->> 'Privileged' IS NOT NULL + AND c ->> 'Privileged' <> 'false' + ) + AND ( + c ->> 'User' IS NOT NULL + AND c ->> 'User' <> 'root' + ) + ) + SELECT + a.task_definition_arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.network_mode IS NULL OR a.network_mode <> 'host' THEN 'skip' + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.network_mode IS NULL OR a.network_mode <> 'host' THEN a.title || ' not host network mode.' + WHEN b.arn IS NOT NULL THEN a.title || ' have secure host network mode.' + ELSE a.title || ' not have secure host network mode.' + END AS reason + FROM + aws_ecs_task_definition AS a + LEFT JOIN host_network_task_definition AS b ON a.task_definition_arn = b.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Amazon ECS task definitions should have secure networking modes and user definitions \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecs_10.yaml b/compliance/controls/aws/aws_foundational_security_ecs_10.yaml old mode 100755 new mode 100644 index 2cbdfe4dc..8b71b615a --- a/compliance/controls/aws/aws_foundational_security_ecs_10.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecs_10.yaml @@ -1,30 +1,30 @@ +Description: This control checks if Amazon ECS Fargate services are running the latest Fargate platform version. This control fails if the platform version is not the latest. ID: aws_foundational_security_ecs_10 -Title: "10 Fargate services should run on the latest Fargate platform version" -Description: "This control checks if Amazon ECS Fargate services are running the latest Fargate platform version. This control fails if the platform version is not the latest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when launch_type <> 'FARGATE' then 'skip' - when platform_version = 'LATEST' then 'ok' - else 'alarm' - end as status, - case - when launch_type <> 'FARGATE' then title || ' is ' || launch_type || ' service.' - when platform_version = 'LATEST' then title || ' running on the latest fargate platform version.' - else title || ' not running on the latest fargate platform version.' - end as reason - from - aws_ecs_service; - PrimaryTable: aws_ecs_service ListOfTables: - aws_ecs_service Parameters: [] + PrimaryTable: aws_ecs_service + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN launch_type <> 'FARGATE' THEN 'skip' + WHEN platform_version = 'LATEST' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN launch_type <> 'FARGATE' THEN title || ' is ' || launch_type || ' service.' + WHEN platform_version = 'LATEST' THEN title || ' running on the latest fargate platform version.' + ELSE title || ' not running on the latest fargate platform version.' + END AS reason + FROM + aws_ecs_service; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 10 Fargate services should run on the latest Fargate platform version \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecs_12.yaml b/compliance/controls/aws/aws_foundational_security_ecs_12.yaml old mode 100755 new mode 100644 index aad7b1a19..3f55784cf --- a/compliance/controls/aws/aws_foundational_security_ecs_12.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecs_12.yaml @@ -1,29 +1,29 @@ +Description: This control checks if ECS clusters use Container Insights. This control fails if Container Insights are not set up for a cluster. ID: aws_foundational_security_ecs_12 -Title: "12 ECS clusters should have Container Insights enabled" -Description: "This control checks if ECS clusters use Container Insights. This control fails if Container Insights are not set up for a cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - cluster_arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when s ->> 'Name' = 'containerInsights' and s ->> 'Value' = 'enabled' then 'ok' - else 'alarm' - end as status, - case - when s ->> 'Name' = 'containerInsights' and s ->> 'Value' = 'enabled' then title || ' Container Insights enabled.' - else title || ' Container Insights disabled.' - end as reason - from - aws_ecs_cluster as c, - jsonb_array_elements(settings) as s; - PrimaryTable: aws_ecs_cluster ListOfTables: - aws_ecs_cluster Parameters: [] + PrimaryTable: aws_ecs_cluster + QueryToExecute: | + SELECT + cluster_arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN s ->> 'Name' = 'containerInsights' AND s ->> 'Value' = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s ->> 'Name' = 'containerInsights' AND s ->> 'Value' = 'enabled' THEN title || ' Container Insights enabled.' + ELSE title || ' Container Insights disabled.' + END AS reason + FROM + aws_ecs_cluster AS c, + jsonb_array_elements(settings) AS s; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 12 ECS clusters should have Container Insights enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecs_2.yaml b/compliance/controls/aws/aws_foundational_security_ecs_2.yaml old mode 100755 new mode 100644 index d257688ed..497a5a044 --- a/compliance/controls/aws/aws_foundational_security_ecs_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecs_2.yaml @@ -1,42 +1,44 @@ +Description: This control checks whether Amazon ECS services are configured to automatically assign public IP addresses. This control fails if AssignPublicIP is ENABLED. This control passes if AssignPublicIP is DISABLED. ID: aws_foundational_security_ecs_2 -Title: "2 Amazon ECS services should not have public IP addresses assigned to them automatically" -Description: "This control checks whether Amazon ECS services are configured to automatically assign public IP addresses. This control fails if AssignPublicIP is ENABLED. This control passes if AssignPublicIP is DISABLED." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with service_awsvpc_mode_task_definition as ( - select - a.service_name as service_name, - b.task_definition_arn as task_definition - from - aws_ecs_service as a - left join aws_ecs_task_definition as b on a.task_definition = b.task_definition_arn - where - b.network_mode = 'awsvpc' - ) - select - a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.service_name is null then 'skip' - when network_configuration -> 'AwsvpcConfiguration' ->> 'AssignPublicIp' = 'DISABLED' then 'ok' - else 'alarm' - end as status, - case - when b.service_name is null then a.title || ' task definition not host network mode.' - when network_configuration -> 'AwsvpcConfiguration' ->> 'AssignPublicIp' = 'DISABLED' then a.title || ' not publicly accessible.' - else a.title || ' publicly accessible.' - end as reason - from - aws_ecs_service as a - left join service_awsvpc_mode_task_definition as b on a.service_name = b.service_name; - PrimaryTable: aws_ecs_service ListOfTables: - aws_ecs_service - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_service + QueryToExecute: | + WITH service_awsvpc_mode_task_definition AS ( + SELECT + a.service_name AS service_name, + b.task_definition_arn AS task_definition + FROM + aws_ecs_service AS a + LEFT JOIN aws_ecs_task_definition AS b + ON a.task_definition = b.task_definition_arn + WHERE + b.network_mode = 'awsvpc' + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.service_name IS NULL THEN 'skip' + WHEN network_configuration -> 'AwsvpcConfiguration' ->> 'AssignPublicIp' = 'DISABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.service_name IS NULL THEN a.title || ' task definition not host network mode.' + WHEN network_configuration -> 'AwsvpcConfiguration' ->> 'AssignPublicIp' = 'DISABLED' THEN a.title || ' not publicly accessible.' + ELSE a.title || ' publicly accessible.' + END AS reason + FROM + aws_ecs_service AS a + LEFT JOIN service_awsvpc_mode_task_definition AS b + ON a.service_name = b.service_name; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Amazon ECS services should not have public IP addresses assigned to them automatically \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecs_3.yaml b/compliance/controls/aws/aws_foundational_security_ecs_3.yaml old mode 100755 new mode 100644 index ccaa84cc7..447295933 --- a/compliance/controls/aws/aws_foundational_security_ecs_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecs_3.yaml @@ -1,28 +1,29 @@ +Description: This control checks if Amazon ECS task definitions are configured to share a host’s process namespace with its containers. + The control fails if the task definition shares the host's process namespace with the containers running on it. ID: aws_foundational_security_ecs_3 -Title: "3 ECS task definitions should not share the host's process namespace" -Description: "This control checks if Amazon ECS task definitions are configured to share a host’s process namespace with its containers. The control fails if the task definition shares the host's process namespace with the containers running on it." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - task_definition_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when pid_mode = 'host' then 'alarm' - else 'ok' - end as status, - case - when pid_mode = 'host' then title || ' shares the host process namespace.' - else title || ' does not share the host process namespace.' - end as reason - from - aws_ecs_task_definition; - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + SELECT + task_definition_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN pid_mode = 'host' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN pid_mode = 'host' THEN title || ' shares the host process namespace.' + ELSE title || ' does not share the host process namespace.' + END AS reason + FROM + aws_ecs_task_definition; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 ECS task definitions should not share the host's process namespace \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecs_4.yaml b/compliance/controls/aws/aws_foundational_security_ecs_4.yaml old mode 100755 new mode 100644 index d18b5ed09..520e7a693 --- a/compliance/controls/aws/aws_foundational_security_ecs_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecs_4.yaml @@ -1,38 +1,39 @@ +Description: This control checks if the privileged parameter in the container definition of Amazon ECS Task Definitions is set to true. The control fails if this parameter is equal to true. ID: aws_foundational_security_ecs_4 -Title: "4 ECS containers should run as non-privileged" -Description: "This control checks if the privileged parameter in the container definition of Amazon ECS Task Definitions is set to true. The control fails if this parameter is equal to true." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with privileged_container_definition as ( - select - distinct task_definition_arn as arn - from - aws_ecs_task_definition, - jsonb_array_elements(container_definitions) as c - where - c ->> 'Privileged' = 'true' - ) - select - d.task_definition_arn as resource, - d.og_account_id as og_account_id, - d.og_resource_id as og_resource_id, - case - when c.arn is null then 'ok' - else 'alarm' - end as status, - case - when c.arn is null then d.title || ' does not have elevated privileges.' - else d.title || ' has elevated privileges.' - end as reason - from - aws_ecs_task_definition as d - left join privileged_container_definition as c on d.task_definition_arn = c.arn; - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH privileged_container_definition AS ( + SELECT + DISTINCT task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c + WHERE + c ->> 'Privileged' = 'true' + ) + SELECT + d.task_definition_arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN c.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.arn IS NULL THEN d.title || ' does not have elevated privileges.' + ELSE d.title || ' has elevated privileges.' + END AS reason + FROM + aws_ecs_task_definition AS d + LEFT JOIN privileged_container_definition AS c + ON d.task_definition_arn = c.arn; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 ECS containers should run as non-privileged \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecs_5.yaml b/compliance/controls/aws/aws_foundational_security_ecs_5.yaml old mode 100755 new mode 100644 index c824631ad..da50505af --- a/compliance/controls/aws/aws_foundational_security_ecs_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecs_5.yaml @@ -1,38 +1,39 @@ +Description: This control checks if ECS containers are limited to read-only access to mounted root filesystems. This control fails if the ReadonlyRootFilesystem parameter in the container definition of ECS task definitions is set to false. ID: aws_foundational_security_ecs_5 -Title: "5 ECS containers should be limited to read-only access to root filesystems" -Description: "This control checks if ECS containers are limited to read-only access to mounted root filesystems. This control fails if the ReadonlyRootFilesystem parameter in the container definition of ECS task definitions is set to false." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with privileged_container_definition as ( - select - distinct task_definition_arn as arn - from - aws_ecs_task_definition, - jsonb_array_elements(container_definitions) as c - where - c ->> 'ReadonlyRootFilesystem' = 'true' - ) - select - d.task_definition_arn as resource, - d.og_account_id as og_account_id, - d.og_resource_id as og_resource_id, - case - when c.arn is not null then 'ok' - else 'alarm' - end as status, - case - when c.arn is not null then d.title || ' containers limited to read-only access to root filesystems.' - else d.title || ' containers not limited to read-only access to root filesystems.' - end as reason - from - aws_ecs_task_definition as d - left join privileged_container_definition as c on d.task_definition_arn = c.arn; - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH privileged_container_definition AS ( + SELECT + DISTINCT task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c + WHERE + c ->> 'ReadonlyRootFilesystem' = 'true' + ) + SELECT + d.task_definition_arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN c.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.arn IS NOT NULL THEN d.title || ' containers limited to read-only access to root filesystems.' + ELSE d.title || ' containers not limited to read-only access to root filesystems.' + END AS reason + FROM + aws_ecs_task_definition AS d + LEFT JOIN privileged_container_definition AS c + ON d.task_definition_arn = c.arn; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 ECS containers should be limited to read-only access to root filesystems \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecs_8.yaml b/compliance/controls/aws/aws_foundational_security_ecs_8.yaml old mode 100755 new mode 100644 index 4dd019c77..df6397fab --- a/compliance/controls/aws/aws_foundational_security_ecs_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecs_8.yaml @@ -1,45 +1,46 @@ +Description: This control checks if the key value of any variables in the environment parameter of container definitions includes AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. This control fails if a single environment variable in any container definition equals AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. This control does not cover environmental variables passed in from other locations such as Amazon S3. ID: aws_foundational_security_ecs_8 -Title: "8 Secrets should not be passed as container environment variables" -Description: "This control checks if the key value of any variables in the environment parameter of container definitions includes AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. This control fails if a single environment variable in any container definition equals AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or ECS_ENGINE_AUTH_DATA. This control does not cover environmental variables passed in from other locations such as Amazon S3." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with definitions_with_secret_environment_variable as ( - select - distinct task_definition_arn as arn - from - aws_ecs_task_definition, - jsonb_array_elements(container_definitions) as c, - jsonb_array_elements( c -> 'Environment') as e, - jsonb_array_elements( - case jsonb_typeof(c -> 'Secrets') - when 'array' then (c -> 'Secrets') - else null end - ) as s - where - e ->> 'Name' like any (array ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY','ECS_ENGINE_AUTH_DATA']) - or s ->> 'Name' like any (array ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY','ECS_ENGINE_AUTH_DATA']) - ) - select - d.task_definition_arn as resource, - d.og_account_id as og_account_id, - d.og_resource_id as og_resource_id, - case - when e.arn is null then 'ok' - else 'alarm' - end as status, - case - when e.arn is null then d.title || ' container environment variables does not have secrets.' - else d.title || ' container environment variables have secrets.' - end as reason - from - aws_ecs_task_definition as d - left join definitions_with_secret_environment_variable as e on d.task_definition_arn = e.arn; - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH definitions_with_secret_environment_variable AS ( + SELECT + DISTINCT task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c, + jsonb_array_elements(c -> 'Environment') AS e, + jsonb_array_elements( + CASE jsonb_typeof(c -> 'Secrets') + WHEN 'array' THEN (c -> 'Secrets') + ELSE NULL + END + ) AS s + WHERE + e ->> 'Name' LIKE ANY (ARRAY ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'ECS_ENGINE_AUTH_DATA']) + OR s ->> 'Name' LIKE ANY (ARRAY ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'ECS_ENGINE_AUTH_DATA']) + ) + SELECT + d.task_definition_arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN e.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN e.arn IS NULL THEN d.title || ' container environment variables does not have secrets.' + ELSE d.title || ' container environment variables have secrets.' + END AS reason + FROM + aws_ecs_task_definition AS d + LEFT JOIN definitions_with_secret_environment_variable AS e ON d.task_definition_arn = e.arn; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 Secrets should not be passed as container environment variables \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ecs_9.yaml b/compliance/controls/aws/aws_foundational_security_ecs_9.yaml old mode 100755 new mode 100644 index 58fff7215..a6a18a716 --- a/compliance/controls/aws/aws_foundational_security_ecs_9.yaml +++ b/compliance/controls/aws/aws_foundational_security_ecs_9.yaml @@ -1,14 +1,39 @@ +Description: This control checks if the latest active Amazon ECS task definition has a logging configuration specified. The control fails if the task definition doesn't have the logConfiguration property defined or if the value for logDriver is null in at least one container definition. ID: aws_foundational_security_ecs_9 -Title: "9 ECS task definitions should have a logging configuration" -Description: "This control checks if the latest active Amazon ECS task definition has a logging configuration specified. The control fails if the task definition doesn't have the logConfiguration property defined or if the value for logDriver is null in at least one container definition." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with task_definitions_logging_enabled as (\n select\n distinct task_definition_arn as arn\n from\n aws_ecs_task_definition,\n jsonb_array_elements(container_definitions) as c\n where\n c ->> 'LogConfiguration' is not null\n)\nselect\n a.task_definition_arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is not null then a.title || ' logging enabled.'\n else a.title || ' logging disabled.'\n end as reason\n \n \nfrom\n aws_ecs_task_definition as a\n left join task_definitions_logging_enabled as b on a.task_definition_arn = b.arn;" - PrimaryTable: aws_ecs_task_definition ListOfTables: - aws_ecs_task_definition Parameters: [] + PrimaryTable: aws_ecs_task_definition + QueryToExecute: | + WITH task_definitions_logging_enabled AS ( + SELECT + DISTINCT task_definition_arn AS arn + FROM + aws_ecs_task_definition, + jsonb_array_elements(container_definitions) AS c + WHERE + c ->> 'LogConfiguration' IS NOT NULL + ) + SELECT + a.task_definition_arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NOT NULL THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN b.arn IS NOT NULL THEN a.title || ' logging enabled.' + ELSE a.title || ' logging disabled.' + END AS reason + FROM + aws_ecs_task_definition AS a + LEFT JOIN task_definitions_logging_enabled AS b + ON a.task_definition_arn = b.arn; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 ECS task definitions should have a logging configuration \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_efs_1.yaml b/compliance/controls/aws/aws_foundational_security_efs_1.yaml old mode 100755 new mode 100644 index 9de028c7b..463333f77 --- a/compliance/controls/aws/aws_foundational_security_efs_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_efs_1.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether Amazon Elastic File System is configured to encrypt the file data using AWS KMS. ID: aws_foundational_security_efs_1 -Title: "1 Amazon EFS should be configured to encrypt file data at rest using AWS KMS" -Description: "This control checks whether Amazon Elastic File System is configured to encrypt the file data using AWS KMS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_efs_file_system;" - PrimaryTable: aws_efs_file_system ListOfTables: - aws_efs_file_system Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_efs_file_system; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Amazon EFS should be configured to encrypt file data at rest using AWS KMS \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_efs_2.yaml b/compliance/controls/aws/aws_foundational_security_efs_2.yaml old mode 100755 new mode 100644 index b9e99a265..eced28707 --- a/compliance/controls/aws/aws_foundational_security_efs_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_efs_2.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether Amazon Elastic File System (Amazon EFS) file systems are added to the backup plans in AWS Backup. The control fails if Amazon EFS file systems are not included in the backup plans. ID: aws_foundational_security_efs_2 -Title: "2 Amazon EFS volumes should be in backup plans" -Description: "This control checks whether Amazon Elastic File System (Amazon EFS) file systems are added to the backup plans in AWS Backup. The control fails if Amazon EFS file systems are not included in the backup plans." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when automatic_backups = 'enabled' then 'ok' - else 'alarm' - end as status, - case - when automatic_backups = 'enabled' then title || ' automatic backups enabled.' - else title || ' automatic backups not enabled.' - end as reason - from - aws_efs_file_system; - PrimaryTable: aws_efs_file_system ListOfTables: - aws_efs_file_system Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN automatic_backups = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN automatic_backups = 'enabled' THEN title || ' automatic backups enabled.' + ELSE title || ' automatic backups not enabled.' + END AS reason + FROM + aws_efs_file_system; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Amazon EFS volumes should be in backup plans \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_efs_3.yaml b/compliance/controls/aws/aws_foundational_security_efs_3.yaml old mode 100755 new mode 100644 index c86b202a7..8fe284f03 --- a/compliance/controls/aws/aws_foundational_security_efs_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_efs_3.yaml @@ -1,14 +1,28 @@ +Description: This control checks if Amazon EFS access points are configured to enforce a root directory. The control fails if the value of Path is set to / (the default root directory of the file system). ID: aws_foundational_security_efs_3 -Title: "3 EFS access points should enforce a root directory" -Description: "This control checks if Amazon EFS access points are configured to enforce a root directory. The control fails if the value of Path is set to / (the default root directory of the file system)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n access_point_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when root_directory ->> 'Path'= '/' then 'alarm'\n else 'ok'\n end as status,\n case\n when root_directory ->> 'Path'= '/' then title || ' not configured to enforce a root directory.'\n else title || ' configured to enforce a root directory.'\n end as reason\n \n \nfrom\n aws_efs_access_point;" - PrimaryTable: aws_efs_access_point ListOfTables: - aws_efs_access_point Parameters: [] + PrimaryTable: aws_efs_access_point + QueryToExecute: | + SELECT + access_point_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN root_directory ->> 'Path' = '/' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN root_directory ->> 'Path' = '/' THEN title || ' not configured to enforce a root directory.' + ELSE title || ' configured to enforce a root directory.' + END AS reason + FROM + aws_efs_access_point; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 EFS access points should enforce a root directory \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_efs_4.yaml b/compliance/controls/aws/aws_foundational_security_efs_4.yaml old mode 100755 new mode 100644 index a1fdf7d2a..9a1ce94d1 --- a/compliance/controls/aws/aws_foundational_security_efs_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_efs_4.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether Amazon EFS access points are configured to enforce a user identity. This control fails if a POSIX user identity is not defined while creating the EFS access point. ID: aws_foundational_security_efs_4 -Title: "4 EFS access points should enforce a user identity" -Description: "This control checks whether Amazon EFS access points are configured to enforce a user identity. This control fails if a POSIX user identity is not defined while creating the EFS access point." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n access_point_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when posix_user is null then 'alarm'\n else 'ok'\n end as status,\n case\n when posix_user is null then title || ' does not enforce a user identity.'\n else title || ' enforces a user identity.'\n end as reason\n \n \nfrom\n aws_efs_access_point;" - PrimaryTable: aws_efs_access_point ListOfTables: - aws_efs_access_point Parameters: [] + PrimaryTable: aws_efs_access_point + QueryToExecute: | + SELECT + access_point_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN posix_user IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN posix_user IS NULL THEN title || ' does not enforce a user identity.' + ELSE title || ' enforces a user identity.' + END AS reason + FROM + aws_efs_access_point; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 EFS access points should enforce a user identity \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_eks_1.yaml b/compliance/controls/aws/aws_foundational_security_eks_1.yaml old mode 100755 new mode 100644 index 02b55a9e2..440ce4219 --- a/compliance/controls/aws/aws_foundational_security_eks_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_eks_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an Amazon EKS cluster endpoint is publicly accessible. The control fails if an EKS cluster has an endpoint that is publicly accessible. ID: aws_foundational_security_eks_1 -Title: "1 EKS cluster endpoints should not be publicly accessible" -Description: "This control checks whether an Amazon EKS cluster endpoint is publicly accessible. The control fails if an EKS cluster has an endpoint that is publicly accessible." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when resources_vpc_config ->> 'EndpointPublicAccess' = 'true' then 'alarm' - else 'ok' - end as status, - case - when resources_vpc_config ->> 'EndpointPublicAccess' = 'true' then title || ' endpoint publicly accessible.' - else title || ' endpoint not publicly accessible.' - end as reason - from - aws_eks_cluster; - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN resources_vpc_config ->> 'EndpointPublicAccess' = 'true' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN resources_vpc_config ->> 'EndpointPublicAccess' = 'true' THEN title || ' endpoint publicly accessible.' + ELSE title || ' endpoint not publicly accessible.' + END AS reason + FROM + aws_eks_cluster; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 EKS cluster endpoints should not be publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_eks_2.yaml b/compliance/controls/aws/aws_foundational_security_eks_2.yaml old mode 100755 new mode 100644 index 23e199c4c..20dacc13e --- a/compliance/controls/aws/aws_foundational_security_eks_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_eks_2.yaml @@ -1,29 +1,28 @@ +Description: This control checks whether an Amazon EKS cluster is running on a supported Kubernetes version. The control fails if the EKS cluster is running on an unsupported version. If your application doesn't require a specific version of Kubernetes, we recommend that you use the latest available Kubernetes version that's supported by EKS for your clusters. ID: aws_foundational_security_eks_2 -Title: "2 EKS clusters should run on a supported Kubernetes version" -Description: "This control checks whether an Amazon EKS cluster is running on a supported Kubernetes version. The control fails if the EKS cluster is running on an unsupported version. If your application doesn't require a specific version of Kubernetes, we recommend that you use the latest available Kubernetes version that's supported by EKS for your clusters." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - -- eks:oldestVersionSupported (Current oldest supported version is 1.19) - when (version)::decimal >= 1.19 then 'ok' - else 'alarm' - end as status, - case - when (version)::decimal >= 1.19 then title || ' runs on a supported kubernetes version.' - else title || ' does not run on a supported kubernetes version.' - end as reason - from - aws_eks_cluster; - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (version)::decimal >= 1.19 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (version)::decimal >= 1.19 THEN title || ' runs on a supported kubernetes version.' + ELSE title || ' does not run on a supported kubernetes version.' + END AS reason + FROM + aws_eks_cluster; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 EKS clusters should run on a supported Kubernetes version \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_eks_8.yaml b/compliance/controls/aws/aws_foundational_security_eks_8.yaml old mode 100755 new mode 100644 index a4de69133..a02897993 --- a/compliance/controls/aws/aws_foundational_security_eks_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_eks_8.yaml @@ -1,43 +1,44 @@ +Description: This control checks whether an Amazon EKS cluster has audit logging enabled. The control fails if audit logging isn't enabled for the cluster. ID: aws_foundational_security_eks_8 -Title: "8 EKS clusters should have audit logging enabled" -Description: "This control checks whether an Amazon EKS cluster has audit logging enabled. The control fails if audit logging isn't enabled for the cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with control_panel_audit_logging as ( - select - distinct arn, - log -> 'Types' as log_type - from - aws_eks_cluster, - jsonb_array_elements(logging -> 'ClusterLogging') as log - where - log ->> 'Enabled' = 'true' - and (log -> 'Types') @> '["api", "audit", "authenticator", "controllerManager", "scheduler"]' - ) - select - c.arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when l.arn is not null then 'ok' - else 'alarm' - end as status, - case - when l.arn is not null then c.title || ' control plane audit logging enabled for all log types.' - else - case when logging -> 'ClusterLogging' @> '[{"Enabled": true}]' then c.title || ' control plane audit logging not enabled for all log types.' - else c.title || ' control plane audit logging not enabled.' - end - end as reason - from - aws_eks_cluster as c - left join control_panel_audit_logging as l on l.arn = c.arn; - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + WITH control_panel_audit_logging AS ( + SELECT + DISTINCT arn, + log -> 'Types' AS log_type + FROM + aws_eks_cluster, + jsonb_array_elements(logging -> 'ClusterLogging') AS log + WHERE + log ->> 'Enabled' = 'true' + AND (log -> 'Types') @> '["api", "audit", "authenticator", "controllerManager", "scheduler"]' + ) + SELECT + c.arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN l.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN l.arn IS NOT NULL THEN c.title || ' control plane audit logging enabled for all log types.' + ELSE + CASE + WHEN logging -> 'ClusterLogging' @> '[{"Enabled": true}]' THEN c.title || ' control plane audit logging not enabled for all log types.' + ELSE c.title || ' control plane audit logging not enabled.' + END + END AS reason + FROM + aws_eks_cluster AS c + LEFT JOIN control_panel_audit_logging AS l ON l.arn = c.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 EKS clusters should have audit logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elasticache_1.yaml b/compliance/controls/aws/aws_foundational_security_elasticache_1.yaml old mode 100755 new mode 100644 index 085e88f4e..b5d9c43dc --- a/compliance/controls/aws/aws_foundational_security_elasticache_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_elasticache_1.yaml @@ -1,14 +1,29 @@ +Description: This control evaluates if Amazon ElastiCache for Redis clusters have automatic backup scheduled. The control fails if the SnapshotRetentionLimit for the Redis cluster is less than 1. ID: aws_foundational_security_elasticache_1 -Title: "1 ElastiCache for Redis clusters should have automatic backups scheduled" -Description: "This control evaluates if Amazon ElastiCache for Redis clusters have automatic backup scheduled. The control fails if the SnapshotRetentionLimit for the Redis cluster is less than 1." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when snapshot_retention_limit < 15 then 'alarm'\n else 'ok'\n end as status,\n case\n when snapshot_retention_limit = 0 then title || ' automatic backups not enabled.'\n when snapshot_retention_limit < 15 then title || ' automatic backup retention period is less than 15 days.'\n else title || ' automatic backup retention period is more than 15 days.'\n end as reason\n \nfrom\n aws_elasticache_replication_group;" - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_replication_group Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN snapshot_retention_limit < 15 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN snapshot_retention_limit = 0 THEN title || ' automatic backups not enabled.' + WHEN snapshot_retention_limit < 15 THEN title || ' automatic backup retention period is less than 15 days.' + ELSE title || ' automatic backup retention period is more than 15 days.' + END AS reason + FROM + aws_elasticache_replication_group; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 ElastiCache for Redis clusters should have automatic backups scheduled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elasticache_2.yaml b/compliance/controls/aws/aws_foundational_security_elasticache_2.yaml old mode 100755 new mode 100644 index aa9b8c716..7ea3b65bb --- a/compliance/controls/aws/aws_foundational_security_elasticache_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_elasticache_2.yaml @@ -1,28 +1,28 @@ +Description: This control evaluates whether ElastiCache for Redis automatically applies minor version upgrades to cache clusters. This control fails if ElastiCache for Redis cache clusters do not have minor version upgrades automatically applied. ID: aws_foundational_security_elasticache_2 -Title: "2 Minor version upgrades should be automatically applied to ElastiCache for Redis cache clusters" -Description: "This control evaluates whether ElastiCache for Redis automatically applies minor version upgrades to cache clusters. This control fails if ElastiCache for Redis cache clusters do not have minor version upgrades automatically applied." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when auto_minor_version_upgrade then 'ok' - else 'alarm' - end as status, - case - when auto_minor_version_upgrade then title || ' automatic minor version upgrades enabled.' - else title || ' automatic minor version upgrades disabled.' - end as reason - from - aws_elasticache_cluster; - PrimaryTable: aws_elasticache_cluster ListOfTables: - aws_elasticache_cluster Parameters: [] + PrimaryTable: aws_elasticache_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrades enabled.' + ELSE title || ' automatic minor version upgrades disabled.' + END AS reason + FROM + aws_elasticache_cluster; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Minor version upgrades should be automatically applied to ElastiCache for Redis cache clusters \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elasticache_3.yaml b/compliance/controls/aws/aws_foundational_security_elasticache_3.yaml old mode 100755 new mode 100644 index c6d6d6a6c..9ea65d6d2 --- a/compliance/controls/aws/aws_foundational_security_elasticache_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_elasticache_3.yaml @@ -1,14 +1,28 @@ +Description: This control checks if ElastiCache for Redis replication groups have automatic failover enabled. This control fails if automatic failover isn't enabled for a Redis replication group. ID: aws_foundational_security_elasticache_3 -Title: "3 ElastiCache for Redis replication groups should have automatic failover enabled" -Description: "This control checks if ElastiCache for Redis replication groups have automatic failover enabled. This control fails if automatic failover isn't enabled for a Redis replication group." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when automatic_failover = 'enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when automatic_failover = 'enabled' then title || ' automatic failover enabled.'\n else title || ' automatic failover disabled.'\n end as reason\n \nfrom\n aws_elasticache_replication_group;" - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_replication_group Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN automatic_failover = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN automatic_failover = 'enabled' THEN title || ' automatic failover enabled.' + ELSE title || ' automatic failover disabled.' + END AS reason + FROM + aws_elasticache_replication_group; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 ElastiCache for Redis replication groups should have automatic failover enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elasticache_4.yaml b/compliance/controls/aws/aws_foundational_security_elasticache_4.yaml old mode 100755 new mode 100644 index 7aa23b1ce..568df2faf --- a/compliance/controls/aws/aws_foundational_security_elasticache_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_elasticache_4.yaml @@ -1,28 +1,28 @@ +Description: This control checks if ElastiCache for Redis replication groups are encrypted at rest. This control fails if an ElastiCache for Redis replication group isn't encrypted at rest. ID: aws_foundational_security_elasticache_4 -Title: "4 ElastiCache for Redis replication groups should be encrypted at rest" -Description: "This control checks if ElastiCache for Redis replication groups are encrypted at rest. This control fails if an ElastiCache for Redis replication group isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when at_rest_encryption_enabled then 'ok' - else 'alarm' - end as status, - case - when at_rest_encryption_enabled then title || ' encryption at rest enabled.' - else title || ' encryption at rest disabled.' - end as reason - from - aws_elasticache_replication_group; - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_replication_group Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN at_rest_encryption_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN at_rest_encryption_enabled THEN title || ' encryption at rest enabled.' + ELSE title || ' encryption at rest disabled.' + END AS reason + FROM + aws_elasticache_replication_group; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 ElastiCache for Redis replication groups should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elasticache_5.yaml b/compliance/controls/aws/aws_foundational_security_elasticache_5.yaml old mode 100755 new mode 100644 index 46d78f798..d11e5cbb8 --- a/compliance/controls/aws/aws_foundational_security_elasticache_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_elasticache_5.yaml @@ -1,14 +1,28 @@ +Description: This control checks if ElastiCache for Redis replication groups are encrypted in transit. This control fails if an ElastiCache for Redis replication group isn't encrypted in transit. ID: aws_foundational_security_elasticache_5 -Title: "5 ElastiCache for Redis replication groups should be encrypted in transit" -Description: "This control checks if ElastiCache for Redis replication groups are encrypted in transit. This control fails if an ElastiCache for Redis replication group isn't encrypted in transit." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when transit_encryption_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when transit_encryption_enabled then title || ' encryption in transit enabled.'\n else title || ' encryption in transit disabled.'\n end as reason\n \nfrom\n aws_elasticache_replication_group;" - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_replication_group Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN transit_encryption_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN transit_encryption_enabled THEN title || ' encryption in transit enabled.' + ELSE title || ' encryption in transit disabled.' + END AS reason + FROM + aws_elasticache_replication_group; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 ElastiCache for Redis replication groups should be encrypted in transit \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elasticache_6.yaml b/compliance/controls/aws/aws_foundational_security_elasticache_6.yaml old mode 100755 new mode 100644 index cf0cd0404..7e8869cdd --- a/compliance/controls/aws/aws_foundational_security_elasticache_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_elasticache_6.yaml @@ -1,39 +1,39 @@ +Description: This control checks if ElastiCache for Redis replication groups have Redis AUTH enabled. The control fails for an ElastiCache for Redis replication group if the Redis version of its nodes is below 6.0 and AuthToken isn't in use. ID: aws_foundational_security_elasticache_6 -Title: "6 ElastiCache for Redis replication groups before version 6.0 should use Redis AUTH" -Description: "This control checks if ElastiCache for Redis replication groups have Redis AUTH enabled. The control fails for an ElastiCache for Redis replication group if the Redis version of its nodes is below 6.0 and AuthToken isn't in use." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with elasticache_cluster_node_version as ( - select - distinct replication_group_id, - engine_version - from - aws_elasticache_cluster - ) - select - arn as resource, - eg.og_account_id as og_account_id, - eg.og_resource_id as og_resource_id, - case - when regexp_split_to_array(v.engine_version, '\.')::int[] >= regexp_split_to_array('6.0', '\.')::int[] then 'skip' - when regexp_split_to_array(v.engine_version, '\.')::int[] < regexp_split_to_array('6.0', '\.')::int[] and eg.auth_token_enabled then 'ok' - else 'alarm' - end as status, - case - when regexp_split_to_array(v.engine_version, '\.')::int[] >= regexp_split_to_array('6.0', '\.')::int[] then eg.title || ' node version is ' || engine_version || '.' - when regexp_split_to_array(v.engine_version, '\.')::int[] < regexp_split_to_array('6.0', '\.')::int[] and eg.auth_token_enabled then eg.title || ' has Redis AUTH enabled.' - else eg.title || ' has Redis AUTH disabled.' - end as reason - from - aws_elasticache_replication_group as eg - left join elasticache_cluster_node_version as v on eg.replication_group_id = v.replication_group_id; - PrimaryTable: aws_elasticache_replication_group ListOfTables: - aws_elasticache_cluster - aws_elasticache_replication_group Parameters: [] + PrimaryTable: aws_elasticache_replication_group + QueryToExecute: | + WITH elasticache_cluster_node_version AS ( + SELECT + DISTINCT replication_group_id, + engine_version + FROM + aws_elasticache_cluster + ) + SELECT + arn AS resource, + eg.og_account_id AS og_account_id, + eg.og_resource_id AS og_resource_id, + CASE + WHEN regexp_split_to_array(v.engine_version, '.')::INT[] >= regexp_split_to_array('6.0', '.')::INT[] THEN 'skip' + WHEN regexp_split_to_array(v.engine_version, '.')::INT[] < regexp_split_to_array('6.0', '.')::INT[] AND eg.auth_token_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN regexp_split_to_array(v.engine_version, '.')::INT[] >= regexp_split_to_array('6.0', '.')::INT[] THEN eg.title || ' node version is ' || engine_version || '.' + WHEN regexp_split_to_array(v.engine_version, '.')::INT[] < regexp_split_to_array('6.0', '.')::INT[] AND eg.auth_token_enabled THEN eg.title || ' has Redis AUTH enabled.' + ELSE eg.title || ' has Redis AUTH disabled.' + END AS reason + FROM + aws_elasticache_replication_group AS eg + LEFT JOIN elasticache_cluster_node_version AS v ON eg.replication_group_id = v.replication_group_id; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 ElastiCache for Redis replication groups before version 6.0 should use Redis AUTH \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elasticache_7.yaml b/compliance/controls/aws/aws_foundational_security_elasticache_7.yaml old mode 100755 new mode 100644 index cf0c7c0e4..34af3f6cf --- a/compliance/controls/aws/aws_foundational_security_elasticache_7.yaml +++ b/compliance/controls/aws/aws_foundational_security_elasticache_7.yaml @@ -1,14 +1,28 @@ +Description: This control checks if ElastiCache clusters are configured with a custom subnet group. The control fails for an ElastiCache cluster if CacheSubnetGroupName has the value default. ID: aws_foundational_security_elasticache_7 -Title: "7 ElastiCache clusters should not use the default subnet group" -Description: "This control checks if ElastiCache clusters are configured with a custom subnet group. The control fails for an ElastiCache cluster if CacheSubnetGroupName has the value default." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when cache_subnet_group_name = 'default' then 'alarm'\n else 'ok'\n end as status,\n case\n when cache_subnet_group_name = 'default' then title || ' not configured with a custom subnet group.'\n else title || ' configured with a custom subnet group.'\n end as reason\n \n \nfrom\n aws_elasticache_cluster;" - PrimaryTable: aws_elasticache_cluster ListOfTables: - aws_elasticache_cluster Parameters: [] + PrimaryTable: aws_elasticache_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cache_subnet_group_name = 'default' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN cache_subnet_group_name = 'default' THEN title || ' not configured with a custom subnet group.' + ELSE title || ' configured with a custom subnet group.' + END AS reason + FROM + aws_elasticache_cluster; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 ElastiCache clusters should not use the default subnet group \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elasticbeanstalk_1.yaml b/compliance/controls/aws/aws_foundational_security_elasticbeanstalk_1.yaml old mode 100755 new mode 100644 index d04203a2d..6d9a3c183 --- a/compliance/controls/aws/aws_foundational_security_elasticbeanstalk_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_elasticbeanstalk_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether enhanced health reporting is enabled for your AWS Elastic Beanstalk environments. Elastic Beanstalk enhanced health reporting enables a more rapid response to changes in the health of the underlying infrastructure. These changes could result in a lack of availability of the application. ID: aws_foundational_security_elasticbeanstalk_1 -Title: "1 Elastic Beanstalk environments should have enhanced health reporting enabled" -Description: "This control checks whether enhanced health reporting is enabled for your AWS Elastic Beanstalk environments.Elastic Beanstalk enhanced health reporting enables a more rapid response to changes in the health of the underlying infrastructure. These changes could result in a lack of availability of the application." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - application_name as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when health_status is not null and health is not null then 'ok' - else 'alarm' - end as status, - case - when health_status is not null and health is not null then application_name || ' enhanced health check enabled.' - else application_name || ' enhanced health check disabled.' - end as reason - from - aws_elastic_beanstalk_environment; - PrimaryTable: aws_elastic_beanstalk_environment ListOfTables: - aws_elastic_beanstalk_environment Parameters: [] + PrimaryTable: aws_elastic_beanstalk_environment + QueryToExecute: | + SELECT + application_name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN health_status IS NOT NULL AND health IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN health_status IS NOT NULL AND health IS NOT NULL THEN application_name || ' enhanced health check enabled.' + ELSE application_name || ' enhanced health check disabled.' + END AS reason + FROM + aws_elastic_beanstalk_environment; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Elastic Beanstalk environments should have enhanced health reporting enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elasticbeanstalk_3.yaml b/compliance/controls/aws/aws_foundational_security_elasticbeanstalk_3.yaml old mode 100755 new mode 100644 index 2e05a2034..ed5c96040 --- a/compliance/controls/aws/aws_foundational_security_elasticbeanstalk_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_elasticbeanstalk_3.yaml @@ -1,42 +1,42 @@ +Description: This control checks whether an Elastic Beanstalk environment is configured to send logs to CloudWatch Logs. The control fails if an Elastic Beanstalk environment isn't configured to send logs to CloudWatch Logs. Optionally, you can provide a custom value for the RetentionInDays parameter if you want the control to pass only if logs are retained for the specified number of days before expiration. ID: aws_foundational_security_elasticbeanstalk_3 -Title: "3 Elastic Beanstalk should stream logs to CloudWatch" -Description: "This control checks whether an Elastic Beanstalk environment is configured to send logs to CloudWatch Logs. The control fails if an Elastic Beanstalk environment isn't configured to send logs to CloudWatch Logs. Optionally, you can provide a custom value for the RetentionInDays parameter if you want the control to pass only if logs are retained for the specified number of days before expiration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with beanstalk_environment_logs_enabled as ( - select - distinct e.arn - from - aws_elastic_beanstalk_environment as e, - jsonb_array_elements(e.configuration_settings) as c, - jsonb_array_elements(c -> 'OptionSettings') as s - where - s ->> 'OptionName' = 'StreamLogs' - and s ->> 'Value' = 'true' - group by - arn - ) - select - e.arn as resource, - e.og_account_id as og_account_id, - e.og_resource_id as og_resource_id, - case - when l.arn is not null then 'ok' - else 'alarm' - end as status, - case - when l.arn is not null then title || ' send logs to AWS CloudWatch.' - else title || ' does not send logs to AWS CloudWatch.' - end as reason - from - aws_elastic_beanstalk_environment as e - left join beanstalk_environment_logs_enabled as l on e.arn = l.arn; - PrimaryTable: aws_elastic_beanstalk_environment ListOfTables: - aws_elastic_beanstalk_environment Parameters: [] + PrimaryTable: aws_elastic_beanstalk_environment + QueryToExecute: | + WITH beanstalk_environment_logs_enabled AS ( + SELECT + DISTINCT e.arn + FROM + aws_elastic_beanstalk_environment AS e, + jsonb_array_elements(e.configuration_settings) AS c, + jsonb_array_elements(c -> 'OptionSettings') AS s + WHERE + s ->> 'OptionName' = 'StreamLogs' + AND s ->> 'Value' = 'true' + GROUP BY + arn + ) + SELECT + e.arn AS resource, + e.og_account_id AS og_account_id, + e.og_resource_id AS og_resource_id, + CASE + WHEN l.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN l.arn IS NOT NULL THEN title || ' send logs to AWS CloudWatch.' + ELSE title || ' does not send logs to AWS CloudWatch.' + END AS reason + FROM + aws_elastic_beanstalk_environment AS e + LEFT JOIN beanstalk_environment_logs_enabled AS l ON e.arn = l.arn; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Elastic Beanstalk should stream logs to CloudWatch \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elb_1.yaml b/compliance/controls/aws/aws_foundational_security_elb_1.yaml old mode 100755 new mode 100644 index c25fae556..51e12d46d --- a/compliance/controls/aws/aws_foundational_security_elb_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_elb_1.yaml @@ -1,44 +1,44 @@ +Description: This control checks whether HTTP to HTTPS redirection is configured on all HTTP listeners of Application Load Balancers. The control fails if any of the HTTP listeners of Application Load Balancers do not have HTTP to HTTPS redirection configured. ID: aws_foundational_security_elb_1 -Title: "1 Application Load Balancer should be configured to redirect all HTTP requests to HTTPS" -Description: "This control checks whether HTTP to HTTPS redirection is configured on all HTTP listeners of Application Load Balancers. The control fails if any of the HTTP listeners of Application Load Balancers do not have HTTP to HTTPS redirection configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with detailed_listeners as ( - select + ListOfTables: + - aws_ec2_load_balancer_listener + - aws_ec2_application_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + WITH detailed_listeners AS ( + SELECT arn, load_balancer_arn, protocol - from + FROM aws_ec2_load_balancer_listener, - jsonb_array_elements(default_actions) as ac - where + jsonb_array_elements(default_actions) AS ac + WHERE split_part(arn,'/',2) = 'app' - and protocol = 'HTTP' - and ac ->> 'Type' = 'redirect' - and ac -> 'RedirectConfig' ->> 'Protocol' = 'HTTPS' + AND protocol = 'HTTP' + AND ac ->> 'Type' = 'redirect' + AND ac -> 'RedirectConfig' ->> 'Protocol' = 'HTTPS' ) - select - a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.load_balancer_arn is null then 'alarm' - else 'ok' - end as status, - case - when b.load_balancer_arn is not null then a.title || ' associated with HTTP redirection.' - else a.title || ' not associated with HTTP redirection.' - end as reason - from + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.load_balancer_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.load_balancer_arn IS NOT NULL THEN a.title || ' associated with HTTP redirection.' + ELSE a.title || ' not associated with HTTP redirection.' + END AS reason + FROM aws_ec2_application_load_balancer a - left join detailed_listeners b on a.arn = b.load_balancer_arn; - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_load_balancer_listener - - aws_ec2_application_load_balancer - Parameters: [] + LEFT JOIN detailed_listeners b ON a.arn = b.load_balancer_arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Application Load Balancer should be configured to redirect all HTTP requests to HTTPS \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elb_10.yaml b/compliance/controls/aws/aws_foundational_security_elb_10.yaml old mode 100755 new mode 100644 index 02f12fd19..f2aa27133 --- a/compliance/controls/aws/aws_foundational_security_elb_10.yaml +++ b/compliance/controls/aws/aws_foundational_security_elb_10.yaml @@ -1,14 +1,25 @@ +Description: This control checks whether a Classic Load Balancer has been configured to span multiple Availability Zones. The control fails if the Classic Load Balancer does not span multiple Availability Zones. ID: aws_foundational_security_elb_10 -Title: "10 Classic Load Balancers should span multiple Availability Zones" -Description: "This control checks whether a Classic Load Balancer has been configured to span multiple Availability Zones. The control fails if the Classic Load Balancer does not span multiple Availability Zones." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(availability_zones) < 2 then 'alarm'\n else 'ok'\n end as status,\n title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason\n \n \nfrom\n aws_ec2_classic_load_balancer;" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason + FROM + aws_ec2_classic_load_balancer; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 10 Classic Load Balancers should span multiple Availability Zones \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elb_12.yaml b/compliance/controls/aws/aws_foundational_security_elb_12.yaml old mode 100755 new mode 100644 index 9618eba40..bb197062d --- a/compliance/controls/aws/aws_foundational_security_elb_12.yaml +++ b/compliance/controls/aws/aws_foundational_security_elb_12.yaml @@ -1,37 +1,37 @@ +Description: This control checks whether an Application Load Balancer is configured with defensive or strictest desync mitigation mode. The control fails if an Application Load Balancer is not configured with defensive or strictest desync mitigation mode. ID: aws_foundational_security_elb_12 -Title: "12 Application Load Balancers should be configured with defensive or strictest desync mitigation mode" -Description: "This control checks whether an Application Load Balancer is configured with defensive or strictest desync mitigation mode. The control fails if an Application Load Balancer is not configured with defensive or strictest desync mitigation mode." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with app_lb_desync_mitigation_mode as ( - select + ListOfTables: + - aws_ec2_application_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + WITH app_lb_desync_mitigation_mode AS ( + SELECT arn, - l ->> 'Key', - l ->> 'Value' as v - from + l ->> 'Key' AS key, + l ->> 'Value' AS v + FROM aws_ec2_application_load_balancer, - jsonb_array_elements(load_balancer_attributes) as l - where + jsonb_array_elements(load_balancer_attributes) AS l + WHERE l ->> 'Key' = 'routing.http.desync_mitigation_mode' ) - select - a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when m.v = any(array['defensive', 'strictest']) then 'ok' - else 'alarm' - end as status, - title || ' has ' || m.v || ' desync mitigation mode.' as reason - from - aws_ec2_application_load_balancer as a - left join app_lb_desync_mitigation_mode as m on a.arn = m.arn; - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - Parameters: [] + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN m.v = ANY(ARRAY['defensive', 'strictest']) THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' has ' || m.v || ' desync mitigation mode.' AS reason + FROM + aws_ec2_application_load_balancer AS a + LEFT JOIN app_lb_desync_mitigation_mode AS m ON a.arn = m.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 12 Application Load Balancers should be configured with defensive or strictest desync mitigation mode \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elb_14.yaml b/compliance/controls/aws/aws_foundational_security_elb_14.yaml old mode 100755 new mode 100644 index 003a0052e..22ffed655 --- a/compliance/controls/aws/aws_foundational_security_elb_14.yaml +++ b/compliance/controls/aws/aws_foundational_security_elb_14.yaml @@ -1,14 +1,39 @@ +Description: This control checks whether a Classic Load Balancer is configured with defensive or strictest desync mitigation mode. This control will fail if the Classic Load Balancer is not configured with defensive or strictest desync mitigation mode. ID: aws_foundational_security_elb_14 -Title: "14 Classic Load Balancers should be configured with defensive or strictest desync mitigation mode" -Description: "This control checks whether a Classic Load Balancer is configured with defensive or strictest desync mitigation mode. This control will fail if the Classic Load Balancer is not configured with defensive or strictest desync mitigation mode." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with app_lb_desync_mitigation_mode as (\n select\n arn,\n a ->> 'Key',\n a ->> 'Value' as v\n from\n aws_ec2_classic_load_balancer,\n jsonb_array_elements(additional_attributes) as a\n where\n a ->> 'Key' = 'elb.http.desyncmitigationmode'\n)\nselect\n c.arn as resource,\n c.og_account_id as og_account_id,\n c.og_resource_id as og_resource_id,\n case\n when m.v = any(array['defensive', 'strictest']) then 'ok'\n else 'alarm'\n end as status,\n title || ' has ' || m.v || ' desync mitigation mode.' as reason\n \n \nfrom\n aws_ec2_classic_load_balancer as c\n left join app_lb_desync_mitigation_mode as m on c.arn = m.arn;" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + WITH app_lb_desync_mitigation_mode AS ( + SELECT + arn, + a ->> 'Key', + a ->> 'Value' AS v + FROM + aws_ec2_classic_load_balancer, + jsonb_array_elements(additional_attributes) AS a + WHERE + a ->> 'Key' = 'elb.http.desyncmitigationmode' + ) + + SELECT + c.arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN m.v = ANY(ARRAY['defensive', 'strictest']) THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' has ' || m.v || ' desync mitigation mode.' AS reason + FROM + aws_ec2_classic_load_balancer AS c + LEFT JOIN app_lb_desync_mitigation_mode AS m + ON c.arn = m.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 14 Classic Load Balancers should be configured with defensive or strictest desync mitigation mode \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elb_2.yaml b/compliance/controls/aws/aws_foundational_security_elb_2.yaml old mode 100755 new mode 100644 index 506e3319f..a4ae303ca --- a/compliance/controls/aws/aws_foundational_security_elb_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_elb_2.yaml @@ -1,41 +1,41 @@ +Description: This control checks whether the Classic Load Balancer uses HTTPS/SSL certificates provided by AWS Certificate Manager (ACM). The control fails if the Classic Load Balancer configured with HTTPS/SSL listener does not use a certificate provided by ACM. ID: aws_foundational_security_elb_2 -Title: "2 Classic Load Balancers with SSL/HTTPS listeners should use a certificate provided by AWS Certificate Manager" -Description: "This control checks whether the Classic Load Balancer uses HTTPS/SSL certificates provided by AWS Certificate Manager (ACM). The control fails if the Classic Load Balancer configured with HTTPS/SSL listener does not use a certificate provided by ACM." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with detailed_classic_listeners as ( - select - name - from - aws_ec2_classic_load_balancer, - jsonb_array_elements(listener_descriptions) as listener_description - where - listener_description -> 'Listener' ->> 'Protocol' in ('HTTPS', 'SSL', 'TLS') - and listener_description -> 'Listener' ->> 'SSLCertificateId' like 'arn:aws:acm%' - ) - select - 'arn:' || a.partition || ':elasticloadbalancing:' || a.region || ':' || a.account_id || ':loadbalancer/' || a.name as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.listener_descriptions is null then 'skip' - when b.name is not null then 'alarm' - else 'ok' - end as status, - case - when a.listener_descriptions is null then a.title || ' has no listener.' - when b.name is not null then a.title || ' does not use certificates provided by ACM.' - else a.title || ' uses certificates provided by ACM.' - end as reason - from - aws_ec2_classic_load_balancer as a - left join detailed_classic_listeners as b on a.name = b.name; - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + WITH detailed_classic_listeners AS ( + SELECT + name + FROM + aws_ec2_classic_load_balancer, + jsonb_array_elements(listener_descriptions) AS listener_description + WHERE + listener_description -> 'Listener' ->> 'Protocol' IN ('HTTPS', 'SSL', 'TLS') + AND listener_description -> 'Listener' ->> 'SSLCertificateId' LIKE 'arn:aws:acm%' + ) + SELECT + 'arn:' || a.partition || ':elasticloadbalancing:' || a.region || ':' || a.account_id || ':loadbalancer/' || a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.listener_descriptions IS NULL THEN 'skip' + WHEN b.name IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.listener_descriptions IS NULL THEN a.title || ' has no listener.' + WHEN b.name IS NOT NULL THEN a.title || ' does not use certificates provided by ACM.' + ELSE a.title || ' uses certificates provided by ACM.' + END AS reason + FROM + aws_ec2_classic_load_balancer AS a + LEFT JOIN detailed_classic_listeners AS b ON a.name = b.name; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Classic Load Balancers with SSL/HTTPS listeners should use a certificate provided by AWS Certificate Manager \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elb_4.yaml b/compliance/controls/aws/aws_foundational_security_elb_4.yaml old mode 100755 new mode 100644 index 75c263a19..2132f5ad1 --- a/compliance/controls/aws/aws_foundational_security_elb_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_elb_4.yaml @@ -1,14 +1,28 @@ +Description: This control evaluates AWS Application Load Balancers (ALB) to ensure they are configured to drop invalid HTTP headers. The control fails if the value of routing.http.drop_invalid_header_fields.enabled is set to false. By default, ALBs are not configured to drop invalid HTTP header values. Removing these header values prevents HTTP desync attacks. ID: aws_foundational_security_elb_4 -Title: "4 Application load balancers should be configured to drop HTTP headers" -Description: "This control evaluates AWS Application Load Balancers (ALB) to ensure they are configured to drop invalid HTTP headers. The control fails if the value of routing.http.drop_invalid_header_fields.enabled is set to false. By default, ALBs are not configured to drop invalid HTTP header values. Removing these header values prevents HTTP desync attacks." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when load_balancer_attributes @> '[{\"Key\": \"routing.http.drop_invalid_header_fields.enabled\", \"Value\": \"true\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when load_balancer_attributes @> '[{\"Key\": \"routing.http.drop_invalid_header_fields.enabled\", \"Value\": \"true\"}]' then title || ' configured to drop http headers.'\n else title || ' not configured to drop http headers.'\n end as reason\n \n \nfrom\n aws_ec2_application_load_balancer;" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN load_balancer_attributes @> '[{"Key": "routing.http.drop_invalid_header_fields.enabled", "Value": "true"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN load_balancer_attributes @> '[{"Key": "routing.http.drop_invalid_header_fields.enabled", "Value": "true"}]' THEN title || ' configured to drop http headers.' + ELSE title || ' not configured to drop http headers.' + END AS reason + FROM + aws_ec2_application_load_balancer; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 Application load balancers should be configured to drop HTTP headers \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elb_6.yaml b/compliance/controls/aws/aws_foundational_security_elb_6.yaml old mode 100755 new mode 100644 index 789ccc59b..be35da2e9 --- a/compliance/controls/aws/aws_foundational_security_elb_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_elb_6.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an Application Load Balancer has deletion protection enabled. The control fails if deletion protection is not configured. Enable deletion protection to protect your Application Load Balancer from deletion. ID: aws_foundational_security_elb_6 -Title: "6 Application Load Balancer deletion protection should be enabled" -Description: "This control checks whether an Application Load Balancer has deletion protection enabled. The control fails if deletion protection is not configured. Enable deletion protection to protect your Application Load Balancer from deletion." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when load_balancer_attributes @> '[{\"Key\": \"deletion_protection.enabled\", \"Value\": \"true\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when load_balancer_attributes @> '[{\"Key\": \"deletion_protection.enabled\", \"Value\": \"true\"}]' then title || ' deletion protection enabled.'\n else title || ' deletion protection disabled.'\n end as reason\n \n \nfrom\n aws_ec2_application_load_balancer;" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN load_balancer_attributes @> '[{"Key": "deletion_protection.enabled", "Value": "true"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN load_balancer_attributes @> '[{"Key": "deletion_protection.enabled", "Value": "true"}]' THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection disabled.' + END AS reason + FROM + aws_ec2_application_load_balancer; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 Application Load Balancer deletion protection should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elb_7.yaml b/compliance/controls/aws/aws_foundational_security_elb_7.yaml old mode 100755 new mode 100644 index e7df2f41d..ceb1a9a9b --- a/compliance/controls/aws/aws_foundational_security_elb_7.yaml +++ b/compliance/controls/aws/aws_foundational_security_elb_7.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether Classic Load Balancers have connection draining enabled. ID: aws_foundational_security_elb_7 -Title: "7 Classic Load Balancers should have connection draining enabled" -Description: "This control checks whether Classic Load Balancers have connection draining enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when connection_draining_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when connection_draining_enabled then title || ' connection draining enabled.'\n else title || ' connection draining disabled.'\n end as reason\n \n \nfrom\n aws_ec2_classic_load_balancer;" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN connection_draining_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN connection_draining_enabled THEN title || ' connection draining enabled.' + ELSE title || ' connection draining disabled.' + END AS reason + FROM + aws_ec2_classic_load_balancer; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 Classic Load Balancers should have connection draining enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_elb_9.yaml b/compliance/controls/aws/aws_foundational_security_elb_9.yaml old mode 100755 new mode 100644 index d278a9730..c78940983 --- a/compliance/controls/aws/aws_foundational_security_elb_9.yaml +++ b/compliance/controls/aws/aws_foundational_security_elb_9.yaml @@ -1,28 +1,28 @@ +Description: This control checks if cross-zone load balancing is enabled for the Classic Load Balancers (CLBs). This control fails if cross-zone load balancing is not enabled for a CLB. ID: aws_foundational_security_elb_9 -Title: "9 Classic Load Balancers should have cross-zone load balancing enabled" -Description: "This control checks if cross-zone load balancing is enabled for the Classic Load Balancers (CLBs). This control fails if cross-zone load balancing is not enabled for a CLB." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when cross_zone_load_balancing_enabled then 'ok' - else 'alarm' - end as status, - case - when cross_zone_load_balancing_enabled then title || ' cross-zone load balancing enabled.' - else title || ' cross-zone load balancing disabled.' - end as reason - from - aws_ec2_classic_load_balancer; - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cross_zone_load_balancing_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cross_zone_load_balancing_enabled THEN title || ' cross-zone load balancing enabled.' + ELSE title || ' cross-zone load balancing disabled.' + END AS reason + FROM + aws_ec2_classic_load_balancer; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 Classic Load Balancers should have cross-zone load balancing enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_emr_1.yaml b/compliance/controls/aws/aws_foundational_security_emr_1.yaml old mode 100755 new mode 100644 index a55745d97..118fb1bcb --- a/compliance/controls/aws/aws_foundational_security_emr_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_emr_1.yaml @@ -1,32 +1,35 @@ +Description: This control checks whether master nodes on Amazon EMR clusters have public IP addresses. The control fails if the master node has public IP addresses that are associated with any of its instances. Public IP addresses are designated in the PublicIp field of the NetworkInterfaces configuration for the instance. This control only checks Amazon EMR clusters that are in a RUNNING or WAITING state. ID: aws_foundational_security_emr_1 -Title: "1 Amazon EMR cluster primary nodes should not have public IP addresses" -Description: "This control checks whether master nodes on Amazon EMR clusters have public IP addresses. The control fails if the master node has public IP addresses that are associated with any of its instances. Public IP addresses are designated in the PublicIp field of the NetworkInterfaces configuration for the instance. This control only checks Amazon EMR clusters that are in a RUNNING or WAITING state." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - c.cluster_arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when c.status ->> 'State' not in ('RUNNING', 'WAITING') then 'skip' - when s.map_public_ip_on_launch then 'alarm' - else 'ok' - end as status, - case - when c.status ->> 'State' not in ('RUNNING', 'WAITING') then c.title || ' is in ' || (c.status ->> 'State') || ' state.' - when s.map_public_ip_on_launch then c.title || ' master nodes assigned with public IP.' - else c.title || ' master nodes not assigned with public IP.' - end as reason - from - aws_emr_cluster as c - left join aws_vpc_subnet as s on c.ec2_instance_attributes ->> 'Ec2SubnetId' = s.subnet_id; - PrimaryTable: aws_emr_cluster ListOfTables: - aws_emr_cluster - aws_vpc_subnet Parameters: [] + PrimaryTable: aws_emr_cluster + QueryToExecute: | + SELECT + c.cluster_arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.status ->> 'State' NOT IN ('RUNNING', 'WAITING') THEN 'skip' + WHEN s.map_public_ip_on_launch THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.status ->> 'State' NOT IN ('RUNNING', 'WAITING') THEN c.title || ' is in ' || (c.status ->> 'State') || ' state.' + WHEN s.map_public_ip_on_launch THEN c.title || ' master nodes assigned with public IP.' + ELSE c.title || ' master nodes not assigned with public IP.' + END AS reason + FROM + aws_emr_cluster AS c + LEFT JOIN + aws_vpc_subnet AS s + ON + c.ec2_instance_attributes ->> 'Ec2SubnetId' = s.subnet_id; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Amazon EMR cluster primary nodes should not have public IP addresses \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_emr_2.yaml b/compliance/controls/aws/aws_foundational_security_emr_2.yaml old mode 100755 new mode 100644 index a8da8ec05..9c1cb6cef --- a/compliance/controls/aws/aws_foundational_security_emr_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_emr_2.yaml @@ -1,43 +1,44 @@ +Description: This control checks whether your account is configured with Amazon EMR block public access. The control fails if the block public access setting isn't enabled or if any port other than port 22 is allowed. ID: aws_foundational_security_emr_2 -Title: "2 Amazon EMR block public access setting should be enabled" -Description: "This control checks whether your account is configured with Amazon EMR block public access. The control fails if the block public access setting isn't enabled or if any port other than port 22 is allowed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with emr_port_configuration as( - select + ListOfTables: + - aws_emr_block_public_access_configuration + Parameters: [] + PrimaryTable: aws_emr_block_public_access_configuration + QueryToExecute: | + WITH emr_port_configuration AS ( + SELECT region, account_id - from + FROM aws_emr_block_public_access_configuration, - jsonb_array_elements(permitted_public_security_group_rule_ranges) as r - where + jsonb_array_elements(permitted_public_security_group_rule_ranges) AS r + WHERE (r -> 'MaxRange')::int = 22 - and (r-> 'MinRange')::int = 22 - and block_public_security_group_rules + AND (r -> 'MinRange')::int = 22 + AND block_public_security_group_rules ) - select - 'arn:' || c.partition || '::' || c.region || ':' || c.account_id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when not block_public_security_group_rules then 'alarm' - when block_public_security_group_rules and p.region is not null then 'ok' - else 'alarm' - end as status, - case - when not block_public_security_group_rules then c.region || ' EMR block public access disabled.' - when block_public_security_group_rules and p.region is not null then c.region || ' EMR block public access enabled.' - else c.region || ' EMR block public access enabled for ports other than 22.' - end as reason - from - aws_emr_block_public_access_configuration as c - left join emr_port_configuration as p on p.region = c.region and p.account_id = c.account_id - PrimaryTable: aws_emr_block_public_access_configuration - ListOfTables: - - aws_emr_block_public_access_configuration - Parameters: [] + SELECT + 'arn:' || c.partition || '::' || c.region || ':' || c.account_id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN NOT block_public_security_group_rules THEN 'alarm' + WHEN block_public_security_group_rules AND p.region IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT block_public_security_group_rules THEN c.region || ' EMR block public access disabled.' + WHEN block_public_security_group_rules AND p.region IS NOT NULL THEN c.region || ' EMR block public access enabled.' + ELSE c.region || ' EMR block public access enabled for ports other than 22.' + END AS reason + FROM + aws_emr_block_public_access_configuration AS c + LEFT JOIN emr_port_configuration AS p + ON p.region = c.region AND p.account_id = c.account_id Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Amazon EMR block public access setting should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_es_1.yaml b/compliance/controls/aws/aws_foundational_security_es_1.yaml old mode 100755 new mode 100644 index 7daffc294..1b84531ea --- a/compliance/controls/aws/aws_foundational_security_es_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_es_1.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether Amazon Elasticsearch Service (Amazon ES) domains have encryption at rest configuration enabled. The check fails if encryption at rest is not enabled. ID: aws_foundational_security_es_1 -Title: "1 Elasticsearch domains should have encryption at-rest enabled" -Description: "This control checks whether Amazon Elasticsearch Service (Amazon ES) domains have encryption at rest configuration enabled. The check fails if encryption at rest is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encryption_at_rest_options ->> 'Enabled' = 'false' then 'alarm'\n else 'ok'\n end status,\n case\n when encryption_at_rest_options ->> 'Enabled' = 'false' then title || ' encryption at rest not enabled.'\n else title || ' encryption at rest enabled.'\n end reason\n \n \nfrom\n aws_elasticsearch_domain;" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encryption_at_rest_options ->> 'Enabled' = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption_at_rest_options ->> 'Enabled' = 'false' THEN title || ' encryption at rest not enabled.' + ELSE title || ' encryption at rest enabled.' + END AS reason + FROM + aws_elasticsearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Elasticsearch domains should have encryption at-rest enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_es_2.yaml b/compliance/controls/aws/aws_foundational_security_es_2.yaml old mode 100755 new mode 100644 index 4bd9b799f..ea02fcba2 --- a/compliance/controls/aws/aws_foundational_security_es_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_es_2.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether Amazon Elasticsearch Service domains are in a VPC. It does not evaluate the VPC subnet routing configuration to determine public access. You should ensure that Amazon ES domains are not attached to public subnets. ID: aws_foundational_security_es_2 -Title: "2 Elasticsearch domains should not be publicly accessible" -Description: "This control checks whether Amazon Elasticsearch Service domains are in a VPC. It does not evaluate the VPC subnet routing configuration to determine public access. You should ensure that Amazon ES domains are not attached to public subnets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when vpc_options ->> 'VPCId' is null then 'alarm'\n else 'ok'\n end status,\n case\n when vpc_options ->> 'VPCId' is null then title || ' not in VPC.'\n else title || ' in VPC ' || (vpc_options ->> 'VPCId') || '.'\n end reason\n \n \nfrom\n aws_elasticsearch_domain;" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_options ->> 'VPCId' IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vpc_options ->> 'VPCId' IS NULL THEN title || ' not in VPC.' + ELSE title || ' in VPC ' || (vpc_options ->> 'VPCId') || '.' + END AS reason + FROM + aws_elasticsearch_domain; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Elasticsearch domains should not be publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_es_3.yaml b/compliance/controls/aws/aws_foundational_security_es_3.yaml old mode 100755 new mode 100644 index 832381b8f..dc810a31a --- a/compliance/controls/aws/aws_foundational_security_es_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_es_3.yaml @@ -1,30 +1,30 @@ +Description: This control checks whether Amazon ES domains have node-to-node encryption enabled. ID: aws_foundational_security_es_3 -Title: "3 Amazon Elasticsearch Service domains should encrypt data sent between nodes" -Description: "This control checks whether Amazon ES domains have node-to-node encryption enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) then 'skip' - when not enabled then 'alarm' - else 'ok' - end as status, - case - when region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) then title || ' node-to-node encryption not supported in ' || region || '.' - when not enabled then title || ' node-to-node encryption disabled.' - else title || ' node-to-node encryption enabled.' - end as reason - from - aws_elasticsearch_domain; - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) THEN 'skip' + WHEN NOT enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) THEN title || ' node-to-node encryption not supported in ' || region || '.' + WHEN NOT enabled THEN title || ' node-to-node encryption disabled.' + ELSE title || ' node-to-node encryption enabled.' + END AS reason + FROM + aws_elasticsearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Amazon Elasticsearch Service domains should encrypt data sent between nodes \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_es_4.yaml b/compliance/controls/aws/aws_foundational_security_es_4.yaml old mode 100755 new mode 100644 index 80157527e..d46d420b5 --- a/compliance/controls/aws/aws_foundational_security_es_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_es_4.yaml @@ -1,32 +1,32 @@ +Description: This control checks whether Elasticsearch domains are configured to send error logs to CloudWatch Logs. ID: aws_foundational_security_es_4 -Title: "4 Elasticsearch domain error logging to CloudWatch Logs should be enabled" -Description: "This control checks whether Elasticsearch domains are configured to send error logs to CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when - log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' - and log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null then 'ok' - else 'alarm' - end as status, - case - when - log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' - and log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null then title || ' error logging enabled.' - else title || ' error logging disabled.' - end as reason - from - aws_elasticsearch_domain; - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN + log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN + log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL THEN title || ' error logging enabled.' + ELSE title || ' error logging disabled.' + END AS reason + FROM + aws_elasticsearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 Elasticsearch domain error logging to CloudWatch Logs should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_es_5.yaml b/compliance/controls/aws/aws_foundational_security_es_5.yaml old mode 100755 new mode 100644 index 8a3190283..eed3bf1c9 --- a/compliance/controls/aws/aws_foundational_security_es_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_es_5.yaml @@ -1,14 +1,32 @@ +Description: This control checks whether Elasticsearch domains have audit logging enabled. This control fails if an Elasticsearch domain does not have audit logging enabled. ID: aws_foundational_security_es_5 -Title: "5 Elasticsearch domains should have audit logging enabled" -Description: "This control checks whether Elasticsearch domains have audit logging enabled. This control fails if an Elasticsearch domain does not have audit logging enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when\n log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when\n log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true'\n and log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null then title || ' audit logging enabled.'\n else title || ' audit logging disabled.'\n end as reason\n \n \nfrom\n aws_elasticsearch_domain;" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN + log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN + log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL THEN title || ' audit logging enabled.' + ELSE title || ' audit logging disabled.' + END AS reason + FROM + aws_elasticsearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 Elasticsearch domains should have audit logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_es_6.yaml b/compliance/controls/aws/aws_foundational_security_es_6.yaml old mode 100755 new mode 100644 index c500b00df..9e6b1cc93 --- a/compliance/controls/aws/aws_foundational_security_es_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_es_6.yaml @@ -1,14 +1,31 @@ +Description: This control checks whether Elasticsearch domains are configured with at least three data nodes and zoneAwarenessEnabled is true. ID: aws_foundational_security_es_6 -Title: "6 Elasticsearch domains should have at least three data nodes" -Description: "This control checks whether Elasticsearch domains are configured with at least three data nodes and zoneAwarenessEnabled is true." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'false' then 'alarm'\n when\n elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'true'\n and (elasticsearch_cluster_config ->> 'InstanceCount')::integer >= 3 then 'ok'\n else 'alarm'\n end status,\n case\n when elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'false' then title || ' zone awareness disabled.'\n else title || ' has ' || (elasticsearch_cluster_config ->> 'InstanceCount') || ' data node(s).'\n end as reason\n \n \nfrom\n aws_elasticsearch_domain;" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'false' THEN 'alarm' + WHEN + elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'true' + AND (elasticsearch_cluster_config ->> 'InstanceCount')::integer >= 3 THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN elasticsearch_cluster_config ->> 'ZoneAwarenessEnabled' = 'false' THEN title || ' zone awareness disabled.' + ELSE title || ' has ' || (elasticsearch_cluster_config ->> 'InstanceCount') || ' data node(s).' + END AS reason + FROM + aws_elasticsearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 Elasticsearch domains should have at least three data nodes \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_es_7.yaml b/compliance/controls/aws/aws_foundational_security_es_7.yaml old mode 100755 new mode 100644 index 9d1d30d2a..ab7a8f49d --- a/compliance/controls/aws/aws_foundational_security_es_7.yaml +++ b/compliance/controls/aws/aws_foundational_security_es_7.yaml @@ -1,31 +1,30 @@ +Description: This control checks whether Elasticsearch domains are configured with at least three dedicated master nodes. This control fails if the domain does not use dedicated master nodes. This control passes if Elasticsearch domains have five dedicated master nodes. However, using more than three master nodes might be unnecessary to mitigate the availability risk, and will result in additional cost. ID: aws_foundational_security_es_7 -Title: "7 Elasticsearch domains should be configured with at least three dedicated master nodes" -Description: "This control checks whether Elasticsearch domains are configured with at least three dedicated master nodes. This control fails if the domain does not use dedicated master nodes. This control passes if Elasticsearch domains have five dedicated master nodes. However, using more than three master nodes might be unnecessary to mitigate the availability risk, and will result in additional cost." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'false' then 'alarm' - when - elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'true' - and (elasticsearch_cluster_config ->> 'DedicatedMasterCount')::integer >= 3 then 'ok' - else 'alarm' - end status, - case - when elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'false' then title || ' dedicated master nodes disabled.' - else title || ' has ' || (elasticsearch_cluster_config ->> 'DedicatedMasterCount') || ' dedicated master node(s).' - end as reason - from - aws_elasticsearch_domain; - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'false' THEN 'alarm' + WHEN elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'true' + AND (elasticsearch_cluster_config ->> 'DedicatedMasterCount')::integer >= 3 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN elasticsearch_cluster_config ->> 'DedicatedMasterEnabled' = 'false' THEN title || ' dedicated master nodes disabled.' + ELSE title || ' has ' || (elasticsearch_cluster_config ->> 'DedicatedMasterCount') || ' dedicated master node(s).' + END AS reason + FROM + aws_elasticsearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 Elasticsearch domains should be configured with at least three dedicated master nodes \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_es_8.yaml b/compliance/controls/aws/aws_foundational_security_es_8.yaml old mode 100755 new mode 100644 index b9c101365..723411bd5 --- a/compliance/controls/aws/aws_foundational_security_es_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_es_8.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether connections to Elasticsearch domains are required to use TLS 1.2. The check fails if the Elasticsearch domain TLSSecurityPolicy is not Policy-Min-TLS-1-2-2019-07. ID: aws_foundational_security_es_8 -Title: "8 Connections to Elasticsearch domains should be encrypted using TLS 1.2" -Description: "This control checks whether connections to Elasticsearch domains are required to use TLS 1.2. The check fails if the Elasticsearch domain TLSSecurityPolicy is not Policy-Min-TLS-1-2-2019-07." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when domain_endpoint_options ->> 'TLSSecurityPolicy' = 'Policy-Min-TLS-1-2-2019-07' then 'ok'\n else 'alarm'\n end status,\n case\n when domain_endpoint_options ->> 'TLSSecurityPolicy' = 'Policy-Min-TLS-1-2-2019-07' then title || ' encrypted using TLS 1.2.'\n else title || ' not encrypted using TLS 1.2.'\n end as reason\n \n \nfrom\n aws_elasticsearch_domain;" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: [] + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN domain_endpoint_options ->> 'TLSSecurityPolicy' = 'Policy-Min-TLS-1-2-2019-07' THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN domain_endpoint_options ->> 'TLSSecurityPolicy' = 'Policy-Min-TLS-1-2-2019-07' THEN title || ' encrypted using TLS 1.2.' + ELSE title || ' not encrypted using TLS 1.2.' + END AS reason + FROM + aws_elasticsearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 Connections to Elasticsearch domains should be encrypted using TLS 1.2 \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_eventbridge_3.yaml b/compliance/controls/aws/aws_foundational_security_eventbridge_3.yaml old mode 100755 new mode 100644 index 4e0b67e49..0267ae440 --- a/compliance/controls/aws/aws_foundational_security_eventbridge_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_eventbridge_3.yaml @@ -1,14 +1,30 @@ +Description: This control checks if an Amazon EventBridge custom event bus has a resource-based policy attached. This control fails if the custom event bus doesn't have a resource-based policy. ID: aws_foundational_security_eventbridge_3 -Title: "3 EventBridge custom event buses should have a resource-based policy attached" -Description: "This control checks if an Amazon EventBridge custom event bus has a resource-based policy attached. This control fails if the custom event bus doesn't have a resource-based policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when name = 'default' then 'skip'\n when policy_std is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when name = 'default' then title || ' is default event bus.'\n when policy_std is not null then title || ' has resource based policy attached.'\n else title || ' does not have resource based policy attached.'\n end as reason\n \n \nfrom\n aws_eventbridge_bus;" - PrimaryTable: aws_eventbridge_bus ListOfTables: - aws_eventbridge_bus Parameters: [] + PrimaryTable: aws_eventbridge_bus + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN name = 'default' THEN 'skip' + WHEN policy_std IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN name = 'default' THEN title || ' is default event bus.' + WHEN policy_std IS NOT NULL THEN title || ' has resource based policy attached.' + ELSE title || ' does not have resource based policy attached.' + END AS reason + FROM + aws_eventbridge_bus; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 EventBridge custom event buses should have a resource-based policy attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_fsx_1.yaml b/compliance/controls/aws/aws_foundational_security_fsx_1.yaml old mode 100755 new mode 100644 index 385c39ce2..bec502c83 --- a/compliance/controls/aws/aws_foundational_security_fsx_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_fsx_1.yaml @@ -1,14 +1,34 @@ +Description: This control checks if an Amazon FSx for OpenZFS file system is configured to copy tags to backups and volumes. The control fails if the OpenZFS file system isn't configured to copy tags to backups and volumes. ID: aws_foundational_security_fsx_1 -Title: "1 FSx for OpenZFS file systems should be configured to copy tags to backups and volumes" -Description: "This control checks if an Amazon FSx for OpenZFS file system is configured to copy tags to backups and volumes. The control fails if the OpenZFS file system isn't configured to copy tags to backups and volumes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when file_system_type <> 'OPENZFS' then 'skip'\n when (open_zfs_configuration ->> 'CopyTagsToBackups')::bool and (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool then 'ok'\n else 'alarm'\n end as status,\n case\n when file_system_type <> 'OPENZFS' then title || ' is of ' || file_system_type || ' type file system.'\n when (open_zfs_configuration ->> 'CopyTagsToBackups')::bool and (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool then title || ' copy tags to backup and volume enabled.'\n when (open_zfs_configuration ->> 'CopyTagsToBackups')::bool then title || ' copy tags to backup enabled but disabled for volume.'\n when (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool then title || ' copy tags to volume enabled but disabled for backup.'\n else title || ' copy tags to backup and volume disabled.'\n end as reason\n \n \nfrom\n aws_fsx_file_system;" - PrimaryTable: aws_fsx_file_system ListOfTables: - aws_fsx_file_system Parameters: [] + PrimaryTable: aws_fsx_file_system + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN file_system_type <> 'OPENZFS' THEN 'skip' + WHEN (open_zfs_configuration ->> 'CopyTagsToBackups')::bool + AND (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN file_system_type <> 'OPENZFS' THEN title || ' is of ' || file_system_type || ' type file system.' + WHEN (open_zfs_configuration ->> 'CopyTagsToBackups')::bool + AND (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool THEN title || ' copy tags to backup and volume enabled.' + WHEN (open_zfs_configuration ->> 'CopyTagsToBackups')::bool THEN title || ' copy tags to backup enabled but disabled for volume.' + WHEN (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool THEN title || ' copy tags to volume enabled but disabled for backup.' + ELSE title || ' copy tags to backup and volume disabled.' + END AS reason + FROM + aws_fsx_file_system; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 FSx for OpenZFS file systems should be configured to copy tags to backups and volumes \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_iam_1.yaml b/compliance/controls/aws/aws_foundational_security_iam_1.yaml old mode 100755 new mode 100644 index ddab9561b..91cfb87b1 --- a/compliance/controls/aws/aws_foundational_security_iam_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_iam_1.yaml @@ -1,49 +1,48 @@ +Description: 'This control checks whether the default version of IAM policies (also known as customer managed policies) has administrator access that includes a statement with ''Effect'': ''Allow'' with ''Action'': ''*'' over ''Resource'': ''*''. The control only checks the customer managed policies that you create. It does not check inline and AWS managed policies.' ID: aws_foundational_security_iam_1 -Title: "1 IAM policies should not allow full '*' administrative privileges" -Description: "This control checks whether the default version of IAM policies (also known as customer managed policies) has administrator access that includes a statement with 'Effect': 'Allow' with 'Action': '*' over 'Resource': '*'. The control only checks the customer managed policies that you create. It does not check inline and AWS managed policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with star_access_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH star_access_policies AS ( + SELECT arn, - count(*) as num_bad_statements - from + COUNT(*) AS num_bad_statements + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where - not is_aws_managed - and s ->> 'Effect' = 'Allow' - and resource = '*' - and ( + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + NOT is_aws_managed + AND s ->> 'Effect' = 'Allow' + AND resource = '*' + AND ( (action = '*' - or action = '*:*' - ) + OR action = '*:*') ) - and is_attached - group by arn + AND is_attached + GROUP BY arn ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when s.arn is null then 'ok' - else 'alarm' - end status, - p.name || ' contains ' || coalesce(s.num_bad_statements,0) || ' statements that allow action "*" on resource "*".' as reason - from - aws_iam_policy as p - left join star_access_policies as s on p.arn = s.arn - where - not p.is_aws_managed; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN s.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + p.name || ' contains ' || COALESCE(s.num_bad_statements,0) || ' statements that allow action "*" on resource "*".' AS reason + FROM + aws_iam_policy AS p + LEFT JOIN star_access_policies AS s ON p.arn = s.arn + WHERE + NOT p.is_aws_managed; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 IAM policies should not allow full '*' administrative privileges \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_iam_2.yaml b/compliance/controls/aws/aws_foundational_security_iam_2.yaml old mode 100755 new mode 100644 index 7a7609f94..5399833da --- a/compliance/controls/aws/aws_foundational_security_iam_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_iam_2.yaml @@ -1,26 +1,26 @@ +Description: This control checks that none of your IAM users have policies attached. Instead, IAM users must inherit permissions from IAM groups or roles. ID: aws_foundational_security_iam_2 -Title: "2 IAM users should not have IAM policies attached" -Description: "This control checks that none of your IAM users have policies attached. Instead, IAM users must inherit permissions from IAM groups or roles." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when inline_policies is null and attached_policy_arns is null then 'ok' - else 'alarm' - end status, - name || ' has ' || coalesce(jsonb_array_length(inline_policies),0) || ' inline and ' || - coalesce(jsonb_array_length(attached_policy_arns),0) || ' directly attached policies.' as reason - from - aws_iam_user; - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN inline_policies IS NULL AND attached_policy_arns IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' has ' || COALESCE(JSONB_ARRAY_LENGTH(inline_policies), 0) || ' inline and ' || + COALESCE(JSONB_ARRAY_LENGTH(attached_policy_arns), 0) || ' directly attached policies.' AS reason + FROM + aws_iam_user; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 IAM users should not have IAM policies attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_iam_21.yaml b/compliance/controls/aws/aws_foundational_security_iam_21.yaml old mode 100755 new mode 100644 index 5722ec10b..b74cf8091 --- a/compliance/controls/aws/aws_foundational_security_iam_21.yaml +++ b/compliance/controls/aws/aws_foundational_security_iam_21.yaml @@ -1,49 +1,50 @@ +Description: 'This control checks whether the IAM identity-based policies that you create have Allow statements that use the * wildcard to grant permissions for all actions on any service. The control fails if any policy statement includes ''Effect'': ''Allow'' with ''Action'': ''Service:*''.' ID: aws_foundational_security_iam_21 -Title: "21 IAM customer managed policies that you create should not allow wildcard actions for services" -Description: "This control checks whether the IAM identity-based policies that you create have Allow statements that use the * wildcard to grant permissions for all actions on any service. The control fails if any policy statement includes 'Effect': 'Allow' with 'Action': 'Service:*'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with wildcard_action_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where - not is_aws_managed - and s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - action like '%:*' - or action = '*' + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + NOT is_aws_managed + AND s ->> 'Effect' = 'Allow' + AND resource = '*' + AND ( + action LIKE '%:*' + OR action = '*' ) - group by + GROUP BY arn ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when w.arn is null then 'ok' - else 'alarm' - end status, - p.name || ' contains ' || coalesce(w.statements_num,0) || - ' statements that allow action "*" on at least 1 AWS service on resource "*".' as reason - from - aws_iam_policy as p - left join wildcard_action_policies as w on p.arn = w.arn - where - not p.is_aws_managed; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN w.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + p.name || ' contains ' || COALESCE(w.statements_num, 0) || + ' statements that allow action "*" on at least 1 AWS service on resource "*".' AS reason + FROM + aws_iam_policy AS p + LEFT JOIN wildcard_action_policies AS w + ON p.arn = w.arn + WHERE + NOT p.is_aws_managed; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 21 IAM customer managed policies that you create should not allow wildcard actions for services \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_iam_3.yaml b/compliance/controls/aws/aws_foundational_security_iam_3.yaml old mode 100755 new mode 100644 index 4390d70c0..dc4f666fc --- a/compliance/controls/aws/aws_foundational_security_iam_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_iam_3.yaml @@ -1,14 +1,26 @@ +Description: This control checks whether the active access keys are rotated within 90 days. ID: aws_foundational_security_iam_3 -Title: "3 IAM users' access keys should be rotated every 90 days or less" -Description: "This control checks whether the active access keys are rotated within 90 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when create_date <= (current_date - interval '90' day) then 'alarm'\n else 'ok'\n end status,\n user_name || ' ' || access_key_id || ' created ' || to_char(create_date , 'DD-Mon-YYYY') ||\n ' (' || extract(day from current_timestamp - create_date) || ' days).'\n as reason\n \nfrom\n aws_iam_access_key;" - PrimaryTable: aws_iam_access_key ListOfTables: - aws_iam_access_key Parameters: [] + PrimaryTable: aws_iam_access_key + QueryToExecute: | + SELECT + 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || ' ' || access_key_id || ' created ' || TO_CHAR(create_date , 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - create_date) || ' days).' AS reason + FROM + aws_iam_access_key; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 IAM users' access keys should be rotated every 90 days or less \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_iam_4.yaml b/compliance/controls/aws/aws_foundational_security_iam_4.yaml old mode 100755 new mode 100644 index 9a4a5b144..b659fdfb8 --- a/compliance/controls/aws/aws_foundational_security_iam_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_iam_4.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether the root user access key is present. The root account is the most privileged user in an AWS account. AWS access keys provide programmatic access to a given account. ID: aws_foundational_security_iam_4 -Title: "4 IAM root user access key should not exist" -Description: "This control checks whether the root user access key is present. The root account is the most privileged user in an AWS account. AWS access keys provide programmatic access to a given account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_access_keys_present > 0 then 'alarm'\n else 'ok'\n end status,\n case\n when account_access_keys_present > 0 then 'Root user access keys exist.'\n else 'No root user access keys exist.'\n end reason\n \nfrom\n aws_iam_account_summary;" - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_access_keys_present > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN account_access_keys_present > 0 THEN 'Root user access keys exist.' + ELSE 'No root user access keys exist.' + END AS reason + FROM + aws_iam_account_summary; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 IAM root user access key should not exist \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_iam_5.yaml b/compliance/controls/aws/aws_foundational_security_iam_5.yaml old mode 100755 new mode 100644 index 9b3c081d3..bdf99366a --- a/compliance/controls/aws/aws_foundational_security_iam_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_iam_5.yaml @@ -1,14 +1,29 @@ +Description: This control checks whether AWS multi-factor authentication (MFA) is enabled for all IAM users that use a console password. ID: aws_foundational_security_iam_5 -Title: "5 MFA should be enabled for all IAM users that have a console password" -Description: "This control checks whether AWS multi-factor authentication (MFA) is enabled for all IAM users that use a console password." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when password_enabled and not mfa_active then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then user_name || ' password login disabled.'\n when password_enabled and not mfa_active then user_name || ' password login enabled but no MFA device configured.'\n else user_name || ' password login enabled and MFA device configured.'\n end as reason\n \nfrom\n aws_iam_credential_report;" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND NOT mfa_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN password_enabled AND NOT mfa_active THEN user_name || ' password login enabled but no MFA device configured.' + ELSE user_name || ' password login enabled and MFA device configured.' + END AS reason + FROM + aws_iam_credential_report; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 MFA should be enabled for all IAM users that have a console password \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_iam_8.yaml b/compliance/controls/aws/aws_foundational_security_iam_8.yaml old mode 100755 new mode 100644 index 509451ee2..d7b3b0586 --- a/compliance/controls/aws/aws_foundational_security_iam_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_iam_8.yaml @@ -1,63 +1,62 @@ +Description: This control checks whether your IAM users have passwords or active access keys that have not been used for 90 days. ID: aws_foundational_security_iam_8 -Title: "8 Unused IAM user credentials should be removed" -Description: "This control checks whether your IAM users have passwords or active access keys that have not been used for 90 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when user_name = '' - then 'info' - when password_enabled and password_last_used is null and password_last_changed < (current_date - interval '90' day) - then 'alarm' - when password_enabled and password_last_used < (current_date - interval '90' day) - then 'alarm' - when access_key_1_active and access_key_1_last_used_date is null and access_key_1_last_rotated < (current_date - interval '90' day) - then 'alarm' - when access_key_1_active and access_key_1_last_used_date < (current_date - interval '90' day) - then 'alarm' - when access_key_2_active and access_key_2_last_used_date is null and access_key_2_last_rotated < (current_date - interval '90' day) - then 'alarm' - when access_key_2_active and access_key_2_last_used_date < (current_date - interval '90' day) - then 'alarm' - else 'ok' - end status, - user_name || - case - when not password_enabled - then ' password not enabled,' - when password_enabled and password_last_used is null - then ' password created ' || to_char(password_last_changed, 'DD-Mon-YYYY') || ' never used,' - else - ' password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || ',' - end || - case - when not access_key_1_active - then ' key 1 not enabled,' - when access_key_1_active and access_key_1_last_used_date is null - then ' key 1 created ' || to_char(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' - else - ' key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' - end || - case - when not access_key_2_active - then ' key 2 not enabled.' - when access_key_2_active and access_key_2_last_used_date is null - then ' key 2 created ' || to_char(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' - else - ' key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' - end - as reason - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_name = '' + THEN 'info' + WHEN password_enabled AND password_last_used IS NULL AND password_last_changed < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN password_enabled AND password_last_used < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL AND access_key_1_last_rotated < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL AND access_key_2_last_rotated < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date < (CURRENT_DATE - INTERVAL '90' DAY) + THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || + CASE + WHEN NOT password_enabled + THEN ' password not enabled,' + WHEN password_enabled AND password_last_used IS NULL + THEN ' password created ' || TO_CHAR(password_last_changed, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_1_active + THEN ' key 1 not enabled,' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL + THEN ' key 1 created ' || TO_CHAR(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_2_active + THEN ' key 2 not enabled.' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL + THEN ' key 2 created ' || TO_CHAR(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' + ELSE + ' key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' + END + AS reason + FROM aws_iam_credential_report; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 Unused IAM user credentials should be removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_kinesis_1.yaml b/compliance/controls/aws/aws_foundational_security_kinesis_1.yaml old mode 100755 new mode 100644 index f9b8797c2..1abd315ec --- a/compliance/controls/aws/aws_foundational_security_kinesis_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_kinesis_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks if Kinesis Data Streams are encrypted at rest with server-side encryption. This control fails if a Kinesis stream is not encrypted at rest with server-side encryption. ID: aws_foundational_security_kinesis_1 -Title: "1 Kinesis Data Streams should be encrypted at rest" -Description: "This control checks if Kinesis Data Streams are encrypted at rest with server-side encryption. This control fails if a Kinesis stream is not encrypted at rest with server-side encryption." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - stream_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when encryption_type = 'KMS' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'KMS' then title || ' server side encryption enabled.' - else title || ' server side encryption disabled.' - end as reason - from - aws_kinesis_stream; - PrimaryTable: aws_kinesis_stream ListOfTables: - aws_kinesis_stream Parameters: [] + PrimaryTable: aws_kinesis_stream + QueryToExecute: | + SELECT + stream_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'KMS' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'KMS' THEN title || ' server side encryption enabled.' + ELSE title || ' server side encryption disabled.' + END AS reason + FROM + aws_kinesis_stream; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Kinesis Data Streams should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_kms_1.yaml b/compliance/controls/aws/aws_foundational_security_kms_1.yaml old mode 100755 new mode 100644 index 80f58f27d..e44be19cc --- a/compliance/controls/aws/aws_foundational_security_kms_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_kms_1.yaml @@ -1,43 +1,43 @@ +Description: Checks whether the default version of IAM customer managed policies allow principals to use the AWS KMS decryption actions on all resources. This control uses Zelkova, an automated reasoning engine, to validate and warn you about policies that may grant broad access to your secrets across AWS accounts. This control fails if the kms:Decrypt or kms:ReEncryptFrom actions are allowed on all KMS keys. The control evaluates both attached and unattached customer managed policies. It does not check inline policies or AWS managed policies. ID: aws_foundational_security_kms_1 -Title: "1 IAM customer managed policies should not allow decryption actions on all KMS keys" -Description: "Checks whether the default version of IAM customer managed policies allow principals to use the AWS KMS decryption actions on all resources. This control uses Zelkova, an automated reasoning engine, to validate and warn you about policies that may grant broad access to your secrets across AWS accounts. This control fails if the kms:Decrypt or kms:ReEncryptFrom actions are allowed on all KMS keys. The control evaluates both attached and unattached customer managed policies. It does not check inline policies or AWS managed policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with policy_with_decrypt_grant as ( - select - distinct arn - from - aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as statement - where - not is_aws_managed - and statement ->> 'Effect' = 'Allow' - and statement -> 'Resource' ?| array['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] - and statement -> 'Action' ?| array['*', 'kms:*', 'kms:decrypt', 'kms:reencryptfrom', 'kms:reencrypt*'] - ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when d.arn is null then 'ok' - else 'alarm' - end as status, - case - when d.arn is null then i.title || ' doesn''t allow decryption actions on all keys.' - else i.title || ' allows decryption actions on all keys.' - end as reason - from - aws_iam_policy i - left join policy_with_decrypt_grant d on i.arn = d.arn - where - not is_aws_managed; - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_policy Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH policy_with_decrypt_grant AS ( + SELECT + DISTINCT arn + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS statement + WHERE + NOT is_aws_managed + AND statement ->> 'Effect' = 'Allow' + AND statement -> 'Resource' ?| ARRAY['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] + AND statement -> 'Action' ?| ARRAY['*', 'kms:*', 'kms:DECRYPT', 'kms:REENCRYPTFROM', 'kms:REENCRYPT*'] + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN d.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.arn IS NULL THEN i.title || ' doesn''t allow decryption actions on all keys.' + ELSE i.title || ' allows decryption actions on all keys.' + END AS reason + FROM + aws_iam_policy i + LEFT JOIN policy_with_decrypt_grant d ON i.arn = d.arn + WHERE + NOT is_aws_managed; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 IAM customer managed policies should not allow decryption actions on all KMS keys \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_kms_3.yaml b/compliance/controls/aws/aws_foundational_security_kms_3.yaml old mode 100755 new mode 100644 index 3b41ad621..5f0fc2fd5 --- a/compliance/controls/aws/aws_foundational_security_kms_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_kms_3.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether AWS KMS customer managed keys (CMK) are scheduled for deletion. The control fails if a CMK is scheduled for deletion. CMKs cannot be recovered once deleted. Data encrypted under a KMS CMK is also permanently unrecoverable if the CMK is deleted. If meaningful data has been encrypted under a CMK scheduled for deletion, consider decrypting the data or re-encrypting the data under a new CMK unless you are intentionally performing a cryptographic erasure. ID: aws_foundational_security_kms_3 -Title: "3 AWS KMS keys should not be unintentionally deleted" -Description: "This control checks whether AWS KMS customer managed keys (CMK) are scheduled for deletion. The control fails if a CMK is scheduled for deletion. CMKs cannot be recovered once deleted. Data encrypted under a KMS CMK is also permanently unrecoverable if the CMK is deleted. If meaningful data has been encrypted under a CMK scheduled for deletion,consider decrypting the data or re-encrypting the data under a new CMK unless you are intentionally performing a cryptographic erasure." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when key_state = 'PendingDeletion' then 'alarm'\n else 'ok'\n end as status,\n case\n when key_state = 'PendingDeletion' then title || ' scheduled for deletion and will be deleted in ' || extract(day from deletion_date - current_timestamp) || ' day(s).'\n else title || ' not scheduled for deletion.'\n end as reason\n \n \nfrom\n aws_kms_key\nwhere\n key_manager = 'CUSTOMER';" - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN key_state = 'PendingDeletion' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN key_state = 'PendingDeletion' THEN title || ' scheduled for deletion and will be deleted in ' || EXTRACT(DAY FROM deletion_date - CURRENT_TIMESTAMP) || ' day(s).' + ELSE title || ' not scheduled for deletion.' + END AS reason + FROM + aws_kms_key + WHERE + key_manager = 'CUSTOMER'; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 AWS KMS keys should not be unintentionally deleted \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_lambda_1.yaml b/compliance/controls/aws/aws_foundational_security_lambda_1.yaml old mode 100755 new mode 100644 index 9b2f15a1b..20f031324 --- a/compliance/controls/aws/aws_foundational_security_lambda_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_lambda_1.yaml @@ -1,14 +1,46 @@ +Description: This control checks whether the Lambda function resource-based policy prohibits public access outside of your account. The Lambda function should not be publicly accessible, as this may allow unintended access to your code stored in the function. ID: aws_foundational_security_lambda_1 -Title: "1 Lambda function policies should prohibit public access" -Description: "This control checks whether the Lambda function resource-based policy prohibits public access outside of your account. The Lambda function should not be publicly accessible, as this may allow unintended access to your code stored in the function." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with wildcard_action_policies as (\n select\n arn,\n count(*) as statements_num\n from\n aws_lambda_function,\n jsonb_array_elements(policy_std -> 'Statement') as s\n where\n s ->> 'Effect' = 'Allow'\n and (\n ( s -> 'Principal' -> 'AWS') = '[\"*\"]'\n or s ->> 'Principal' = '*'\n )\n group by\n arn\n)\nselect\n f.arn as resource,\n f.og_account_id as og_account_id,\n f.og_resource_id as og_resource_id,\n case\n when p.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when p.arn is null then title || ' does not allow public access.'\n else title || ' contains ' || coalesce(p.statements_num,0) ||\n ' statements that allows public access.'\n end as reason\n \n \nfrom\n aws_lambda_function as f\n left join wildcard_action_policies as p on p.arn = f.arn;" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT + arn, + COUNT(*) AS statements_num + FROM + aws_lambda_function, + jsonb_array_elements(policy_std -> 'Statement') AS s + WHERE + s ->> 'Effect' = 'Allow' + AND ( + (s -> 'Principal' -> 'AWS') = '[\"*\"]' + OR s ->> 'Principal' = '*' + ) + GROUP BY + arn + ) + SELECT + f.arn AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' does not allow public access.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || ' statements that allows public access.' + END AS reason + FROM + aws_lambda_function AS f + LEFT JOIN wildcard_action_policies AS p + ON p.arn = f.arn Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Lambda function policies should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_lambda_2.yaml b/compliance/controls/aws/aws_foundational_security_lambda_2.yaml old mode 100755 new mode 100644 index f83fecfae..6d59b9d1b --- a/compliance/controls/aws/aws_foundational_security_lambda_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_lambda_2.yaml @@ -1,32 +1,32 @@ +Description: 'This control checks that the Lambda function settings for runtimes match the expected values set for the latest runtimes for each supported language. This control checks for the following runtimes: nodejs20.x, nodejs18.x, nodejs16.x, python3.12, python3.11, python3.10, python3.9, python3.8, ruby3.3, ruby3.2, java21, java17, java11, java8.al2, dotnet8, dotnet6' ID: aws_foundational_security_lambda_2 -Title: "2 Lambda functions should use supported runtimes" -Description: "This control checks that the Lambda function settings for runtimes match the expected values set for the latest runtimes for each supported language. This control checks for the following runtimes: nodejs20.x, nodejs18.x, nodejs16.x, python3.12, python3.11, python3.10, python3.9, python3.8, ruby3.3, ruby3.2, java21, java17, java11, java8.al2, dotnet8, dotnet6" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when package_type <> 'Zip' then 'skip' - when runtime like any ($1) then 'ok' - when runtime like any ($2) then 'alarm' - else 'info' - end as status, - case - when package_type <> 'Zip' then title || ' package type is ' || package_type || '.' - when runtime like any ($1) then title || ' uses latest runtime - ' || runtime || '.' - when runtime like any ($2) then title || ' uses ' || runtime || ' which is not the latest version.' - else title || ' uses runtime ' || runtime || ' which is yet to be released.' - end as reason - from - aws_lambda_function; - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN package_type <> 'Zip' THEN 'skip' + WHEN runtime LIKE ANY ($1) THEN 'ok' + WHEN runtime LIKE ANY ($2) THEN 'alarm' + ELSE 'info' + END AS status, + CASE + WHEN package_type <> 'Zip' THEN title || ' package type is ' || package_type || '.' + WHEN runtime LIKE ANY ($1) THEN title || ' uses latest runtime - ' || runtime || '.' + WHEN runtime LIKE ANY ($2) THEN title || ' uses ' || runtime || ' which is not the latest version.' + ELSE title || ' uses runtime ' || runtime || ' which is yet to be released.' + END AS reason + FROM + aws_lambda_function; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Lambda functions should use supported runtimes \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_msk_1.yaml b/compliance/controls/aws/aws_foundational_security_msk_1.yaml old mode 100755 new mode 100644 index 62a7b50a6..20a67510f --- a/compliance/controls/aws/aws_foundational_security_msk_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_msk_1.yaml @@ -1,14 +1,28 @@ +Description: This controls checks if an Amazon MSK cluster is encrypted in transit with HTTPS (TLS) among the broker nodes of the cluster. The control fails if plain text communication is enabled for a cluster broker node connection. ID: aws_foundational_security_msk_1 -Title: "1 MSK clusters should be encrypted in transit among broker nodes" -Description: "This controls checks if an Amazon MSK cluster is encrypted in transit with HTTPS (TLS) among the broker nodes of the cluster. The control fails if plain text communication is enabled for a cluster broker node connection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when provisioned -> 'EncryptionInfo' -> 'EncryptionInTransit' ->> 'ClientBroker' = 'TLS' then 'ok'\n else 'alarm'\n end as status,\n case\n when provisioned -> 'EncryptionInfo' -> 'EncryptionInTransit' ->> 'ClientBroker' = 'TLS' then title || ' encryption in transit enabled with TLS.'\n else title || ' encryption in transit enabled with plaintext.'\n end as reason\n \n \nfrom\n aws_msk_cluster;" - PrimaryTable: aws_msk_cluster ListOfTables: - aws_msk_cluster Parameters: [] + PrimaryTable: aws_msk_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN provisioned -> 'EncryptionInfo' -> 'EncryptionInTransit' ->> 'ClientBroker' = 'TLS' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN provisioned -> 'EncryptionInfo' -> 'EncryptionInTransit' ->> 'ClientBroker' = 'TLS' THEN title || ' encryption in transit enabled with TLS.' + ELSE title || ' encryption in transit enabled with plaintext.' + END AS reason + FROM + aws_msk_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 MSK clusters should be encrypted in transit among broker nodes \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_neptune_1.yaml b/compliance/controls/aws/aws_foundational_security_neptune_1.yaml old mode 100755 new mode 100644 index ef19e7345..557209768 --- a/compliance/controls/aws/aws_foundational_security_neptune_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_neptune_1.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether a Neptune DB cluster is encrypted at rest. The control fails if a Neptune DB cluster isn't encrypted at rest. ID: aws_foundational_security_neptune_1 -Title: "1 Neptune DB clusters should be encrypted at rest" -Description: "This control checks whether a Neptune DB cluster is encrypted at rest. The control fails if a Neptune DB cluster isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_neptune_db_cluster;" - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Neptune DB clusters should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_neptune_2.yaml b/compliance/controls/aws/aws_foundational_security_neptune_2.yaml old mode 100755 new mode 100644 index 25b8902a2..f586656a9 --- a/compliance/controls/aws/aws_foundational_security_neptune_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_neptune_2.yaml @@ -1,29 +1,29 @@ +Description: This control checks whether a Neptune DB cluster publishes audit logs to Amazon CloudWatch Logs. The control fails if a Neptune DB cluster doesn't publish audit logs to CloudWatch Logs. EnableCloudWatchLogsExport should be set to Audit. ID: aws_foundational_security_neptune_2 -Title: "2 Neptune DB clusters should publish audit logs to CloudWatch Logs" -Description: "This control checks whether a Neptune DB cluster publishes audit logs to Amazon CloudWatch Logs. The control fails if a Neptune DB cluster doesn't publish audit logs to CloudWatch Logs. EnableCloudWatchLogsExport should be set to Audit." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - engine, - case - when enabled_cloudwatch_logs_exports @> '["audit"]' then 'ok' - else 'alarm' - end as status, - case - when enabled_cloudwatch_logs_exports @> '["audit"]' then title || ' audit logging enabled.' - else title || ' audit logging disabled.' - end as reason - from - aws_neptune_db_cluster; - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + engine, + CASE + WHEN enabled_cloudwatch_logs_exports @> '["audit"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled_cloudwatch_logs_exports @> '["audit"]' THEN title || ' audit logging enabled.' + ELSE title || ' audit logging disabled.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Neptune DB clusters should publish audit logs to CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_neptune_3.yaml b/compliance/controls/aws/aws_foundational_security_neptune_3.yaml old mode 100755 new mode 100644 index e8506c973..b0d62c156 --- a/compliance/controls/aws/aws_foundational_security_neptune_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_neptune_3.yaml @@ -1,14 +1,29 @@ +Description: This control checks whether a Neptune manual DB cluster snapshot is public. The control fails if a Neptune manual DB cluster snapshot is public. ID: aws_foundational_security_neptune_3 -Title: "3 Neptune DB cluster snapshots should not be public" -Description: "This control checks whether a Neptune manual DB cluster snapshot is public. The control fails if a Neptune manual DB cluster snapshot is public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n db_cluster_snapshot_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end reason\n \nfrom\n aws_neptune_db_cluster_snapshot,\n jsonb_array_elements(db_cluster_snapshot_attributes) as cluster_snapshot;" - PrimaryTable: aws_neptune_db_cluster_snapshot ListOfTables: - aws_neptune_db_cluster_snapshot Parameters: [] + PrimaryTable: aws_neptune_db_cluster_snapshot + QueryToExecute: | + SELECT + db_cluster_snapshot_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cluster_snapshot -> 'AttributeValues' = '["all"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN cluster_snapshot -> 'AttributeValues' = '["all"]' THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_neptune_db_cluster_snapshot, + jsonb_array_elements(db_cluster_snapshot_attributes) AS cluster_snapshot; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Neptune DB cluster snapshots should not be public \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_neptune_4.yaml b/compliance/controls/aws/aws_foundational_security_neptune_4.yaml old mode 100755 new mode 100644 index 8504ee3bb..e93813321 --- a/compliance/controls/aws/aws_foundational_security_neptune_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_neptune_4.yaml @@ -1,28 +1,28 @@ +Description: This control checks if a Neptune DB cluster has deletion protection enabled. The control fails if a Neptune DB cluster doesn't have deletion protection enabled. ID: aws_foundational_security_neptune_4 -Title: "4 Neptune DB clusters should have deletion protection enabled" -Description: "This control checks if a Neptune DB cluster has deletion protection enabled. The control fails if a Neptune DB cluster doesn't have deletion protection enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when deletion_protection then 'ok' - else 'alarm' - end as status, - case - when deletion_protection then title || ' deletion protection enabled.' - else title || ' deletion protection disabled.' - end as reason - from - aws_neptune_db_cluster; - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN deletion_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN deletion_protection THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection disabled.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 Neptune DB clusters should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_neptune_5.yaml b/compliance/controls/aws/aws_foundational_security_neptune_5.yaml old mode 100755 new mode 100644 index 5c684b3fe..7847c1436 --- a/compliance/controls/aws/aws_foundational_security_neptune_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_neptune_5.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether a Neptune DB cluster has automated backups enabled, and a backup retention period greater than or equal to 7 days. The control fails if backups aren't enabled for the Neptune DB cluster, or if the retention period is less than 7 days. ID: aws_foundational_security_neptune_5 -Title: "5 Neptune DB clusters should have automated backups enabled" -Description: "This control checks whether a Neptune DB cluster has automated backups enabled, and a backup retention period greater than or equal to 7 days. The control fails if backups aren't enabled for the Neptune DB cluster, or if the retention period is less than 7 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when backup_retention_period >= 7 then 'ok' - else 'alarm' - end as status, - case - when backup_retention_period >= 7 then title || ' automated backups enabled.' - else title || ' automated backups disabled.' - end as reason - from - aws_neptune_db_cluster; - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN backup_retention_period >= 7 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN backup_retention_period >= 7 THEN title || ' automated backups enabled.' + ELSE title || ' automated backups disabled.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 Neptune DB clusters should have automated backups enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_neptune_6.yaml b/compliance/controls/aws/aws_foundational_security_neptune_6.yaml old mode 100755 new mode 100644 index 3635b516a..42e882a16 --- a/compliance/controls/aws/aws_foundational_security_neptune_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_neptune_6.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether a Neptune DB cluster snapshot is encrypted at rest. The control fails if a Neptune DB cluster isn't encrypted at rest. ID: aws_foundational_security_neptune_6 -Title: "6 Neptune DB cluster snapshots should be encrypted at rest" -Description: "This control checks whether a Neptune DB cluster snapshot is encrypted at rest. The control fails if a Neptune DB cluster isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n db_cluster_snapshot_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \nfrom\n aws_neptune_db_cluster_snapshot;" - PrimaryTable: aws_neptune_db_cluster_snapshot ListOfTables: - aws_neptune_db_cluster_snapshot Parameters: [] + PrimaryTable: aws_neptune_db_cluster_snapshot + QueryToExecute: | + SELECT + db_cluster_snapshot_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_neptune_db_cluster_snapshot; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 Neptune DB cluster snapshots should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_neptune_7.yaml b/compliance/controls/aws/aws_foundational_security_neptune_7.yaml old mode 100755 new mode 100644 index 3410ec2e2..1363b71bc --- a/compliance/controls/aws/aws_foundational_security_neptune_7.yaml +++ b/compliance/controls/aws/aws_foundational_security_neptune_7.yaml @@ -1,14 +1,28 @@ +Description: This control checks if a Neptune DB cluster has IAM database authentication enabled. The control fails if IAM database authentication isn't enabled for a Neptune DB cluster. ID: aws_foundational_security_neptune_7 -Title: "7 Neptune DB clusters should have IAM database authentication enabled" -Description: "This control checks if a Neptune DB cluster has IAM database authentication enabled. The control fails if IAM database authentication isn't enabled for a Neptune DB cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when iam_database_authentication_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when iam_database_authentication_enabled then title || ' IAM authentication enabled.'\n else title || ' IAM authentication disabled.'\n end as reason\n \n \nfrom\n aws_neptune_db_cluster;" - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN iam_database_authentication_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN iam_database_authentication_enabled THEN title || ' IAM authentication enabled.' + ELSE title || ' IAM authentication disabled.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 Neptune DB clusters should have IAM database authentication enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_neptune_8.yaml b/compliance/controls/aws/aws_foundational_security_neptune_8.yaml old mode 100755 new mode 100644 index c09e0d2ad..d1967e60f --- a/compliance/controls/aws/aws_foundational_security_neptune_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_neptune_8.yaml @@ -1,14 +1,28 @@ +Description: This control checks if a Neptune DB cluster is configured to copy all tags to snapshots when the snapshots are created. The control fails if a Neptune DB cluster isn't configured to copy tags to snapshots. ID: aws_foundational_security_neptune_8 -Title: "8 Neptune DB clusters should be configured to copy tags to snapshots" -Description: "This control checks if a Neptune DB cluster is configured to copy all tags to snapshots when the snapshots are created. The control fails if a Neptune DB cluster isn't configured to copy tags to snapshots." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when copy_tags_to_snapshot then 'ok'\n else 'alarm'\n end as status,\n case\n when copy_tags_to_snapshot then title || ' copy tags to snapshot enabled.'\n else title || ' copy tags to snapshot disabled.'\n end as reason\n \n \nfrom\n aws_neptune_db_cluster;" - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN copy_tags_to_snapshot THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN copy_tags_to_snapshot THEN title || ' copy tags to snapshot enabled.' + ELSE title || ' copy tags to snapshot disabled.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 Neptune DB clusters should be configured to copy tags to snapshots \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_networkfirewall_2.yaml b/compliance/controls/aws/aws_foundational_security_networkfirewall_2.yaml old mode 100755 new mode 100644 index 7f2b5e000..f498e49b4 --- a/compliance/controls/aws/aws_foundational_security_networkfirewall_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_networkfirewall_2.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether logging is enabled for an AWS Network Firewall firewall. The control fails if logging isn't enabled for at least one log type or if the logging destination doesn't exist. ID: aws_foundational_security_networkfirewall_2 -Title: "2 Network Firewall logging should be enabled" -Description: "This control checks whether logging is enabled for an AWS Network Firewall firewall. The control fails if logging isn't enabled for at least one log type or if the logging destination doesn't exist." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(logging_configuration) > 0 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(logging_configuration) > 0 then title || ' logging enabled.'\n else title || ' logging disabled.'\n end reason\n \n \nfrom\n aws_networkfirewall_firewall;" - PrimaryTable: aws_networkfirewall_firewall ListOfTables: - aws_networkfirewall_firewall Parameters: [] + PrimaryTable: aws_networkfirewall_firewall + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(logging_configuration) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(logging_configuration) > 0 THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason + FROM + aws_networkfirewall_firewall; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Network Firewall logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_networkfirewall_3.yaml b/compliance/controls/aws/aws_foundational_security_networkfirewall_3.yaml old mode 100755 new mode 100644 index ee37b2db7..03d8c35ba --- a/compliance/controls/aws/aws_foundational_security_networkfirewall_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_networkfirewall_3.yaml @@ -1,30 +1,36 @@ +Description: This control checks whether a Network Firewall policy has any stateful or stateless rule groups associated. The control fails if stateless or stateful rule groups are not assigned. ID: aws_foundational_security_networkfirewall_3 -Title: "3 Network Firewall policies should have at least one rule group associated" -Description: "This control checks whether a Network Firewall policy has any stateful or stateless rule groups associated. The control fails if stateless or stateful rule groups are not assigned." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when (firewall_policy ->> 'StatefulRuleGroupReferences' is null or jsonb_array_length(firewall_policy -> 'StatefulRuleGroupReferences') = 0) - and (firewall_policy ->> 'StatelessRuleGroupReferences' is null or jsonb_array_length(firewall_policy -> 'StatelessRuleGroupReferences') = 0) then 'alarm' - else 'ok' - end as status, - case - when (firewall_policy ->> 'StatefulRuleGroupReferences' is null or jsonb_array_length(firewall_policy -> 'StatefulRuleGroupReferences') = 0) - and (firewall_policy ->> 'StatelessRuleGroupReferences' is null or jsonb_array_length(firewall_policy -> 'StatelessRuleGroupReferences') = 0) then title || ' has no associated rule groups.' - else title || ' has associated rule groups.' - end as reason - from - aws_networkfirewall_firewall_policy; - PrimaryTable: aws_networkfirewall_firewall_policy ListOfTables: - aws_networkfirewall_firewall_policy Parameters: [] + PrimaryTable: aws_networkfirewall_firewall_policy + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (firewall_policy ->> 'StatefulRuleGroupReferences' IS NULL + OR jsonb_array_length(firewall_policy -> 'StatefulRuleGroupReferences') = 0) + AND (firewall_policy ->> 'StatelessRuleGroupReferences' IS NULL + OR jsonb_array_length(firewall_policy -> 'StatelessRuleGroupReferences') = 0) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (firewall_policy ->> 'StatefulRuleGroupReferences' IS NULL + OR jsonb_array_length(firewall_policy -> 'StatefulRuleGroupReferences') = 0) + AND (firewall_policy ->> 'StatelessRuleGroupReferences' IS NULL + OR jsonb_array_length(firewall_policy -> 'StatelessRuleGroupReferences') = 0) + THEN title || ' has no associated rule groups.' + ELSE title || ' has associated rule groups.' + END AS reason + FROM + aws_networkfirewall_firewall_policy; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Network Firewall policies should have at least one rule group associated \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_networkfirewall_4.yaml b/compliance/controls/aws/aws_foundational_security_networkfirewall_4.yaml old mode 100755 new mode 100644 index c32aefd07..055c2e1d8 --- a/compliance/controls/aws/aws_foundational_security_networkfirewall_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_networkfirewall_4.yaml @@ -1,30 +1,30 @@ +Description: A firewall policy defines how your firewall monitors and handles traffic in Amazon VPC. You configure stateless and stateful rule groups to filter packets and traffic flows. Defaulting to Pass can allow unintended traffic. ID: aws_foundational_security_networkfirewall_4 -Title: "4 The default stateless action for Network Firewall policies should be drop or forward for full packets" -Description: "A firewall policy defines how your firewall monitors and handles traffic in Amazon VPC. You configure stateless and stateful rule groups to filter packets and traffic flows. Defaulting to Pass can allow unintended traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when (not (firewall_policy -> 'StatelessDefaultActions') ? 'aws:drop' - and not (firewall_policy -> 'StatelessDefaultActions') ? 'aws:forward_to_sfe') then 'alarm' - else 'ok' - end as status, - case - when (not (firewall_policy -> 'StatelessDefaultActions') ? 'aws:drop' - and not (firewall_policy -> 'StatelessDefaultActions') ? 'aws:forward_to_sfe') then title || ' stateless action is neither drop nor forward for full packets.' - else title || ' stateless action is either drop or forward for full packets.' - end as reason - from - aws_networkfirewall_firewall_policy; - PrimaryTable: aws_networkfirewall_firewall_policy ListOfTables: - aws_networkfirewall_firewall_policy Parameters: [] + PrimaryTable: aws_networkfirewall_firewall_policy + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (NOT (firewall_policy -> 'StatelessDefaultActions') ? 'aws:drop' + AND NOT (firewall_policy -> 'StatelessDefaultActions') ? 'aws:forward_to_sfe') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (NOT (firewall_policy -> 'StatelessDefaultActions') ? 'aws:drop' + AND NOT (firewall_policy -> 'StatelessDefaultActions') ? 'aws:forward_to_sfe') THEN title || ' stateless action is neither drop nor forward for full packets.' + ELSE title || ' stateless action is either drop or forward for full packets.' + END AS reason + FROM + aws_networkfirewall_firewall_policy; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 The default stateless action for Network Firewall policies should be drop or forward for full packets \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_networkfirewall_5.yaml b/compliance/controls/aws/aws_foundational_security_networkfirewall_5.yaml old mode 100755 new mode 100644 index 4e1dc602d..a6b02691d --- a/compliance/controls/aws/aws_foundational_security_networkfirewall_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_networkfirewall_5.yaml @@ -1,30 +1,30 @@ +Description: This control checks whether the default stateless action for fragmented packets for a Network Firewall policy is drop or forward. The control passes if Drop or Forward is selected, and fails if Pass is selected. ID: aws_foundational_security_networkfirewall_5 -Title: "5 The default stateless action for Network Firewall policies should be drop or forward for fragmented packets" -Description: "This control checks whether the default stateless action for fragmented packets for a Network Firewall policy is drop or forward. The control passes if Drop or Forward is selected, and fails if Pass is selected." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when (not (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:drop' - and not (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:forward_to_sfe') then 'alarm' - else 'ok' - end as status, - case - when (not (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:drop' - and not (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:forward_to_sfe') then title || ' stateless action is neither drop nor forward for fragmented packets.' - else title || ' stateless action is either drop or forward for fragmented packets.' - end as reason - from - aws_networkfirewall_firewall_policy; - PrimaryTable: aws_networkfirewall_firewall_policy ListOfTables: - aws_networkfirewall_firewall_policy Parameters: [] + PrimaryTable: aws_networkfirewall_firewall_policy + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (NOT (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:drop' + AND NOT (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:forward_to_sfe') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (NOT (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:drop' + AND NOT (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:forward_to_sfe') THEN title || ' stateless action is neither drop nor forward for fragmented packets.' + ELSE title || ' stateless action is either drop or forward for fragmented packets.' + END AS reason + FROM + aws_networkfirewall_firewall_policy; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 The default stateless action for Network Firewall policies should be drop or forward for fragmented packets \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_networkfirewall_6.yaml b/compliance/controls/aws/aws_foundational_security_networkfirewall_6.yaml old mode 100755 new mode 100644 index 8317c258c..5a4b79db0 --- a/compliance/controls/aws/aws_foundational_security_networkfirewall_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_networkfirewall_6.yaml @@ -1,29 +1,29 @@ +Description: A rule group contains rules that define how your firewall processes traffic in your VPC. An empty stateless rule group when present in a firewall policy might give the impression that the rule group will process traffic. However, when the stateless rule group is empty, it does not process traffic. ID: aws_foundational_security_networkfirewall_6 -Title: "6 Stateless network firewall rule group should not be empty" -Description: "A rule group contains rules that define how your firewall processes traffic in your VPC. An empty stateless rule group when present in a firewall policy might give the impression that the rule group will process traffic. However, when the stateless rule group is empty, it does not process traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when type = 'STATEFUL' then 'skip' - when jsonb_array_length(rules_source -> 'StatelessRulesAndCustomActions' -> 'StatelessRules') > 0 then 'ok' - else 'alarm' - end as status, - case - when type = 'STATEFUL' then title || ' is a stateful rule group.' - else title || ' has ' || jsonb_array_length(rules_source -> 'StatelessRulesAndCustomActions' -> 'StatelessRules') || ' rule(s).' - end as reason - from - aws_networkfirewall_rule_group; - PrimaryTable: aws_networkfirewall_rule_group ListOfTables: - aws_networkfirewall_rule_group Parameters: [] + PrimaryTable: aws_networkfirewall_rule_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN type = 'STATEFUL' THEN 'skip' + WHEN jsonb_array_length(rules_source -> 'StatelessRulesAndCustomActions' -> 'StatelessRules') > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN type = 'STATEFUL' THEN title || ' is a stateful rule group.' + ELSE title || ' has ' || jsonb_array_length(rules_source -> 'StatelessRulesAndCustomActions' -> 'StatelessRules') || ' rule(s).' + END AS reason + FROM + aws_networkfirewall_rule_group; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 Stateless network firewall rule group should not be empty \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_networkfirewall_9.yaml b/compliance/controls/aws/aws_foundational_security_networkfirewall_9.yaml old mode 100755 new mode 100644 index 6d60dd85d..dbf9fd743 --- a/compliance/controls/aws/aws_foundational_security_networkfirewall_9.yaml +++ b/compliance/controls/aws/aws_foundational_security_networkfirewall_9.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an AWS Network Firewall firewall has deletion protection enabled. The control fails if deletion protection isn't enabled for a firewall. ID: aws_foundational_security_networkfirewall_9 -Title: "9 Network Firewall firewalls should have deletion protection enabled" -Description: "This control checks whether an AWS Network Firewall firewall has deletion protection enabled. The control fails if deletion protection isn't enabled for a firewall." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when delete_protection then 'ok' - else 'alarm' - end status, - case - when delete_protection then title || ' delete protection enabled.' - else title || ' delete protection disabled.' - end reason - from - aws_networkfirewall_firewall; - PrimaryTable: aws_networkfirewall_firewall ListOfTables: - aws_networkfirewall_firewall Parameters: [] + PrimaryTable: aws_networkfirewall_firewall + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN delete_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN delete_protection THEN title || ' delete protection enabled.' + ELSE title || ' delete protection disabled.' + END AS reason + FROM + aws_networkfirewall_firewall; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 Network Firewall firewalls should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_opensearch_1.yaml b/compliance/controls/aws/aws_foundational_security_opensearch_1.yaml old mode 100755 new mode 100644 index 1cec7e728..98e41a7c7 --- a/compliance/controls/aws/aws_foundational_security_opensearch_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_opensearch_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether OpenSearch domains have encryption-at-rest configuration enabled. The check fails if encryption at rest is not enabled. ID: aws_foundational_security_opensearch_1 -Title: "1 OpenSearch domains should have encryption at rest enabled" -Description: "This control checks whether OpenSearch domains have encryption-at-rest configuration enabled. The check fails if encryption at rest is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when encryption_at_rest_options ->> 'Enabled' = 'false' then 'alarm' - else 'ok' - end status, - case - when encryption_at_rest_options ->> 'Enabled' = 'false' then title || ' encryption at rest disabled.' - else title || ' encryption at rest enabled.' - end reason - from - aws_opensearch_domain; - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encryption_at_rest_options ->> 'Enabled' = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption_at_rest_options ->> 'Enabled' = 'false' THEN title || ' encryption at rest disabled.' + ELSE title || ' encryption at rest enabled.' + END AS reason + FROM + aws_opensearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 OpenSearch domains should have encryption at rest enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_opensearch_10.yaml b/compliance/controls/aws/aws_foundational_security_opensearch_10.yaml old mode 100755 new mode 100644 index 82ca6836f..eeb635b46 --- a/compliance/controls/aws/aws_foundational_security_opensearch_10.yaml +++ b/compliance/controls/aws/aws_foundational_security_opensearch_10.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an Amazon OpenSearch Service domain has the latest software update installed. The control fails if a software update is available but not installed for the domain. ID: aws_foundational_security_opensearch_10 -Title: "10 OpenSearch domains should have the latest software update installed" -Description: "This control checks whether an Amazon OpenSearch Service domain has the latest software update installed. The control fails if a software update is available but not installed for the domain." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when service_software_options ->> 'UpdateAvailable' = 'false' then 'ok'\n else 'alarm'\n end status,\n case\n when service_software_options ->> 'UpdateAvailable' = 'false' then title || ' updated with latest service software version.'\n else title || ' not updated with latest service software version.'\n end reason\n \n \nfrom\n aws_opensearch_domain;" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN service_software_options ->> 'UpdateAvailable' = 'false' THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN service_software_options ->> 'UpdateAvailable' = 'false' THEN title || ' updated with latest service software version.' + ELSE title || ' not updated with latest service software version.' + END reason + FROM + aws_opensearch_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 10 OpenSearch domains should have the latest software update installed \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_opensearch_2.yaml b/compliance/controls/aws/aws_foundational_security_opensearch_2.yaml old mode 100755 new mode 100644 index 0e6ca5e44..2cf8b6e47 --- a/compliance/controls/aws/aws_foundational_security_opensearch_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_opensearch_2.yaml @@ -1,51 +1,51 @@ +Description: This control checks whether OpenSearch domains are in a VPC. It does not evaluate the VPC subnet routing configuration to determine public access. ID: aws_foundational_security_opensearch_2 -Title: "2 OpenSearch domains should not be publicly accessible" -Description: "This control checks whether OpenSearch domains are in a VPC. It does not evaluate the VPC subnet routing configuration to determine public access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with public_subnets as ( - select - distinct a -> 'SubnetId' as SubnetId - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a, - jsonb_array_elements(routes) as r - where - r ->> 'DestinationCidrBlock' = '0.0.0.0/0' - and r ->> 'GatewayId' like 'igw-%' - ), opensearch_domain_with_public_subnet as ( - select - arn - from - aws_opensearch_domain , - jsonb_array_elements(vpc_options -> 'SubnetIds') as s - where - s in (select SubnetId from public_subnets) - ) - select - d.arn as resource, - d.og_account_id as og_account_id, - d.og_resource_id as og_resource_id, - case - when d.vpc_options ->> 'VPCId' is null then 'alarm' - when d.vpc_options ->> 'VPCId' is not null and p.arn is not null then 'alarm' - else 'ok' - end status, - case - when vpc_options ->> 'VPCId' is null then title || ' not in VPC.' - when d.vpc_options ->> 'VPCId' is not null and p.arn is not null then title || ' attached to public subnet.' - else title || ' in VPC ' || (vpc_options ->> 'VPCId') || '.' - end reason - from - aws_opensearch_domain as d - left join opensearch_domain_with_public_subnet as p on d.arn = p.arn; - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_vpc_route_table - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + WITH public_subnets AS ( + SELECT + DISTINCT a -> 'SubnetId' AS SubnetId + FROM + aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE + r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND r ->> 'GatewayId' LIKE 'igw-%' + ), opensearch_domain_with_public_subnet AS ( + SELECT + arn + FROM + aws_opensearch_domain, + jsonb_array_elements(vpc_options -> 'SubnetIds') AS s + WHERE + s IN (SELECT SubnetId FROM public_subnets) + ) + SELECT + d.arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN d.vpc_options ->> 'VPCId' IS NULL THEN 'alarm' + WHEN d.vpc_options ->> 'VPCId' IS NOT NULL AND p.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN vpc_options ->> 'VPCId' IS NULL THEN title || ' not in VPC.' + WHEN d.vpc_options ->> 'VPCId' IS NOT NULL AND p.arn IS NOT NULL THEN title || ' attached to public subnet.' + ELSE title || ' in VPC ' || (vpc_options ->> 'VPCId') || '.' + END reason + FROM + aws_opensearch_domain AS d + LEFT JOIN opensearch_domain_with_public_subnet AS p ON d.arn = p.arn; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 OpenSearch domains should not be publicly accessible \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_opensearch_3.yaml b/compliance/controls/aws/aws_foundational_security_opensearch_3.yaml old mode 100755 new mode 100644 index f858252a4..f43359ebb --- a/compliance/controls/aws/aws_foundational_security_opensearch_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_opensearch_3.yaml @@ -1,30 +1,33 @@ +Description: This control checks whether OpenSearch domains have node-to-node encryption enabled. This control fails if node-to-node encryption is disabled on the domain. ID: aws_foundational_security_opensearch_3 -Title: "3 OpenSearch domains should encrypt data sent between nodes" -Description: "This control checks whether OpenSearch domains have node-to-node encryption enabled. This control fails if node-to-node encryption is disabled on the domain." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) then 'skip' - when node_to_node_encryption_options_enabled then 'ok' - else 'alarm' - end as status, - case - when region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) then title || ' node-to-node encryption not supported in ' || region || '.' - when node_to_node_encryption_options_enabled then title || ' node-to-node encryption enabled.' - else title || ' node-to-node encryption disabled.' - end as reason - from - aws_opensearch_domain; - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) THEN 'skip' + WHEN node_to_node_encryption_options_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) THEN + title || ' node-to-node encryption not supported in ' || region || '.' + WHEN node_to_node_encryption_options_enabled THEN + title || ' node-to-node encryption enabled.' + ELSE + title || ' node-to-node encryption disabled.' + END AS reason + FROM + aws_opensearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 OpenSearch domains should encrypt data sent between nodes \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_opensearch_4.yaml b/compliance/controls/aws/aws_foundational_security_opensearch_4.yaml old mode 100755 new mode 100644 index 79f7b2b37..90fc764a0 --- a/compliance/controls/aws/aws_foundational_security_opensearch_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_opensearch_4.yaml @@ -1,14 +1,76 @@ +Description: This control checks whether OpenSearch domains are configured to send error logs to CloudWatch Logs. This control fails if error logging to CloudWatch is not enabled for a domain. ID: aws_foundational_security_opensearch_4 -Title: "4 OpenSearch domain error logging to CloudWatch Logs should be enabled" -Description: "This control checks whether OpenSearch domains are configured to send error logs to CloudWatch Logs. This control fails if error logging to CloudWatch is not enabled for a domain." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_publishing_options is null then 'alarm'\n when\n ( log_publishing_options -> 'AUDIT_LOGS' is null\n or log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'INDEX_SLOW_LOGS' is null\n or log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'SEARCH_SLOW_LOGS' is null\n or log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'ES_APPLICATION_LOGS' is null\n or log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n then 'ok'\n else 'alarm'\n end as status,\n case\n when log_publishing_options is null then title || ' logging not enabled.'\n when\n ( log_publishing_options -> 'AUDIT_LOGS' is null\n or log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'INDEX_SLOW_LOGS' is null\n or log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'SEARCH_SLOW_LOGS' is null\n or log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'ES_APPLICATION_LOGS' is null\n or log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n ) then title || ' send logs to AWS CloudWatch.'\n else title || ' does not send logs to AWS CloudWatch.'\n end as reason\n \n \nfrom\n aws_opensearch_domain;" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_publishing_options IS NULL THEN 'alarm' + WHEN + (log_publishing_options -> 'AUDIT_LOGS' IS NULL + OR log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'INDEX_SLOW_LOGS' IS NULL + OR log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'SEARCH_SLOW_LOGS' IS NULL + OR log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'ES_APPLICATION_LOGS' IS NULL + OR log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_publishing_options IS NULL THEN title || ' logging not enabled.' + WHEN + (log_publishing_options -> 'AUDIT_LOGS' IS NULL + OR log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'INDEX_SLOW_LOGS' IS NULL + OR log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'SEARCH_SLOW_LOGS' IS NULL + OR log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'ES_APPLICATION_LOGS' IS NULL + OR log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) THEN title || ' send logs to AWS CloudWatch.' + ELSE title || ' does not send logs to AWS CloudWatch.' + END AS reason + FROM + aws_opensearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 OpenSearch domain error logging to CloudWatch Logs should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_opensearch_5.yaml b/compliance/controls/aws/aws_foundational_security_opensearch_5.yaml old mode 100755 new mode 100644 index 08b01b72b..9a8bb1a97 --- a/compliance/controls/aws/aws_foundational_security_opensearch_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_opensearch_5.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether OpenSearch domains have audit logging enabled. This control fails if an OpenSearch domain does not have audit logging enabled. ID: aws_foundational_security_opensearch_5 -Title: "5 OpenSearch domains should have audit logging enabled" -Description: "This control checks whether OpenSearch domains have audit logging enabled. This control fails if an OpenSearch domain does not have audit logging enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_publishing_options -> 'AUDIT_LOGS' ->> 'Enabled' = 'true' then 'ok'\n else 'ok'\n end as status,\n case\n when log_publishing_options -> 'AUDIT_LOGS' ->> 'Enabled' = 'true' then title || ' audit logging enabled.'\n else title || ' audit logging disabled.'\n end as reason\n \n \nfrom\n aws_opensearch_domain;" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_publishing_options -> 'AUDIT_LOGS' ->> 'Enabled' = 'true' THEN 'ok' + ELSE 'ok' + END AS status, + CASE + WHEN log_publishing_options -> 'AUDIT_LOGS' ->> 'Enabled' = 'true' THEN title || ' audit logging enabled.' + ELSE title || ' audit logging disabled.' + END AS reason + FROM + aws_opensearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 OpenSearch domains should have audit logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_opensearch_6.yaml b/compliance/controls/aws/aws_foundational_security_opensearch_6.yaml old mode 100755 new mode 100644 index f7c98431a..fda0e0774 --- a/compliance/controls/aws/aws_foundational_security_opensearch_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_opensearch_6.yaml @@ -1,14 +1,42 @@ +Description: This control checks whether OpenSearch domains are configured with at least three data nodes and zoneAwarenessEnabled is true. This control fails for an OpenSearch domain if instanceCount is less than 3 or zoneAwarenessEnabled is false. ID: aws_foundational_security_opensearch_6 -Title: "6 OpenSearch domains should have at least three data nodes" -Description: "This control checks whether OpenSearch domains are configured with at least three data nodes and zoneAwarenessEnabled is true. This control fails for an OpenSearch domain if instanceCount is less than 3 or zoneAwarenessEnabled is false." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when cluster_config ->> 'ZoneAwarenessEnabled' = 'true' and cluster_config ->> 'InstanceCount' > '2' then 'ok'\n else 'alarm'\n end as status,\n case\n when cluster_config ->> 'ZoneAwarenessEnabled' = 'true' and cluster_config ->> 'InstanceCount' > '2' then title || ' zone awareness is '\n || case when cluster_config ->> 'ZoneAwarenessEnabled' = 'true' then 'enabled' else 'disabled' end || ' with ' || (cluster_config ->> 'InstanceCount') || ' data node(s) configued.'\n else title || ' zone awareness is ' || case when cluster_config ->> 'ZoneAwarenessEnabled' = 'true' then 'enabled' else 'disabled' end || ' with ' || (cluster_config ->> 'InstanceCount') || ' data node(s) configued.'\n end as reason\n \n \nfrom\n aws_opensearch_domain;" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cluster_config ->> 'ZoneAwarenessEnabled' = 'true' + AND cluster_config ->> 'InstanceCount' > '2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cluster_config ->> 'ZoneAwarenessEnabled' = 'true' + AND cluster_config ->> 'InstanceCount' > '2' THEN + title || ' zone awareness is ' || + CASE + WHEN cluster_config ->> 'ZoneAwarenessEnabled' = 'true' + THEN 'enabled' + ELSE 'disabled' + END || ' with ' || (cluster_config ->> 'InstanceCount') || ' data node(s) configured.' + ELSE + title || ' zone awareness is ' || + CASE + WHEN cluster_config ->> 'ZoneAwarenessEnabled' = 'true' + THEN 'enabled' + ELSE 'disabled' + END || ' with ' || (cluster_config ->> 'InstanceCount') || ' data node(s) configured.' + END AS reason + FROM + aws_opensearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 OpenSearch domains should have at least three data nodes \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_opensearch_7.yaml b/compliance/controls/aws/aws_foundational_security_opensearch_7.yaml old mode 100755 new mode 100644 index 69aa49916..c046626ff --- a/compliance/controls/aws/aws_foundational_security_opensearch_7.yaml +++ b/compliance/controls/aws/aws_foundational_security_opensearch_7.yaml @@ -1,28 +1,32 @@ +Description: This control checks whether OpenSearch domains have fine-grained access control enabled. The control fails if the fine-grained access control is not enabled. Fine-grained access control requires advanced-security-options in the OpenSearch parameter update-domain-config to be enabled. ID: aws_foundational_security_opensearch_7 -Title: "7 OpenSearch domains should have fine-grained access control enabled" -Description: "This control checks whether OpenSearch domains have fine-grained access control enabled. The control fails if the fine-grained access control is not enabled. Fine-grained access control requires advanced-security-optionsin the OpenSearch parameter update-domain-config to be enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when advanced_security_options is null or not (advanced_security_options -> 'Enabled')::boolean then 'alarm' - else 'ok' - end as status, - case - when advanced_security_options is null or not (advanced_security_options -> 'Enabled')::boolean then title || ' has fine-grained access control disabled.' - else title || ' has fine-grained access control enabled.' - end as reason - from - aws_opensearch_domain; - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN advanced_security_options IS NULL + OR NOT (advanced_security_options -> 'Enabled')::boolean + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN advanced_security_options IS NULL + OR NOT (advanced_security_options -> 'Enabled')::boolean + THEN title || ' has fine-grained access control disabled.' + ELSE title || ' has fine-grained access control enabled.' + END AS reason + FROM + aws_opensearch_domain; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 OpenSearch domains should have fine-grained access control enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_opensearch_8.yaml b/compliance/controls/aws/aws_foundational_security_opensearch_8.yaml old mode 100755 new mode 100644 index 441b361fc..09c5dde9a --- a/compliance/controls/aws/aws_foundational_security_opensearch_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_opensearch_8.yaml @@ -1,14 +1,34 @@ +Description: This control checks whether connections to OpenSearch domains are required to use TLS 1.2. The check fails if the OpenSearch domain TLSSecurityPolicy is not Policy-Min-TLS-1-2-2019-07. ID: aws_foundational_security_opensearch_8 -Title: "8 Connections to OpenSearch domains should be encrypted using TLS 1.2" -Description: "This control checks whether connections to OpenSearch domains are required to use TLS 1.2. The check fails if the OpenSearch domain TLSSecurityPolicy is not Policy-Min-TLS-1-2-2019-07." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when (domain_endpoint_options ->> 'EnforceHTTPS' = 'false') or (domain_endpoint_options ->> 'EnforceHTTPS' = 'true' and domain_endpoint_options ->> 'TLSSecurityPolicy' not in ('tlsPolicies')) then 'alarm'\n else 'ok'\n end status,\n case\n when (domain_endpoint_options ->> 'EnforceHTTPS' = 'false') or (domain_endpoint_options ->> 'EnforceHTTPS' = 'true' and domain_endpoint_options ->> 'TLSSecurityPolicy' not in ('tlsPolicies')) then title || ' does not use HTTPS.'\n else title || ' uses HTTPS.'\n end as reason\n \n \nfrom\n aws_opensearch_domain;" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (domain_endpoint_options ->> 'EnforceHTTPS' = 'false') OR + (domain_endpoint_options ->> 'EnforceHTTPS' = 'true' AND + domain_endpoint_options ->> 'TLSSecurityPolicy' NOT IN ('tlsPolicies')) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (domain_endpoint_options ->> 'EnforceHTTPS' = 'false') OR + (domain_endpoint_options ->> 'EnforceHTTPS' = 'true' AND + domain_endpoint_options ->> 'TLSSecurityPolicy' NOT IN ('tlsPolicies')) + THEN title || ' does not use HTTPS.' + ELSE title || ' uses HTTPS.' + END AS reason + FROM + aws_opensearch_domain; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 Connections to OpenSearch domains should be encrypted using TLS 1.2 \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_pca_1.yaml b/compliance/controls/aws/aws_foundational_security_pca_1.yaml old mode 100755 new mode 100644 index 6294eb593..4dc27a647 --- a/compliance/controls/aws/aws_foundational_security_pca_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_pca_1.yaml @@ -1,30 +1,30 @@ +Description: This control checks if AWS Private CA has a root certificate authority (CA) that is disabled. The control fails if the root CA is enabled. ID: aws_foundational_security_pca_1 -Title: "1 AWS Private CA root certificate authority should be disabled" -Description: "This control checks if AWS Private CA has a root certificate authority (CA) that is disabled. The control fails if the root CA is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when type <> 'ROOT' then 'skip' - when status = 'DISABLED' then 'ok' - else 'alarm' - end as status, - case - when type <> 'ROOT' then title || ' is not root CA.' - when status = 'DISABLED' then title || ' root CA disabled.' - else title || ' root CA not disabled.' - end as reason - from - aws_acmpca_certificate_authority; - PrimaryTable: aws_acmpca_certificate_authority ListOfTables: - aws_acmpca_certificate_authority Parameters: [] + PrimaryTable: aws_acmpca_certificate_authority + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN type <> 'ROOT' THEN 'skip' + WHEN status = 'DISABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN type <> 'ROOT' THEN title || ' is not root CA.' + WHEN status = 'DISABLED' THEN title || ' root CA disabled.' + ELSE title || ' root CA not disabled.' + END AS reason + FROM + aws_acmpca_certificate_authority; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 AWS Private CA root certificate authority should be disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_10.yaml b/compliance/controls/aws/aws_foundational_security_rds_10.yaml old mode 100755 new mode 100644 index 5da8b6d0d..a151a7598 --- a/compliance/controls/aws/aws_foundational_security_rds_10.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_10.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an RDS DB instance has IAM database authentication enabled. IAM database authentication allows authentication to database instances with an authentication token instead of a password. Network traffic to and from the database is encrypted using SSL. ID: aws_foundational_security_rds_10 -Title: "10 IAM authentication should be configured for RDS instances" -Description: "This control checks whether an RDS DB instance has IAM database authentication enabled IAM database authentication allows authentication to database instances with an authentication token instead of a password. Network traffic to and from the database is encrypted using SSL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when iam_database_authentication_enabled then 'ok' - else 'alarm' - end as status, - case - when iam_database_authentication_enabled then title || ' IAM authentication enabled.' - else title || ' IAM authentication not enabled.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN iam_database_authentication_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN iam_database_authentication_enabled THEN title || ' IAM authentication enabled.' + ELSE title || ' IAM authentication not enabled.' + END AS reason + FROM + aws_rds_db_instance; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 10 IAM authentication should be configured for RDS instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_11.yaml b/compliance/controls/aws/aws_foundational_security_rds_11.yaml old mode 100755 new mode 100644 index a0bc2ca3a..a212379a1 --- a/compliance/controls/aws/aws_foundational_security_rds_11.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_11.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether Amazon Relational Database Service instances have automated backups enabled and the backup retention period is greater than or equal to seven days. The control fails if backups are not enabled, and if the retention period is less than 7 days. ID: aws_foundational_security_rds_11 -Title: "11 RDS instances should have automatic backups enabled" -Description: "This control checks whether Amazon Relational Database Service instances have automated backups enabled and the backup retention period is greater than or equal to seven days. The control fails if backups are not enabled, and if the retention period is less than 7 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when backup_retention_period < 1 then 'alarm' - else 'ok' - end as status, - case - when backup_retention_period < 1 then title || ' backups not enabled.' - else title || ' backups enabled.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN backup_retention_period < 1 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN backup_retention_period < 1 THEN title || ' backups not enabled.' + ELSE title || ' backups enabled.' + END AS reason + FROM + aws_rds_db_instance; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 11 RDS instances should have automatic backups enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_12.yaml b/compliance/controls/aws/aws_foundational_security_rds_12.yaml old mode 100755 new mode 100644 index 765cab1d6..2e2ad4384 --- a/compliance/controls/aws/aws_foundational_security_rds_12.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_12.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an RDS DB cluster has IAM database authentication enabled. IAM database authentication allows for password-free authentication to database instances. The authentication uses an authentication token. Network traffic to and from the database is encrypted using SSL. ID: aws_foundational_security_rds_12 -Title: "12 IAM authentication should be configured for RDS clusters" -Description: "This control checks whether an RDS DB cluster has IAM database authentication enabled. IAM database authentication allows for password-free authentication to database instances. The authentication uses an authentication token. Network traffic to and from the database is encrypted using SSL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when iam_database_authentication_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when iam_database_authentication_enabled then title || ' IAM authentication enabled.'\n else title || ' IAM authentication not enabled.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster;" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN iam_database_authentication_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN iam_database_authentication_enabled THEN title || ' IAM authentication enabled.' + ELSE title || ' IAM authentication not enabled.' + END AS reason + FROM + aws_rds_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 12 IAM authentication should be configured for RDS clusters \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_13.yaml b/compliance/controls/aws/aws_foundational_security_rds_13.yaml old mode 100755 new mode 100644 index 38fefeb40..ff4b0ea9a --- a/compliance/controls/aws/aws_foundational_security_rds_13.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_13.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether automatic minor version upgrades are enabled for the RDS database instance. Enabling automatic minor version upgrades ensures that the latest minor version updates to the relational database management system (RDBMS) are installed. These upgrades might include security patches and bug fixes. Keeping up to date with patch installation is an important step in securing systems. ID: aws_foundational_security_rds_13 -Title: "13 RDS automatic minor version upgrades should be enabled" -Description: "This control checks whether automatic minor version upgrades are enabled for the RDS database instance. Enabling automatic minor version upgrades ensures that the latest minor version updates to the relational database management system (RDBMS) are installed. These upgrades might include security patches and bug fixes. Keeping up to date with patch installation is an important step in securing systems." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when auto_minor_version_upgrade then 'ok' - else 'alarm' - end as status, - case - when auto_minor_version_upgrade then title || ' automatic minor version upgrades enabled.' - else title || ' automatic minor version upgrades not enabled.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrades enabled.' + ELSE title || ' automatic minor version upgrades not enabled.' + END AS reason + FROM + aws_rds_db_instance; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 13 RDS automatic minor version upgrades should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_14.yaml b/compliance/controls/aws/aws_foundational_security_rds_14.yaml old mode 100755 new mode 100644 index f1d329843..73ac13526 --- a/compliance/controls/aws/aws_foundational_security_rds_14.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_14.yaml @@ -1,30 +1,30 @@ +Description: This control checks whether Amazon Aurora clusters have backtracking enabled. Backups help you to recover more quickly from a security incident. They also strengthen the resilience of your systems. Aurora backtracking reduces the time to recover a database to a point in time. It does not require a database restore to do so. ID: aws_foundational_security_rds_14 -Title: "14 Amazon Aurora clusters should have backtracking enabled" -Description: "This control checks whether Amazon Aurora clusters have backtracking enabled. Backups help you to recover more quickly from a security incident. They also strengthens the resilience of your systems. Aurora backtracking reduces the time to recover a database to a point in time. It does not require a database restore to so." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when engine not ilike '%aurora-mysql%' then 'skip' - when backtrack_window is not null then 'ok' - else 'alarm' - end as status, - case - when engine not ilike '%aurora-mysql%' then title || ' not Aurora MySQL-compatible edition.' - when backtrack_window is not null then title || ' backtracking enabled.' - else title || ' backtracking not enabled.' - end as reason - from - aws_rds_db_cluster; - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine NOT ILIKE '%aurora-mysql%' THEN 'skip' + WHEN backtrack_window IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine NOT ILIKE '%aurora-mysql%' THEN title || ' not Aurora MySQL-compatible edition.' + WHEN backtrack_window IS NOT NULL THEN title || ' backtracking enabled.' + ELSE title || ' backtracking not enabled.' + END AS reason + FROM + aws_rds_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 14 Amazon Aurora clusters should have backtracking enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_15.yaml b/compliance/controls/aws/aws_foundational_security_rds_15.yaml old mode 100755 new mode 100644 index dcd41b07c..1597344ff --- a/compliance/controls/aws/aws_foundational_security_rds_15.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_15.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether high availability is enabled for your RDS DB clusters. RDS DB clusters should be configured for multiple Availability Zones to ensure availability of the data that is stored. ID: aws_foundational_security_rds_15 -Title: "15 RDS DB clusters should be configured for multiple Availability Zones" -Description: "This control checks whether high availability is enabled for your RDS DB clusters. RDS DB clusters should be configured for multiple Availability Zones to ensure availability of the data that is stored." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when multi_az then 'ok'\n else 'alarm'\n end as status,\n case\n when multi_az then title || ' Multi-AZ enabled.'\n else title || ' Multi-AZ disabled.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster;" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN multi_az THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN multi_az THEN title || ' Multi-AZ enabled.' + ELSE title || ' Multi-AZ disabled.' + END AS reason + FROM + aws_rds_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 15 RDS DB clusters should be configured for multiple Availability Zones \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_16.yaml b/compliance/controls/aws/aws_foundational_security_rds_16.yaml old mode 100755 new mode 100644 index d25ad8c71..e0e05233f --- a/compliance/controls/aws/aws_foundational_security_rds_16.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_16.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether RDS DB clusters are configured to copy all tags to snapshots when the snapshots are created. ID: aws_foundational_security_rds_16 -Title: "16 RDS DB clusters should be configured to copy tags to snapshots" -Description: "This control checks whether RDS DB clusters are configured to copy all tags to snapshots when the snapshots are created." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when copy_tags_to_snapshot then 'ok'\n else 'alarm'\n end as status,\n case\n when copy_tags_to_snapshot then title || ' copy tags to snapshot enabled.'\n else title || ' copy tags to snapshot disabled.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster;" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN copy_tags_to_snapshot THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN copy_tags_to_snapshot THEN title || ' copy tags to snapshot enabled.' + ELSE title || ' copy tags to snapshot disabled.' + END AS reason + FROM + aws_rds_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 16 RDS DB clusters should be configured to copy tags to snapshots \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_17.yaml b/compliance/controls/aws/aws_foundational_security_rds_17.yaml old mode 100755 new mode 100644 index 7a4e75e17..10cb59946 --- a/compliance/controls/aws/aws_foundational_security_rds_17.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_17.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether RDS DB instances are configured to copy all tags to snapshots when the snapshots are created. ID: aws_foundational_security_rds_17 -Title: "17 RDS DB instances should be configured to copy tags to snapshots" -Description: "This control checks whether RDS DB instances are configured to copy all tags to snapshots when the snapshots are created." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when copy_tags_to_snapshot then 'ok' - else 'alarm' - end as status, - case - when copy_tags_to_snapshot then title || ' copy tags to snapshot enabled.' - else title || ' copy tags to snapshot disabled.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN copy_tags_to_snapshot THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN copy_tags_to_snapshot THEN title || ' copy tags to snapshot enabled.' + ELSE title || ' copy tags to snapshot disabled.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 17 RDS DB instances should be configured to copy tags to snapshots \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_18.yaml b/compliance/controls/aws/aws_foundational_security_rds_18.yaml old mode 100755 new mode 100644 index 241912b2b..ac2906add --- a/compliance/controls/aws/aws_foundational_security_rds_18.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_18.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an RDS instance is deployed in a VPC (EC2-VPC). ID: aws_foundational_security_rds_18 -Title: "18 RDS instances should be deployed in a VPC" -Description: "This control checks whether an RDS instance is deployed in a VPC (EC2-VPC)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when vpc_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when vpc_id is null then title || ' is not in VPC.'\n else title || ' is in VPC ' || vpc_id || '.'\n end as reason\n \n \nfrom\n aws_rds_db_instance;" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vpc_id IS NULL THEN title || ' is not in VPC.' + ELSE title || ' is in VPC ' || vpc_id || '.' + END AS reason + FROM + aws_rds_db_instance; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 18 RDS instances should be deployed in a VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_19.yaml b/compliance/controls/aws/aws_foundational_security_rds_19.yaml old mode 100755 new mode 100644 index 3c29172d6..4f46c85ec --- a/compliance/controls/aws/aws_foundational_security_rds_19.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_19.yaml @@ -1,14 +1,37 @@ +Description: This control checks whether an Amazon RDS event subscription exists that has notifications enabled for the following source type, event category key-value pairs. ID: aws_foundational_security_rds_19 -Title: "19 Existing RDS event notification subscriptions should be configured for critical cluster events." -Description: "This control checks whether an Amazon RDS event subscription exists that has notifications enabled for the following source type, event category key-value pairs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when source_type <> 'db-cluster' then 'skip'\n when source_type = 'db-cluster' and enabled and event_categories_list @> '[\"failure\", \"maintenance\"]' then 'ok'\n else 'alarm'\n end as status,\n case\n when source_type <> 'db-cluster' then cust_subscription_id || ' event subscription of ' || source_type || ' type.'\n when source_type = 'db-cluster' and enabled and event_categories_list @> '[\"failure\", \"maintenance\"]' then cust_subscription_id || ' event subscription enabled for critical db cluster events.'\n else cust_subscription_id || ' event subscription missing critical db cluster events.'\n end as reason\n \nfrom\n aws_rds_db_event_subscription;" - PrimaryTable: aws_rds_db_event_subscription ListOfTables: - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_rds_db_event_subscription + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN source_type <> 'db-cluster' THEN 'skip' + WHEN source_type = 'db-cluster' + AND enabled + AND event_categories_list @> '["failure", "maintenance"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN source_type <> 'db-cluster' THEN + cust_subscription_id || ' event subscription of ' || source_type || ' type.' + WHEN source_type = 'db-cluster' + AND enabled + AND event_categories_list @> '["failure", "maintenance"]' THEN + cust_subscription_id || ' event subscription enabled for critical db cluster events.' + ELSE + cust_subscription_id || ' event subscription missing critical db cluster events.' + END AS reason + FROM + aws_rds_db_event_subscription; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 19 Existing RDS event notification subscriptions should be configured for critical cluster events. \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_2.yaml b/compliance/controls/aws/aws_foundational_security_rds_2.yaml old mode 100755 new mode 100644 index 46227c138..716bc6fac --- a/compliance/controls/aws/aws_foundational_security_rds_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_2.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether Amazon RDS instances are publicly accessible by evaluating the PubliclyAccessible field in the instance configuration item. Neptune DB instances and Amazon DocumentDB clusters do not have the PubliclyAccessible flag and cannot be evaluated. However, this control can still generate findings for these resources. You can suppress these findings. ID: aws_foundational_security_rds_2 -Title: "2 RDS DB instances should prohibit public access, determined by the PubliclyAccessible configuration" -Description: "This control checks whether Amazon RDS instances are publicly accessible by evaluating the PubliclyAccessible field in the instance configuration item. Neptune DB instances and Amazon DocumentDB clusters do not have the PubliclyAccessible flag and cannot be evaluated. However, this control can still generate findings for these resources. You can suppress these findings." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when publicly_accessible then 'alarm' - else 'ok' - end status, - case - when publicly_accessible then title || ' publicly accessible.' - else title || ' not publicly accessible.' - end reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_rds_db_instance; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 RDS DB instances should prohibit public access, determined by the PubliclyAccessible configuration \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_20.yaml b/compliance/controls/aws/aws_foundational_security_rds_20.yaml old mode 100755 new mode 100644 index c86c19610..f1257cf5f --- a/compliance/controls/aws/aws_foundational_security_rds_20.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_20.yaml @@ -1,30 +1,34 @@ +Description: This control checks whether an Amazon RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs. ID: aws_foundational_security_rds_20 -Title: "20 Existing RDS event notification subscriptions should be configured for critical database instance events" -Description: "This control checks whether an Amazon RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when source_type <> 'db-instance' then 'skip' - when source_type = 'db-instance' and enabled and event_categories_list @> '["failure", "maintenance", "configuration change"]' then 'ok' - else 'alarm' - end as status, - case - when source_type <> 'db-instance' then cust_subscription_id || ' event subscription of ' || source_type || ' type.' - when source_type like 'db-instance' and enabled and event_categories_list @> '["failure", "maintenance", "configuration change"]' then cust_subscription_id || ' event subscription enabled for critical instance events.' - else cust_subscription_id || ' event subscription missing critical instance events.' - end as reason - from - aws_rds_db_event_subscription; - PrimaryTable: aws_rds_db_event_subscription ListOfTables: - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_rds_db_event_subscription + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN source_type <> 'db-instance' THEN 'skip' + WHEN source_type = 'db-instance' + AND enabled + AND event_categories_list @> '["failure", "maintenance", "configuration change"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN source_type <> 'db-instance' THEN cust_subscription_id || ' event subscription of ' || source_type || ' type.' + WHEN source_type LIKE 'db-instance' + AND enabled + AND event_categories_list @> '["failure", "maintenance", "configuration change"]' THEN cust_subscription_id || ' event subscription enabled for critical instance events.' + ELSE cust_subscription_id || ' event subscription missing critical instance events.' + END AS reason + FROM + aws_rds_db_event_subscription; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 20 Existing RDS event notification subscriptions should be configured for critical database instance events \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_21.yaml b/compliance/controls/aws/aws_foundational_security_rds_21.yaml old mode 100755 new mode 100644 index c95b66411..5838d4f32 --- a/compliance/controls/aws/aws_foundational_security_rds_21.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_21.yaml @@ -1,30 +1,33 @@ +Description: This control checks whether an Amazon RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs. ID: aws_foundational_security_rds_21 -Title: "21 An RDS event notifications subscription should be configured for critical database parameter group events" -Description: "This control checks whether an Amazon RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when source_type <> 'db-parameter-group' then 'skip' - when source_type = 'db-parameter-group' and enabled and event_categories_list @> '["maintenance", "failure"]' then 'ok' - else 'alarm' - end as status, - case - when source_type <> 'db-parameter-group' then cust_subscription_id || ' event subscription of ' || source_type || ' type.' - when source_type = 'db-parameter-group' and enabled and event_categories_list @> '["configuration change"]' then cust_subscription_id || ' event subscription enabled for critical database parameter group events.' - else cust_subscription_id || ' event subscription missing critical database parameter group events.' - end as reason - from - aws_rds_db_event_subscription; - PrimaryTable: aws_rds_db_event_subscription ListOfTables: - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_rds_db_event_subscription + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN source_type <> 'db-parameter-group' THEN 'skip' + WHEN source_type = 'db-parameter-group' AND enabled AND event_categories_list @> '["maintenance", "failure"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN source_type <> 'db-parameter-group' THEN + cust_subscription_id || ' event subscription of ' || source_type || ' type.' + WHEN source_type = 'db-parameter-group' AND enabled AND event_categories_list @> '["configuration change"]' THEN + cust_subscription_id || ' event subscription enabled for critical database parameter group events.' + ELSE + cust_subscription_id || ' event subscription missing critical database parameter group events.' + END AS reason + FROM + aws_rds_db_event_subscription; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 21 An RDS event notifications subscription should be configured for critical database parameter group events \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_22.yaml b/compliance/controls/aws/aws_foundational_security_rds_22.yaml old mode 100755 new mode 100644 index e7fe018a4..ee65f363e --- a/compliance/controls/aws/aws_foundational_security_rds_22.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_22.yaml @@ -1,30 +1,34 @@ +Description: This control checks whether an Amazon RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs. ID: aws_foundational_security_rds_22 -Title: "22 An RDS event notifications subscription should be configured for critical database security group events" -Description: "This control checks whether an Amazon RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when source_type <> 'db-security-group' then 'skip' - when source_type = 'db-security-group' and enabled and event_categories_list @> '["failure", "configuration change"]' then 'ok' - else 'alarm' - end as status, - case - when source_type <> 'db-security-group' then cust_subscription_id || ' event subscription of ' || source_type || ' type.' - when source_type = 'db-security-group' and enabled and event_categories_list @> '["failure", "configuration change"]' then cust_subscription_id || ' event subscription enabled for critical database security group events.' - else cust_subscription_id || ' event subscription missing critical database security group events.' - end as reason - from - aws_rds_db_event_subscription; - PrimaryTable: aws_rds_db_event_subscription ListOfTables: - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_rds_db_event_subscription + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN source_type <> 'db-security-group' THEN 'skip' + WHEN source_type = 'db-security-group' + AND enabled + AND event_categories_list @> '["failure", "configuration change"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN source_type <> 'db-security-group' THEN cust_subscription_id || ' event subscription of ' || source_type || ' type.' + WHEN source_type = 'db-security-group' + AND enabled + AND event_categories_list @> '["failure", "configuration change"]' THEN cust_subscription_id || ' event subscription enabled for critical database security group events.' + ELSE cust_subscription_id || ' event subscription missing critical database security group events.' + END AS reason + FROM + aws_rds_db_event_subscription; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 22 An RDS event notifications subscription should be configured for critical database security group events \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_24.yaml b/compliance/controls/aws/aws_foundational_security_rds_24.yaml old mode 100755 new mode 100644 index 1b876b6b3..ed65eb3cb --- a/compliance/controls/aws/aws_foundational_security_rds_24.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_24.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an Amazon RDS database cluster has changed the admin username from its default value. This rule will fail if the admin username is set to the default value. ID: aws_foundational_security_rds_24 -Title: "24 RDS database clusters should use a custom administrator username" -Description: "This control checks whether an Amazon RDS database cluster has changed the admin username from its default value. This rule will fail if the admin username is set to the default value." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when master_user_name in ('admin', 'postgres') then 'alarm' - else 'ok' - end status, - case - when master_user_name in ('admin', 'postgres') then title || ' using default master user name.' - else title || ' not using default master user name.' - end reason - from - aws_rds_db_cluster; - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN master_user_name IN ('admin', 'postgres') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN master_user_name IN ('admin', 'postgres') THEN title || ' using default master user name.' + ELSE title || ' not using default master user name.' + END AS reason + FROM + aws_rds_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 24 RDS database clusters should use a custom administrator username \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_25.yaml b/compliance/controls/aws/aws_foundational_security_rds_25.yaml old mode 100755 new mode 100644 index d969b965b..4a13dcb4e --- a/compliance/controls/aws/aws_foundational_security_rds_25.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_25.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether you've changed the administrative username for Amazon Relational Database Service (Amazon RDS) database instances from the default value. The control fails if the administrative username is set to the default value. ID: aws_foundational_security_rds_25 -Title: "25 RDS database instances should use a custom administrator username" -Description: "This control checks whether you've changed the administrative username for Amazon Relational Database Service (Amazon RDS) database instances from the default value. The control fails if the administrative username is set to the default value." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when master_user_name in ('admin','postgres') then 'alarm'\n else 'ok'\n end status,\n case\n when master_user_name in ('admin', 'postgres') then title || ' using default master user name.'\n else title || ' not using default master user name.'\n end reason\n \nfrom\n aws_rds_db_instance;" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN master_user_name IN ('admin', 'postgres') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN master_user_name IN ('admin', 'postgres') THEN title || ' using default master user name.' + ELSE title || ' not using default master user name.' + END AS reason + FROM + aws_rds_db_instance; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 25 RDS database instances should use a custom administrator username \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_27.yaml b/compliance/controls/aws/aws_foundational_security_rds_27.yaml old mode 100755 new mode 100644 index e480834e0..d302bc1bc --- a/compliance/controls/aws/aws_foundational_security_rds_27.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_27.yaml @@ -1,14 +1,28 @@ +Description: This control checks if an RDS DB cluster is encrypted at rest. The control fails if an RDS DB cluster isn't encrypted at rest. ID: aws_foundational_security_rds_27 -Title: "27 RDS DB clusters should be encrypted at rest" -Description: "This control checks if an RDS DB cluster is encrypted at rest. The control fails if an RDS DB cluster isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster;" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_rds_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 27 RDS DB clusters should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_3.yaml b/compliance/controls/aws/aws_foundational_security_rds_3.yaml old mode 100755 new mode 100644 index 30338099f..647802ffc --- a/compliance/controls/aws/aws_foundational_security_rds_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_3.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether storage encryption is enabled for your Amazon RDS DB instances. This control is intended for RDS DB instances. However, it can also generate findings for Aurora DB instances, Neptune DB instances, and Amazon DocumentDB clusters. If these findings are not useful, then you can suppress them. ID: aws_foundational_security_rds_3 -Title: "3 RDS DB instances should have encryption at rest enabled" -Description: "This control checks whether storage encryption is enabled for your Amazon RDS DB instances. This control is intended for RDS DB instances. However, it can also generate findings for Aurora DB instances, Neptune DB instances, and Amazon DocumentDB clusters. If these findings are not useful, then you can suppress them." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_rds_db_instance;" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_rds_db_instance; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 RDS DB instances should have encryption at rest enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_34.yaml b/compliance/controls/aws/aws_foundational_security_rds_34.yaml old mode 100755 new mode 100644 index e61d64da9..41688cf96 --- a/compliance/controls/aws/aws_foundational_security_rds_34.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_34.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether an Amazon Aurora MySQL DB cluster is configured to publish audit logs to Amazon CloudWatch Logs. The control fails if the cluster isn't configured to publish audit logs to CloudWatch Logs. ID: aws_foundational_security_rds_34 -Title: "34 Aurora MySQL DB clusters should publish audit logs to CloudWatch Logs" -Description: "This control checks whether an Amazon Aurora MySQL DB cluster is configured to publish audit logs to Amazon CloudWatch Logs. The control fails if the cluster isn't configured to publish audit logs to CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when engine not ilike '%aurora-mysql%' then 'skip'\n when enabled_cloudwatch_logs_exports @> '[\"audit\"]' then 'ok'\n else 'alarm'\n end as status,\n case\n when engine not ilike '%aurora-mysql%' then title || ' is not Aurora MySQL-compatible edition.'\n when enabled_cloudwatch_logs_exports @> '[\"audit\"]' then title || ' audit logging enabled.'\n else title || ' audit logging disabled.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster;" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine NOT ILIKE '%aurora-mysql%' THEN 'skip' + WHEN enabled_cloudwatch_logs_exports @> '["audit"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine NOT ILIKE '%aurora-mysql%' THEN title || ' is not Aurora MySQL-compatible edition.' + WHEN enabled_cloudwatch_logs_exports @> '["audit"]' THEN title || ' audit logging enabled.' + ELSE title || ' audit logging disabled.' + END AS reason + FROM + aws_rds_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 34 Aurora MySQL DB clusters should publish audit logs to CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_35.yaml b/compliance/controls/aws/aws_foundational_security_rds_35.yaml old mode 100755 new mode 100644 index fb61f00d1..ca7d57cfc --- a/compliance/controls/aws/aws_foundational_security_rds_35.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_35.yaml @@ -1,14 +1,28 @@ +Description: This control checks if automatic minor version upgrade is enabled for an Amazon RDS database cluster. The control fails if automatic minor version upgrade isn't enabled for an RDS cluster. ID: aws_foundational_security_rds_35 -Title: "35 RDS DB clusters should have automatic minor version upgrade enabled" -Description: "This control checks if automatic minor version upgrade is enabled for an Amazon RDS database cluster. The control fails if automatic minor version upgrade isn't enabled for an RDS cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when auto_minor_version_upgrade then 'ok'\n else 'alarm'\n end as status,\n case\n when auto_minor_version_upgrade then title || ' automatic minor version upgrades enabled.'\n else title || ' automatic minor version upgrades disabled.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster;" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrades enabled.' + ELSE title || ' automatic minor version upgrades disabled.' + END AS reason + FROM + aws_rds_db_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 35 RDS DB clusters should have automatic minor version upgrade enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_5.yaml b/compliance/controls/aws/aws_foundational_security_rds_5.yaml old mode 100755 new mode 100644 index 5dac7a032..aede9a941 --- a/compliance/controls/aws/aws_foundational_security_rds_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_5.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether high availability is enabled for your RDS DB instances. RDS DB instances should be configured for multiple Availability Zones (AZs). This ensures the availability of the data stored. Multi-AZ deployments allow for automated failover if there is an issue with Availability Zone availability and during regular RDS maintenance. ID: aws_foundational_security_rds_5 -Title: "5 RDS DB instances should be configured with multiple Availability Zones" -Description: "This control checks whether high availability is enabled for your RDS DB instances. RDS DB instances should be configured for multiple Availability Zones (AZs). This ensures the availability of the data stored. Multi-AZ deployments allow for automated failover if there is an issue with Availability Zone availability and during regular RDS maintenance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when engine ilike any (array ['%aurora-mysql%', '%aurora-postgres%']) then 'skip'\n when multi_az then 'ok'\n else 'alarm'\n end as status,\n case\n when engine ilike any (array ['%aurora-mysql%', '%aurora-postgres%']) then title || ' cluster instance.'\n when multi_az then title || ' Multi-AZ enabled.'\n else title || ' Multi-AZ disabled.'\n end as reason\n \n \nfrom\n aws_rds_db_instance;" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine ILIKE ANY (ARRAY ['%aurora-mysql%', '%aurora-postgres%']) THEN 'skip' + WHEN multi_az THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine ILIKE ANY (ARRAY ['%aurora-mysql%', '%aurora-postgres%']) THEN title || ' cluster instance.' + WHEN multi_az THEN title || ' Multi-AZ enabled.' + ELSE title || ' Multi-AZ disabled.' + END AS reason + FROM + aws_rds_db_instance; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 RDS DB instances should be configured with multiple Availability Zones \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_7.yaml b/compliance/controls/aws/aws_foundational_security_rds_7.yaml old mode 100755 new mode 100644 index ddc2e2a5c..0d7ca5f99 --- a/compliance/controls/aws/aws_foundational_security_rds_7.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_7.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether RDS clusters have deletion protection enabled. This control is intended for RDS DB instances. However, it can also generate findings for Aurora DB instances, Neptune DB instances, and Amazon DocumentDB clusters. If these findings are not useful, then you can suppress them. ID: aws_foundational_security_rds_7 -Title: "7 RDS clusters should have deletion protection enabled" -Description: "This control checks whether RDS clusters have deletion protection enabled. This control is intended for RDS DB instances. However, it can also generate findings for Aurora DB instances, Neptune DB instances, and Amazon DocumentDB clusters. If these findings are not useful,then you can suppress them." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - db_cluster_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when deletion_protection then 'ok' - else 'alarm' - end as status, - case - when deletion_protection then title || ' deletion protection enabled.' - else title || ' deletion protection not enabled.' - end as reason - from - aws_rds_db_cluster; - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + db_cluster_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN deletion_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN deletion_protection THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection not enabled.' + END AS reason + FROM + aws_rds_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 RDS clusters should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_8.yaml b/compliance/controls/aws/aws_foundational_security_rds_8.yaml old mode 100755 new mode 100644 index 8c556311e..ef9a53198 --- a/compliance/controls/aws/aws_foundational_security_rds_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_8.yaml @@ -1,30 +1,30 @@ +Description: 'This control checks whether your RDS DB instances that use one of the listed database engines have deletion protection enabled. DatabaseEngines: mariadb,mysql,oracle-ee,oracle-se2,oracle-se1,oracle-se,postgres,sqlserver-ee,sqlserver-se,sqlserver-ex,sqlserver-web.' ID: aws_foundational_security_rds_8 -Title: "8 RDS DB instances should have deletion protection enabled" -Description: "This control checks whether your RDS DB instances that use one of the listed database engines have deletion protection enabled. DatabaseEngines: mariadb,mysql,oracle-ee,oracle-se2,oracle-se1,oracle-se,postgres,sqlserver-ee,sqlserver-se,sqlserver-ex,sqlserver-web." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when engine like any(array['aurora%', 'docdb', 'neptune']) then 'skip' - when deletion_protection then 'ok' - else 'alarm' - end status, - case - when engine like any(array['aurora%', 'docdb', 'neptune']) then title || ' has engine ' || engine || ' cluster, deletion protection is set at cluster level.' - when deletion_protection then title || ' deletion protection enabled.' - else title || ' deletion protection not enabled.' - end reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine LIKE ANY(array['aurora%', 'docdb', 'neptune']) THEN 'skip' + WHEN deletion_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine LIKE ANY(array['aurora%', 'docdb', 'neptune']) THEN title || ' has engine ' || engine || ' cluster, deletion protection is set at cluster level.' + WHEN deletion_protection THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection not enabled.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 RDS DB instances should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_rds_9.yaml b/compliance/controls/aws/aws_foundational_security_rds_9.yaml old mode 100755 new mode 100644 index fcfd609fc..8dc2fe8a8 --- a/compliance/controls/aws/aws_foundational_security_rds_9.yaml +++ b/compliance/controls/aws/aws_foundational_security_rds_9.yaml @@ -1,43 +1,43 @@ +Description: This control checks whether the logs of Amazon RDS are enabled and sent to CloudWatch Logs. RDS databases should have relevant logs enabled. Database logging provides detailed records of requests made to RDS. Database logs can assist with security and access audits and can help to diagnose availability issues. ID: aws_foundational_security_rds_9 -Title: "9 RDS DB instances should publish logs to CloudWatch Logs" -Description: "This control checks whether the logs of Amazon RDS are enabled and sent to CloudWatch Logs. RDS databases should have relevant logs enabled. Database logging provides detailed records of requests made to RDS. Database logs can assist with security and access audits and can help to diagnose availability issues." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when engine = 'docdb' then 'skip' - when engine like any (array ['mariadb', '%mysql']) and enabled_cloudwatch_logs_exports ?& array ['audit','error','general','slowquery'] then 'ok' - when engine like any (array['%postgres%']) and enabled_cloudwatch_logs_exports ?& array ['postgresql','upgrade'] then 'ok' - when engine like 'oracle%' and enabled_cloudwatch_logs_exports ?& array ['alert','audit', 'trace','listener'] then 'ok' - when engine = 'sqlserver-ex' and enabled_cloudwatch_logs_exports ?& array ['error'] then 'ok' - when engine like 'sqlserver%' and enabled_cloudwatch_logs_exports ?& array ['error','agent'] then 'ok' - else 'alarm' - end as status, - case - when engine = 'docdb' then title || ' is docdb instance.' - when engine like any (array ['mariadb', '%mysql']) and enabled_cloudwatch_logs_exports ?& array ['audit','error','general','slowquery'] - then title || ' ' || engine || ' logging enabled.' - when engine like any (array['%postgres%']) and enabled_cloudwatch_logs_exports ?& array ['postgresql','upgrade'] - then title || ' ' || engine || ' logging enabled.' - when engine like 'oracle%' and enabled_cloudwatch_logs_exports ?& array ['alert','audit', 'trace','listener'] - then title || ' ' || engine || ' logging enabled.' - when engine = 'sqlserver-ex' and enabled_cloudwatch_logs_exports ?& array ['error'] - then title || ' ' || engine || ' logging enabled.' - when engine like 'sqlserver%' and enabled_cloudwatch_logs_exports ?& array ['error','agent'] - then title || ' ' || engine || ' logging enabled.' - else title || ' logging not enabled.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine = 'docdb' THEN 'skip' + WHEN engine LIKE ANY (ARRAY ['mariadb', '%mysql']) AND enabled_cloudwatch_logs_exports ?& ARRAY ['audit','error','general','slowquery'] THEN 'ok' + WHEN engine LIKE ANY (ARRAY['%postgres%']) AND enabled_cloudwatch_logs_exports ?& ARRAY ['postgresql','upgrade'] THEN 'ok' + WHEN engine LIKE 'oracle%' AND enabled_cloudwatch_logs_exports ?& ARRAY ['alert', 'audit', 'trace', 'listener'] THEN 'ok' + WHEN engine = 'sqlserver-ex' AND enabled_cloudwatch_logs_exports ?& ARRAY ['error'] THEN 'ok' + WHEN engine LIKE 'sqlserver%' AND enabled_cloudwatch_logs_exports ?& ARRAY ['error', 'agent'] THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine = 'docdb' THEN title || ' is docdb instance.' + WHEN engine LIKE ANY (ARRAY ['mariadb', '%mysql']) AND enabled_cloudwatch_logs_exports ?& ARRAY ['audit','error','general','slowquery'] + THEN title || ' ' || engine || ' logging enabled.' + WHEN engine LIKE ANY (ARRAY['%postgres%']) AND enabled_cloudwatch_logs_exports ?& ARRAY ['postgresql','upgrade'] + THEN title || ' ' || engine || ' logging enabled.' + WHEN engine LIKE 'oracle%' AND enabled_cloudwatch_logs_exports ?& ARRAY ['alert', 'audit', 'trace', 'listener'] + THEN title || ' ' || engine || ' logging enabled.' + WHEN engine = 'sqlserver-ex' AND enabled_cloudwatch_logs_exports ?& ARRAY ['error'] + THEN title || ' ' || engine || ' logging enabled.' + WHEN engine LIKE 'sqlserver%' AND enabled_cloudwatch_logs_exports ?& ARRAY ['error', 'agent'] + THEN title || ' ' || engine || ' logging enabled.' + ELSE title || ' logging not enabled.' + END AS reason + FROM + aws_rds_db_instance; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 RDS DB instances should publish logs to CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_redshift_1.yaml b/compliance/controls/aws/aws_foundational_security_redshift_1.yaml old mode 100755 new mode 100644 index fddd31098..c94fc1fa7 --- a/compliance/controls/aws/aws_foundational_security_redshift_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_redshift_1.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether Amazon Redshift clusters are publicly accessible. It evaluates the PubliclyAccessible field in the cluster configuration item. The PubliclyAccessible attribute of the Amazon Redshift cluster configuration indicates whether the cluster is publicly accessible. When the cluster is configured with PubliclyAccessible set to true, it is an Internet-facing instance that has a publicly resolvable DNS name, which resolves to a public IP address. When the cluster is not publicly accessible, it is an internal instance with a DNS name that resolves to a private IP address. Unless you intend for your cluster to be publicly accessible, the cluster should not be configured with PubliclyAccessible set to true. ID: aws_foundational_security_redshift_1 -Title: "1 Amazon Redshift clusters should prohibit public access" -Description: "This control checks whether Amazon Redshift clusters are publicly accessible. It evaluates the PubliclyAccessible field in the cluster configuration item. The PubliclyAccessible attribute of the Amazon Redshift cluster configuration indicates whether the cluster is publicly accessible. When the cluster is configured with PubliclyAccessible set to true, it is an Internet-facing instance that has a publicly resolvable DNS name, which resolves to a public IP address. When the cluster is not publicly accessible, it is an internal instance with a DNS name that resolves to a private IP address. Unless you intend for your cluster to be publicly accessible, the cluster should not be configured with PubliclyAccessible set to true." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n cluster_namespace_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when publicly_accessible then 'alarm'\n else 'ok'\n end status,\n case\n when publicly_accessible then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end reason\n\n \n \nfrom\n aws_redshift_cluster;" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + cluster_namespace_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_redshift_cluster; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Amazon Redshift clusters should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_redshift_10.yaml b/compliance/controls/aws/aws_foundational_security_redshift_10.yaml old mode 100755 new mode 100644 index b424cf0d7..aaf6a8a11 --- a/compliance/controls/aws/aws_foundational_security_redshift_10.yaml +++ b/compliance/controls/aws/aws_foundational_security_redshift_10.yaml @@ -1,28 +1,30 @@ +Description: This control checks if Amazon Redshift clusters are encrypted at rest. + The control fails if a Redshift cluster isn't encrypted at rest or if the encryption key + is different from the provided key in the rule parameter. ID: aws_foundational_security_redshift_10 -Title: "10 Redshift clusters should be encrypted at rest" -Description: "This control checks if Amazon Redshift clusters are encrypted at rest. The control fails if a Redshift cluster isn't encrypted at rest or if the encryption key is different from the provided key in the rule parameter." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when encrypted and kms_key_id is not null then 'ok' - else 'alarm' - end as status, - case - when encrypted and kms_key_id is not null then title || ' encrypted with KMS.' - else title || ' not encrypted with KMS' - end as reason - from - aws_redshift_cluster; - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted AND kms_key_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted AND kms_key_id IS NOT NULL THEN title || ' encrypted with KMS.' + ELSE title || ' not encrypted with KMS' + END AS reason + FROM + aws_redshift_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 10 Redshift clusters should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_redshift_2.yaml b/compliance/controls/aws/aws_foundational_security_redshift_2.yaml old mode 100755 new mode 100644 index 82bb5fc15..58a5a49ac --- a/compliance/controls/aws/aws_foundational_security_redshift_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_redshift_2.yaml @@ -1,42 +1,42 @@ +Description: This control checks whether connections to Amazon Redshift clusters are required to use encryption in transit. The check fails if the Amazon Redshift cluster parameter require_SSL is not set to 1. TLS can be used to help prevent potential attackers from using person-in-the-middle or similar attacks to eavesdrop on or manipulate network traffic. Only encrypted connections over TLS should be allowed. Encrypting data in transit can affect performance. You should test your application with this feature to understand the performance profile and the impact of TLS. ID: aws_foundational_security_redshift_2 -Title: "2 Connections to Amazon Redshift clusters should be encrypted in transit" -Description: "This control checks whether connections to Amazon Redshift clusters are required to use encryption in transit. The check fails if the Amazon Redshift cluster parameter require_SSL is not set to 1. TLS can be used to help prevent potential attackers from using person-in-the-middle or similar attacks to eavesdrop on or manipulate network traffic. Only encrypted connections over TLS should be allowed. Encrypting data in transit can affect performance. You should test your application with this feature to understand the performance profile and the impact of TLS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with pg_with_ssl as ( - select - name as pg_name, - p ->> 'ParameterName' as parameter_name, - p ->> 'ParameterValue' as parameter_value - from - aws_redshift_parameter_group, - jsonb_array_elements(parameters) as p - where - p ->> 'ParameterName' = 'require_ssl' - and p ->> 'ParameterValue' = 'true' - ) - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when cpg ->> 'ParameterGroupName' in (select pg_name from pg_with_ssl ) then 'ok' - else 'alarm' - end as status, - case - when cpg ->> 'ParameterGroupName' in (select pg_name from pg_with_ssl ) then title || ' encryption in transit enabled.' - else title || ' encryption in transit disabled.' - end as reason - from - aws_redshift_cluster, - jsonb_array_elements(cluster_parameter_groups) as cpg; - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_parameter_group - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + WITH pg_with_ssl AS ( + SELECT + name AS pg_name, + p ->> 'ParameterName' AS parameter_name, + p ->> 'ParameterValue' AS parameter_value + FROM + aws_redshift_parameter_group, + JSONB_ARRAY_ELEMENTS(parameters) AS p + WHERE + p ->> 'ParameterName' = 'require_ssl' + AND p ->> 'ParameterValue' = 'true' + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cpg ->> 'ParameterGroupName' IN (SELECT pg_name FROM pg_with_ssl) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cpg ->> 'ParameterGroupName' IN (SELECT pg_name FROM pg_with_ssl) THEN title || ' encryption in transit enabled.' + ELSE title || ' encryption in transit disabled.' + END AS reason + FROM + aws_redshift_cluster, + JSONB_ARRAY_ELEMENTS(cluster_parameter_groups) AS cpg; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Connections to Amazon Redshift clusters should be encrypted in transit \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_redshift_3.yaml b/compliance/controls/aws/aws_foundational_security_redshift_3.yaml old mode 100755 new mode 100644 index efe7f5e10..ab455a11b --- a/compliance/controls/aws/aws_foundational_security_redshift_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_redshift_3.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether Amazon Redshift clusters have automated snapshots enabled. It also checks whether the snapshot retention period is greater than or equal to seven. ID: aws_foundational_security_redshift_3 -Title: "3 Amazon Redshift clusters should have automatic snapshots enabled" -Description: "This control checks whether Amazon Redshift clusters have automated snapshots enabled. It also checks whether the snapshot retention period is greater than or equal to seven." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when automated_snapshot_retention_period >= 7 then 'ok'\n else 'alarm'\n end as status,\n case\n when automated_snapshot_retention_period >= 7 then title || ' automatic snapshots enabled with retention period greater than equals 7 days.'\n else title || ' automatic snapshots enabled with retention period less than 7 days.'\n end as reason\n \n \nfrom\n aws_redshift_cluster;" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN automated_snapshot_retention_period >= 7 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN automated_snapshot_retention_period >= 7 THEN title || ' automatic snapshots enabled with retention period greater than or equals 7 days.' + ELSE title || ' automatic snapshots enabled with retention period less than 7 days.' + END AS reason + FROM + aws_redshift_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Amazon Redshift clusters should have automatic snapshots enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_redshift_4.yaml b/compliance/controls/aws/aws_foundational_security_redshift_4.yaml old mode 100755 new mode 100644 index 474add604..efa2e7c5c --- a/compliance/controls/aws/aws_foundational_security_redshift_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_redshift_4.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an Amazon Redshift cluster has audit logging enabled. ID: aws_foundational_security_redshift_4 -Title: "4 Amazon Redshift clusters should have audit logging enabled" -Description: "This control checks whether an Amazon Redshift cluster has audit logging enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when automated_snapshot_retention_period >= 7 then 'ok' - else 'alarm' - end as status, - case - when automated_snapshot_retention_period >= 7 then title || ' automatic snapshots enabled with retention period greater than equals 7 days.' - else title || ' automatic snapshots enabled with retention period less than 7 days.' - end as reason - from - aws_redshift_cluster; - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN automated_snapshot_retention_period >= 7 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN automated_snapshot_retention_period >= 7 THEN title || ' automatic snapshots enabled with retention period greater than or equals 7 days.' + ELSE title || ' automatic snapshots enabled with retention period less than 7 days.' + END AS reason + FROM + aws_redshift_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 Amazon Redshift clusters should have audit logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_redshift_6.yaml b/compliance/controls/aws/aws_foundational_security_redshift_6.yaml old mode 100755 new mode 100644 index 9aca9bd08..1ea396e43 --- a/compliance/controls/aws/aws_foundational_security_redshift_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_redshift_6.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether automatic major version upgrades are enabled for the Amazon Redshift cluster. ID: aws_foundational_security_redshift_6 -Title: "6 Amazon Redshift should have automatic upgrades to major versions enabled" -Description: "This control checks whether automatic major version upgrades are enabled for the Amazon Redshift cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when allow_version_upgrade then 'ok' - else 'alarm' - end as status, - case - when allow_version_upgrade then title || ' automatic upgrades to major versions enabled.' - else title || ' automatic upgrades to major versions disabled.' - end as reason - from - aws_redshift_cluster; - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN allow_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN allow_version_upgrade THEN title || ' automatic upgrades to major versions enabled.' + ELSE title || ' automatic upgrades to major versions disabled.' + END AS reason + FROM + aws_redshift_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 Amazon Redshift should have automatic upgrades to major versions enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_redshift_7.yaml b/compliance/controls/aws/aws_foundational_security_redshift_7.yaml old mode 100755 new mode 100644 index 600958bd5..c8ab5892e --- a/compliance/controls/aws/aws_foundational_security_redshift_7.yaml +++ b/compliance/controls/aws/aws_foundational_security_redshift_7.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an Amazon Redshift cluster has EnhancedVpcRouting enabled. ID: aws_foundational_security_redshift_7 -Title: "7 Amazon Redshift clusters should use enhanced VPC routing" -Description: "This control checks whether an Amazon Redshift cluster has EnhancedVpcRouting enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when enhanced_vpc_routing then 'ok' - else 'alarm' - end as status, - case - when enhanced_vpc_routing then title || ' enhanced VPC routing enabled.' - else title || ' enhanced VPC routing disabled.' - end as reason - from - aws_redshift_cluster; - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enhanced_vpc_routing THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enhanced_vpc_routing THEN title || ' enhanced VPC routing enabled.' + ELSE title || ' enhanced VPC routing disabled.' + END AS reason + FROM + aws_redshift_cluster; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 Amazon Redshift clusters should use enhanced VPC routing \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_redshift_8.yaml b/compliance/controls/aws/aws_foundational_security_redshift_8.yaml old mode 100755 new mode 100644 index bc0aec6ef..6d474debd --- a/compliance/controls/aws/aws_foundational_security_redshift_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_redshift_8.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether a Amazon Redshift cluster has changed the admin username from its default value. This control will fail if the admin username for a Redshift cluster is set to awsuser. ID: aws_foundational_security_redshift_8 -Title: "8 Amazon Redshift clusters should not use the default Admin username" -Description: "This control checks whether a Amazon Redshift cluster has changed the admin username from its default value. This control will fail if the admin username for a Redshift cluster is set to awsuser." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when master_username = 'awsuser' then 'alarm'\n else 'ok'\n end as status,\n case\n when master_username = 'awsuser' then title || ' using default master user name.'\n else title || ' not using default master user name.'\n end as reason\n \n \nfrom\n aws_redshift_cluster;" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN master_username = 'awsuser' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN master_username = 'awsuser' THEN title || ' using default master user name.' + ELSE title || ' not using default master user name.' + END AS reason + FROM + aws_redshift_cluster; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 Amazon Redshift clusters should not use the default Admin username \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_redshift_9.yaml b/compliance/controls/aws/aws_foundational_security_redshift_9.yaml old mode 100755 new mode 100644 index 7a8ac88e6..5966d1924 --- a/compliance/controls/aws/aws_foundational_security_redshift_9.yaml +++ b/compliance/controls/aws/aws_foundational_security_redshift_9.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an Amazon Redshift cluster has changed the database name from its default value. The control will fail if the database name for a Redshift cluster is set to dev. ID: aws_foundational_security_redshift_9 -Title: "9 Redshift clusters should not use the default database name" -Description: "This control checks whether an Amazon Redshift cluster has changed the database name from its default value. The control will fail if the database name for a Redshift cluster is set to dev." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when db_name = 'dev' then 'alarm'\n else 'ok'\n end as status,\n case\n when db_name = 'dev' then title || ' using default database name.'\n else title || ' not using default database name.'\n end as reason\n \n \nfrom\n aws_redshift_cluster;" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN db_name = 'dev' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN db_name = 'dev' THEN title || ' using default database name.' + ELSE title || ' not using default database name.' + END AS reason + FROM + aws_redshift_cluster; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 Redshift clusters should not use the default database name \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_route53_2.yaml b/compliance/controls/aws/aws_foundational_security_route53_2.yaml old mode 100755 new mode 100644 index 01756f037..2ff069d26 --- a/compliance/controls/aws/aws_foundational_security_route53_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_route53_2.yaml @@ -1,30 +1,30 @@ +Description: This control checks if DNS query logging is enabled for an Amazon Route 53 public hosted zone. The control fails if DNS query logging isn't enabled for a Route 53 public hosted zone. ID: aws_foundational_security_route53_2 -Title: "2 Route 53 public hosted zones should log DNS queries" -Description: "This control checks if DNS query logging is enabled for an Amazon Route 53 public hosted zone. The control fails if DNS query logging isn't enabled for a Route 53 public hosted zone." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when private_zone then 'skip' - when query_logging_configs is not null or jsonb_array_length(query_logging_configs) > 0 then 'ok' - else 'alarm' - end as status, - case - when private_zone then title || ' is private hosted zone.' - when query_logging_configs is not null or jsonb_array_length(query_logging_configs) > 0 then title || ' query logging to CloudWatch enabled.' - else title || ' query logging to CloudWatch disabled.' - end as reason - from - aws_route53_zone; - PrimaryTable: aws_route53_zone ListOfTables: - aws_route53_zone Parameters: [] + PrimaryTable: aws_route53_zone + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN private_zone THEN 'skip' + WHEN query_logging_configs IS NOT NULL OR jsonb_array_length(query_logging_configs) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN private_zone THEN title || ' is private hosted zone.' + WHEN query_logging_configs IS NOT NULL OR jsonb_array_length(query_logging_configs) > 0 THEN title || ' query logging to CloudWatch enabled.' + ELSE title || ' query logging to CloudWatch disabled.' + END AS reason + FROM + aws_route53_zone; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Route 53 public hosted zones should log DNS queries \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_s3_1.yaml b/compliance/controls/aws/aws_foundational_security_s3_1.yaml old mode 100755 new mode 100644 index 3e56c95d8..e06c234af --- a/compliance/controls/aws/aws_foundational_security_s3_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_s3_1.yaml @@ -1,14 +1,42 @@ +Description: This control checks whether the following Amazon S3 public access block settings are configured at the account level ID: aws_foundational_security_s3_1 -Title: "1 S3 Block Public Access setting should be enabled" -Description: "This control checks whether the following Amazon S3 public access block settings are configured at the account level" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn' || ':' || 'aws' || ':::' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when block_public_acls\n and block_public_policy\n and ignore_public_acls\n and restrict_public_buckets\n then 'ok'\n else 'alarm'\n end as status,\n case\n when block_public_acls\n and block_public_policy\n and ignore_public_acls\n and restrict_public_buckets\n then 'Account level public access blocks enabled.'\n else 'Account level public access blocks not enabled for: ' ||\n concat_ws(', ',\n case when not (block_public_acls ) then 'block_public_acls' end,\n case when not (block_public_policy) then 'block_public_policy' end,\n case when not (ignore_public_acls ) then 'ignore_public_acls' end,\n case when not (restrict_public_buckets) then 'restrict_public_buckets' end\n ) || '.'\n end as reason\n \nfrom\n aws_s3_account_settings;\n" - PrimaryTable: aws_s3_account_settings ListOfTables: - aws_s3_account_settings Parameters: [] + PrimaryTable: aws_s3_account_settings + QueryToExecute: | + SELECT + 'arn' || ':' || 'aws' || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN 'Account level public access blocks enabled.' + ELSE 'Account level public access blocks not enabled for: ' || + concat_ws(', ', + CASE WHEN NOT (block_public_acls) THEN 'block_public_acls' END, + CASE WHEN NOT (block_public_policy) THEN 'block_public_policy' END, + CASE WHEN NOT (ignore_public_acls) THEN 'ignore_public_acls' END, + CASE WHEN NOT (restrict_public_buckets) THEN 'restrict_public_buckets' END + ) || '.' + END AS reason + FROM + aws_s3_account_settings; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 S3 Block Public Access setting should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_s3_10.yaml b/compliance/controls/aws/aws_foundational_security_s3_10.yaml old mode 100755 new mode 100644 index e96065cbe..d11017cbe --- a/compliance/controls/aws/aws_foundational_security_s3_10.yaml +++ b/compliance/controls/aws/aws_foundational_security_s3_10.yaml @@ -1,40 +1,40 @@ +Description: This control checks if Amazon Simple Storage Service (Amazon S3) version enabled buckets have lifecycle policy configured. This rule fails if Amazon S3 lifecycle policy is not enabled. ID: aws_foundational_security_s3_10 -Title: "10 S3 buckets with versioning enabled should have lifecycle policies configured" -Description: "This control checks if Amazon Simple Storage Service (Amazon S3) version enabled buckets have lifecycle policy configured. This rule fails if Amazon S3 lifecycle policy is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with lifecycle_rules_enabled as ( - select + ListOfTables: + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH lifecycle_rules_enabled AS ( + SELECT arn - from + FROM aws_s3_bucket, - jsonb_array_elements(lifecycle_rules) as r - where + jsonb_array_elements(lifecycle_rules) AS r + WHERE r ->> 'Status' = 'Enabled' ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when not versioning_enabled then 'alarm' - when versioning_enabled and r.arn is not null then 'ok' - else 'alarm' - end as status, - case - when not versioning_enabled then name || ' versioning diabled.' - when versioning_enabled and r.arn is not null then name || ' lifecycle policy configured.' - else name || ' lifecycle policy not configured.' - end as reason - from - aws_s3_bucket as b - left join lifecycle_rules_enabled as r on r.arn = b.arn; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_s3_bucket - Parameters: [] + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN NOT versioning_enabled THEN 'alarm' + WHEN versioning_enabled AND r.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT versioning_enabled THEN name || ' versioning disabled.' + WHEN versioning_enabled AND r.arn IS NOT NULL THEN name || ' lifecycle policy configured.' + ELSE name || ' lifecycle policy not configured.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN lifecycle_rules_enabled AS r ON r.arn = b.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 10 S3 buckets with versioning enabled should have lifecycle policies configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_s3_11.yaml b/compliance/controls/aws/aws_foundational_security_s3_11.yaml old mode 100755 new mode 100644 index bb29a8e1c..791f005d1 --- a/compliance/controls/aws/aws_foundational_security_s3_11.yaml +++ b/compliance/controls/aws/aws_foundational_security_s3_11.yaml @@ -1,14 +1,36 @@ +Description: This control checks whether S3 Event Notifications are enabled on an Amazon S3 bucket. This control fails if S3 Event Notifications are not enabled on a bucket. ID: aws_foundational_security_s3_11 -Title: "11 S3 buckets should have event notifications enabled" -Description: "This control checks whether S3 Event Notifications are enabled on an Amazon S3 bucket. This control fails if S3 Event Notifications are not enabled on a bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when\n event_notification_configuration ->> 'EventBridgeConfiguration' is null\n and event_notification_configuration ->> 'LambdaFunctionConfigurations' is null\n and event_notification_configuration ->> 'QueueConfigurations' is null\n and event_notification_configuration ->> 'TopicConfigurations' is null then 'alarm'\n else 'ok'\n end as status,\n case\n when\n event_notification_configuration ->> 'EventBridgeConfiguration' is null\n and event_notification_configuration ->> 'LambdaFunctionConfigurations' is null\n and event_notification_configuration ->> 'QueueConfigurations' is null\n and event_notification_configuration ->> 'TopicConfigurations' is null then title || ' event notifications disabled.'\n else title || ' event notifications enabled.'\n end as reason\n \n \nfrom\n aws_s3_bucket;" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN + event_notification_configuration ->> 'EventBridgeConfiguration' IS NULL + AND event_notification_configuration ->> 'LambdaFunctionConfigurations' IS NULL + AND event_notification_configuration ->> 'QueueConfigurations' IS NULL + AND event_notification_configuration ->> 'TopicConfigurations' IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + event_notification_configuration ->> 'EventBridgeConfiguration' IS NULL + AND event_notification_configuration ->> 'LambdaFunctionConfigurations' IS NULL + AND event_notification_configuration ->> 'QueueConfigurations' IS NULL + AND event_notification_configuration ->> 'TopicConfigurations' IS NULL THEN title || ' event notifications disabled.' + ELSE title || ' event notifications enabled.' + END AS reason + FROM + aws_s3_bucket; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 11 S3 buckets should have event notifications enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_s3_12.yaml b/compliance/controls/aws/aws_foundational_security_s3_12.yaml old mode 100755 new mode 100644 index 72f6b836e..828d15f8e --- a/compliance/controls/aws/aws_foundational_security_s3_12.yaml +++ b/compliance/controls/aws/aws_foundational_security_s3_12.yaml @@ -1,24 +1,29 @@ +Description: This control checks whether Amazon S3 buckets provide user permissions via ACLs. The control fails if ACLs are configured for managing user access on S3 buckets. ID: aws_foundational_security_s3_12 -Title: "12 S3 access control lists (ACLs) should not be used to manage user access to buckets" -Description: "This control checks whether Amazon S3 buckets provide user permissions via ACLs. The control fails if ACLs are configured for managing user access on S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bucket_acl_details as ( - select + ListOfTables: + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH bucket_acl_details AS ( + SELECT arn, title, - array[acl -> 'Owner' ->> 'ID'] as bucket_owner, - array_agg(grantee_id) as bucket_acl_permissions, + ARRAY[acl -> 'Owner' ->> 'ID'] AS bucket_owner, + array_agg(grantee_id) AS bucket_acl_permissions, object_ownership_controls, region, account_id, _ctx, tags - from + FROM aws_s3_bucket, - jsonb_path_query(acl, '$.Grants.Grantee.ID') as grantee_id - group by + jsonb_path_query(acl, '$.Grants.Grantee.ID') AS grantee_id + GROUP BY arn, title, acl, @@ -28,40 +33,35 @@ Query: _ctx, tags ), - bucket_acl_checks as ( - select + bucket_acl_checks AS ( + SELECT arn, title, - to_jsonb(bucket_acl_permissions) - bucket_owner as additional_permissions, + TO_JSONB(bucket_acl_permissions) - bucket_owner AS additional_permissions, object_ownership_controls, region, account_id, _ctx, tags - from + FROM bucket_acl_details ) - select - arn as resource, - account_id as og_account_id, - arn as og_resource_id, - case - when object_ownership_controls -> 'Rules' @> '[{"ObjectOwnership": "BucketOwnerEnforced"} ]' then 'ok' - when jsonb_array_length(additional_permissions) = 0 then 'ok' - else 'alarm' - end as status, - case - when object_ownership_controls -> 'Rules' @> '[{"ObjectOwnership": "BucketOwnerEnforced"} ]' then title || ' ACLs are disabled.' - when jsonb_array_length(additional_permissions) = 0 then title || ' does not have ACLs for user access.' - else title || ' has ACLs for user access.' - end as reason - from + SELECT + arn AS resource, + account_id AS og_account_id, + arn AS og_resource_id, + CASE + WHEN object_ownership_controls -> 'Rules' @> '[{"ObjectOwnership": "BucketOwnerEnforced"}]' THEN 'ok' + WHEN JSONB_ARRAY_LENGTH(additional_permissions) = 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN object_ownership_controls -> 'Rules' @> '[{"ObjectOwnership": "BucketOwnerEnforced"}]' THEN title || ' ACLs are disabled.' + WHEN JSONB_ARRAY_LENGTH(additional_permissions) = 0 THEN title || ' does not have ACLs for user access.' + ELSE title || ' has ACLs for user access.' + END AS reason + FROM bucket_acl_checks; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_s3_bucket - Parameters: [] Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 12 S3 access control lists (ACLs) should not be used to manage user access to buckets \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_s3_13.yaml b/compliance/controls/aws/aws_foundational_security_s3_13.yaml old mode 100755 new mode 100644 index fe572102e..6efe14e23 --- a/compliance/controls/aws/aws_foundational_security_s3_13.yaml +++ b/compliance/controls/aws/aws_foundational_security_s3_13.yaml @@ -1,38 +1,38 @@ +Description: This control checks if a lifecycle policy is configured for an Amazon S3 bucket. This control fails if a lifecycle policy is not configured for an S3 bucket. ID: aws_foundational_security_s3_13 -Title: "13 S3 buckets should have lifecycle policies configured" -Description: "This control checks if a lifecycle policy is configured for an Amazon S3 bucket. This control fails if a lifecycle policy is not configured for an S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with lifecycle_rules_enabled as ( - select + ListOfTables: + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH lifecycle_rules_enabled AS ( + SELECT arn - from + FROM aws_s3_bucket, - jsonb_array_elements(lifecycle_rules) as r - where + jsonb_array_elements(lifecycle_rules) AS r + WHERE r ->> 'Status' = 'Enabled' ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when r.arn is not null then 'ok' - else 'alarm' - end status, - case - when r.arn is not null then name || ' lifecycle policy or rules configured.' - else name || ' lifecycle policy or rules not configured.' - end reason - from - aws_s3_bucket as b - left join lifecycle_rules_enabled as r on r.arn = b.arn; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_s3_bucket - Parameters: [] + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN r.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.arn IS NOT NULL THEN name || ' lifecycle policy or rules configured.' + ELSE name || ' lifecycle policy or rules not configured.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN lifecycle_rules_enabled AS r ON r.arn = b.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 13 S3 buckets should have lifecycle policies configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_s3_19.yaml b/compliance/controls/aws/aws_foundational_security_s3_19.yaml old mode 100755 new mode 100644 index 115d78214..355bfcc29 --- a/compliance/controls/aws/aws_foundational_security_s3_19.yaml +++ b/compliance/controls/aws/aws_foundational_security_s3_19.yaml @@ -1,43 +1,42 @@ +Description: This control checks whether an Amazon S3 access point has block public access settings enabled. The control fails if block public access settings aren't enabled for the access point. ID: aws_foundational_security_s3_19 -Title: "19 S3 access points should have block public access settings enabled" -Description: "This control checks whether an Amazon S3 access point has block public access settings enabled. The control fails if block public access settings aren't enabled for the access point." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - access_point_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when block_public_acls - and block_public_policy - and ignore_public_acls - and restrict_public_buckets - then 'ok' - else 'alarm' - end as status, - case - when block_public_acls - and block_public_policy - and ignore_public_acls - and restrict_public_buckets - then name || ' all public access blocks enabled.' - else name || ' not enabled for: ' || - concat_ws(', ', - case when not block_public_acls then 'block_public_acls' end, - case when not block_public_policy then 'block_public_policy' end, - case when not ignore_public_acls then 'ignore_public_acls' end, - case when not restrict_public_buckets then 'restrict_public_buckets' end - ) || '.' - end as reason - - from - aws_s3_access_point; - PrimaryTable: aws_s3_access_point ListOfTables: - aws_s3_access_point Parameters: [] + PrimaryTable: aws_s3_access_point + QueryToExecute: | + SELECT + access_point_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN name || ' all public access blocks enabled.' + ELSE name || ' not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT block_public_acls THEN 'block_public_acls' END, + CASE WHEN NOT block_public_policy THEN 'block_public_policy' END, + CASE WHEN NOT ignore_public_acls THEN 'ignore_public_acls' END, + CASE WHEN NOT restrict_public_buckets THEN 'restrict_public_buckets' END + ) || '.' + END AS reason + FROM + aws_s3_access_point; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 19 S3 access points should have block public access settings enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_s3_5.yaml b/compliance/controls/aws/aws_foundational_security_s3_5.yaml old mode 100755 new mode 100644 index 5f2a07bd7..405936a10 --- a/compliance/controls/aws/aws_foundational_security_s3_5.yaml +++ b/compliance/controls/aws/aws_foundational_security_s3_5.yaml @@ -1,48 +1,48 @@ +Description: 'This control checks whether S3 buckets have policies that require requests to use Secure Socket Layer (SSL). S3 buckets should have policies that require all requests (Action: S3:*)to only accept transmission of data over HTTPS in the S3 resource policy, indicated by the condition key aws:SecureTransport.' ID: aws_foundational_security_s3_5 -Title: "5 S3 buckets should require requests to use Secure Socket Layer" -Description: "This control checks whether S3 buckets have policies that require requests to use Secure Socket Layer (SSL). S3 buckets should have policies that require all requests (Action: S3:*)to only accept transmission of data over HTTPS in the S3 resource policy, indicated by the condition key aws:SecureTransport." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ssl_ok as ( - select - distinct name, + ListOfTables: + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH ssl_ok AS ( + SELECT + DISTINCT name, arn, - 'ok' as status - from + 'ok' AS status + FROM aws_s3_bucket, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p, - jsonb_array_elements_text(s -> 'Action') as a, - jsonb_array_elements_text(s -> 'Resource') as r, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + jsonb_array_elements_text(s -> 'Action') AS a, + jsonb_array_elements_text(s -> 'Resource') AS r, jsonb_array_elements_text( - s -> 'Condition' -> 'Bool' -> 'aws:securetransport' - ) as ssl - where + s -> 'Condition' -> 'Bool' -> 'aws:SecureTransport' + ) AS ssl + WHERE p = '*' - and s ->> 'Effect' = 'Deny' - and ssl :: bool = false + AND s ->> 'Effect' = 'Deny' + AND ssl::bool = false ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when ok.status = 'ok' then 'ok' - else 'alarm' - end status, - case - when ok.status = 'ok' then b.name || ' bucket policy enforces HTTPS.' - else b.name || ' bucket policy does not enforce HTTPS.' - end reason - from - aws_s3_bucket as b - left join ssl_ok as ok on ok.name = b.name; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_s3_bucket - Parameters: [] + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN ok.status = 'ok' THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN ok.status = 'ok' THEN b.name || ' bucket policy enforces HTTPS.' + ELSE b.name || ' bucket policy does not enforce HTTPS.' + END reason + FROM + aws_s3_bucket AS b + LEFT JOIN ssl_ok AS ok ON ok.name = b.name; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 S3 buckets should require requests to use Secure Socket Layer \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_s3_6.yaml b/compliance/controls/aws/aws_foundational_security_s3_6.yaml old mode 100755 new mode 100644 index f583f0d44..29faab5f7 --- a/compliance/controls/aws/aws_foundational_security_s3_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_s3_6.yaml @@ -1,25 +1,30 @@ +Description: This control checks whether the S3 bucket policy prevents principals from other AWS accounts from performing denied actions on resources in the S3 bucket. ID: aws_foundational_security_s3_6 -Title: "6 Amazon S3 permissions granted to other AWS accounts in bucket policies should be restricted" -Description: "This control checks whether the S3 bucket policy prevents principals from other AWS accounts from performing denied actions on resources in the S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with cross_account_buckets as ( - select - distinct arn - from + ListOfTables: + - aws_s3_bucket + Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH cross_account_buckets AS ( + SELECT DISTINCT + arn + FROM aws_s3_bucket, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p, - string_to_array(p, ':') as pa, - jsonb_array_elements_text(s -> 'Action') as a - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + string_to_array(p, ':') AS pa, + jsonb_array_elements_text(s -> 'Action') AS a + WHERE s ->> 'Effect' = 'Allow' - and ( - pa [5] != account_id - or p = '*' + AND ( + pa[5] != account_id + OR p = '*' ) - and a in ( + AND a IN ( 's3:deletebucketpolicy', 's3:putbucketacl', 's3:putbucketpolicy', @@ -27,26 +32,21 @@ Query: 's3:putobjectacl' ) ) - select - a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.arn is null then 'ok' - else 'alarm' - end as status, - case - when b.arn is null then title || ' restricts cross-account bucket access.' - else title || ' allows cross-account bucket access.' - end as reason - from + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NULL THEN title || ' restricts cross-account bucket access.' + ELSE title || ' allows cross-account bucket access.' + END AS reason + FROM aws_s3_bucket a - left join cross_account_buckets b on a.arn = b.arn; - PrimaryTable: aws_s3_bucket - ListOfTables: - - aws_s3_bucket - Parameters: [] + LEFT JOIN cross_account_buckets b ON a.arn = b.arn; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 Amazon S3 permissions granted to other AWS accounts in bucket policies should be restricted \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_s3_8.yaml b/compliance/controls/aws/aws_foundational_security_s3_8.yaml old mode 100755 new mode 100644 index fd0e5888d..051e0c42f --- a/compliance/controls/aws/aws_foundational_security_s3_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_s3_8.yaml @@ -1,42 +1,42 @@ +Description: This control checks whether S3 buckets have bucket-level public access blocks applied. ID: aws_foundational_security_s3_8 -Title: "8 S3 Block Public Access setting should be enabled at the bucket level" -Description: "This control checks whether S3 buckets have bucket-level public access blocks applied." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when block_public_acls - and block_public_policy - and ignore_public_acls - and restrict_public_buckets - then 'ok' - else 'alarm' - end as status, - case - when block_public_acls - and block_public_policy - and ignore_public_acls - and restrict_public_buckets - then name || ' all public access blocks enabled.' - else name || ' not enabled for: ' || - concat_ws(', ', - case when not block_public_acls then 'block_public_acls' end, - case when not block_public_policy then 'block_public_policy' end, - case when not ignore_public_acls then 'ignore_public_acls' end, - case when not restrict_public_buckets then 'restrict_public_buckets' end - ) || '.' - end as reason - from - aws_s3_bucket; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN name || ' all public access blocks enabled.' + ELSE name || ' not enabled for: ' || + concat_ws(', ', + CASE WHEN NOT block_public_acls THEN 'block_public_acls' END, + CASE WHEN NOT block_public_policy THEN 'block_public_policy' END, + CASE WHEN NOT ignore_public_acls THEN 'ignore_public_acls' END, + CASE WHEN NOT restrict_public_buckets THEN 'restrict_public_buckets' END + ) || '.' + END AS reason + FROM + aws_s3_bucket; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 S3 Block Public Access setting should be enabled at the bucket level \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_s3_9.yaml b/compliance/controls/aws/aws_foundational_security_s3_9.yaml old mode 100755 new mode 100644 index 355eb3418..574e6257d --- a/compliance/controls/aws/aws_foundational_security_s3_9.yaml +++ b/compliance/controls/aws/aws_foundational_security_s3_9.yaml @@ -1,14 +1,28 @@ +Description: When logging is enabled, Amazon S3 delivers access logs for a source bucket to a chosen target bucket. The target bucket must be in the same AWS Region as the source bucket and must not have a default retention period configuration. ID: aws_foundational_security_s3_9 -Title: "9 S3 bucket server access logging should be enabled" -Description: "When logging is enabled, Amazon S3 delivers access logs for a source bucket to a chosen target bucket. The target bucket must be in the same AWS Region as the source bucket and must not have a default retention period configuration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when logging -> 'TargetBucket' is null then 'alarm'\n else 'ok'\n end as status,\n case\n when logging -> 'TargetBucket' is null then title || ' logging disabled.'\n else title || ' logging enabled.'\n end as reason\n \n \nfrom\n aws_s3_bucket;" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logging -> 'TargetBucket' IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN logging -> 'TargetBucket' IS NULL THEN title || ' logging disabled.' + ELSE title || ' logging enabled.' + END AS reason + FROM + aws_s3_bucket; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 S3 bucket server access logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_sagemaker_1.yaml b/compliance/controls/aws/aws_foundational_security_sagemaker_1.yaml old mode 100755 new mode 100644 index 69c997772..25b34b1b2 --- a/compliance/controls/aws/aws_foundational_security_sagemaker_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_sagemaker_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether direct internet access is disabled for an SageMaker notebook instance. To do this, it checks whether the DirectInternetAccess field is disabled for the notebook instance. If you configure your SageMaker instance without a VPC, then by default direct internet access is enabled on your instance. You should configure your instance with a VPC and change the default setting to Disable — Access the internet through a VPC. ID: aws_foundational_security_sagemaker_1 -Title: "1 SageMaker notebook instances should not have direct internet access" -Description: "This control checks whether direct internet access is disabled for an SageMaker notebook instance. To do this, it checks whether the DirectInternetAccess field is disabled for the notebook instance. If you configure your SageMaker instance without a VPC, then by default direct internet access is enabled on your instance. You should configure your instance with a VPC and change the default setting to Disable — Access the internet through a VPC." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when direct_internet_access = 'Enabled' then 'alarm' - else 'ok' - end status, - case - when direct_internet_access = 'Enabled' then title || ' direct internet access enabled.' - else title || ' direct internet access disabled.' - end reason - from - aws_sagemaker_notebook_instance; - PrimaryTable: aws_sagemaker_notebook_instance ListOfTables: - aws_sagemaker_notebook_instance Parameters: [] + PrimaryTable: aws_sagemaker_notebook_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN direct_internet_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN direct_internet_access = 'Enabled' THEN title || ' direct internet access enabled.' + ELSE title || ' direct internet access disabled.' + END AS reason + FROM + aws_sagemaker_notebook_instance; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 SageMaker notebook instances should not have direct internet access \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_sagemaker_2.yaml b/compliance/controls/aws/aws_foundational_security_sagemaker_2.yaml old mode 100755 new mode 100644 index c7208f136..c6c121f8d --- a/compliance/controls/aws/aws_foundational_security_sagemaker_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_sagemaker_2.yaml @@ -1,28 +1,28 @@ +Description: This control checks if an Amazon SageMaker notebook instance is launched within a custom virtual private cloud (VPC). This control fails if a SageMaker notebook instance is not launched within a custom VPC or if it is launched in the SageMaker service VPC. ID: aws_foundational_security_sagemaker_2 -Title: "2 SageMaker notebook instances should be launched in a custom VPC" -Description: "This control checks if an Amazon SageMaker notebook instance is launched within a custom virtual private cloud (VPC). This control fails if a SageMaker notebook instance is not launched within a custom VPC or if it is launched in the SageMaker service VPC." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when subnet_id is not null then 'ok' - else 'alarm' - end as status, - case - when subnet_id is not null then title || ' in VPC.' - else title || ' not in VPC.' - end as reason - from - aws_sagemaker_notebook_instance; - PrimaryTable: aws_sagemaker_notebook_instance ListOfTables: - aws_sagemaker_notebook_instance Parameters: [] + PrimaryTable: aws_sagemaker_notebook_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN subnet_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN subnet_id IS NOT NULL THEN title || ' in VPC.' + ELSE title || ' not in VPC.' + END AS reason + FROM + aws_sagemaker_notebook_instance; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 SageMaker notebook instances should be launched in a custom VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_sagemaker_3.yaml b/compliance/controls/aws/aws_foundational_security_sagemaker_3.yaml old mode 100755 new mode 100644 index 4fc9941d7..9ae1910a7 --- a/compliance/controls/aws/aws_foundational_security_sagemaker_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_sagemaker_3.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether root access is turned on for an Amazon SageMaker notebook instance. The control fails if root access is turned on for a SageMaker notebook instance. ID: aws_foundational_security_sagemaker_3 -Title: "3 Users should not have root access to SageMaker notebook instances" -Description: "This control checks whether root access is turned on for an Amazon SageMaker notebook instance. The control fails if root access is turned on for a SageMaker notebook instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when root_access = 'Disabled' then 'ok' - else 'alarm' - end as status, - case - when root_access = 'Disabled' then title || ' root access disabled.' - else title || ' root access enabled.' - end as reason - from - aws_sagemaker_notebook_instance; - PrimaryTable: aws_sagemaker_notebook_instance ListOfTables: - aws_sagemaker_notebook_instance Parameters: [] + PrimaryTable: aws_sagemaker_notebook_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN root_access = 'Disabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN root_access = 'Disabled' THEN title || ' root access disabled.' + ELSE title || ' root access enabled.' + END AS reason + FROM + aws_sagemaker_notebook_instance; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Users should not have root access to SageMaker notebook instances \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_secretsmanager_1.yaml b/compliance/controls/aws/aws_foundational_security_secretsmanager_1.yaml old mode 100755 new mode 100644 index d9b75f832..2b12ff15f --- a/compliance/controls/aws/aws_foundational_security_secretsmanager_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_secretsmanager_1.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether a secret stored in AWS Secrets Manager is configured with automatic rotation. Secrets Manager helps you improve the security posture of your organization. Secrets include database credentials, passwords, and third-party API keys. You can use Secrets Manager to store secrets centrally, encrypt secrets automatically, control access to secrets, and rotate secrets safely and automatically. ID: aws_foundational_security_secretsmanager_1 -Title: "1 Secrets Manager secrets should have automatic rotation enabled" -Description: "This control checks whether a secret stored in AWS Secrets Manager is configured with automatic rotation. Secrets Manager helps you improve the security posture of your organization. Secrets include database credentials, passwords, and third-party API keys. You can use Secrets Manager to store secrets centrally, encrypt secrets automatically, control access to secrets, and rotate secrets safely and automatically." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when rotation_rules is null then 'alarm'\n else 'ok'\n end as status,\n case\n when rotation_rules is null then title || ' automatic rotation not enabled.'\n else title || ' automatic rotation enabled.'\n end as reason\n \n \nfrom\n aws_secretsmanager_secret;" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN rotation_rules IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN rotation_rules IS NULL THEN title || ' automatic rotation not enabled.' + ELSE title || ' automatic rotation enabled.' + END AS reason + FROM + aws_secretsmanager_secret; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Secrets Manager secrets should have automatic rotation enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_secretsmanager_2.yaml b/compliance/controls/aws/aws_foundational_security_secretsmanager_2.yaml old mode 100755 new mode 100644 index 3d616fa43..32979de4c --- a/compliance/controls/aws/aws_foundational_security_secretsmanager_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_secretsmanager_2.yaml @@ -1,14 +1,40 @@ +Description: This control checks whether an AWS Secrets Manager secret rotated successfully based on the rotation schedule. The control fails if RotationOccurringAsScheduled is false. The control does not evaluate secrets that do not have rotation configured. ID: aws_foundational_security_secretsmanager_2 -Title: "2 Secrets Manager secrets configured with automatic rotation should rotate successfully" -Description: "This control checks whether an AWS Secrets Manager secret rotated successfully based on the rotation schedule. The control fails if RotationOccurringAsScheduled is false. The control does not evaluate secrets that do not have rotation configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when primary_region is not null and region != primary_region then 'skip' -- Replica secret\n when rotation_rules is null then 'alarm' -- Rotation not enabled\n when last_rotated_date is null\n and (date(current_date) - date(created_date)) <= (rotation_rules -> 'AutomaticallyAfterDays')::integer then 'ok' -- New secret not due for rotation yet\n when last_rotated_date is null\n and (date(current_date) - date(created_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer then 'alarm' -- New secret overdue for rotation\n when last_rotated_date is not null\n and (date(current_date) - date(last_rotated_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer then 'alarm' -- Secret has been rotated before but is overdue for another rotation\n end as status,\n case\n when primary_region is not null and region != primary_region then title || ' is a replica.'\n when rotation_rules is null then title || ' rotation not enabled.'\n when last_rotated_date is null\n and (date(current_date) - date(created_date)) <= (rotation_rules -> 'AutomaticallyAfterDays')::integer then title || ' scheduled for rotation.'\n when last_rotated_date is null\n and (date(current_date) - date(created_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer then title || ' not rotated as per schedule.'\n when last_rotated_date is not null\n and (date(current_date) - date(last_rotated_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer then title || ' not rotated as per schedule.'\n end as reason\n \n \nfrom\n aws_secretsmanager_secret;" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN primary_region IS NOT NULL AND region != primary_region THEN 'skip' + WHEN rotation_rules IS NULL THEN 'alarm' + WHEN last_rotated_date IS NULL + AND (DATE(current_date) - DATE(created_date)) <= (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN 'ok' + WHEN last_rotated_date IS NULL + AND (DATE(current_date) - DATE(created_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN 'alarm' + WHEN last_rotated_date IS NOT NULL + AND (DATE(current_date) - DATE(last_rotated_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN 'alarm' + END AS status, + CASE + WHEN primary_region IS NOT NULL AND region != primary_region THEN title || ' is a replica.' + WHEN rotation_rules IS NULL THEN title || ' rotation not enabled.' + WHEN last_rotated_date IS NULL + AND (DATE(current_date) - DATE(created_date)) <= (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN title || ' scheduled for rotation.' + WHEN last_rotated_date IS NULL + AND (DATE(current_date) - DATE(created_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN title || ' not rotated as per schedule.' + WHEN last_rotated_date IS NOT NULL + AND (DATE(current_date) - DATE(last_rotated_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN title || ' not rotated as per schedule.' + END AS reason + FROM + aws_secretsmanager_secret; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Secrets Manager secrets configured with automatic rotation should rotate successfully \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_secretsmanager_3.yaml b/compliance/controls/aws/aws_foundational_security_secretsmanager_3.yaml old mode 100755 new mode 100644 index 0626827e1..8770e33e3 --- a/compliance/controls/aws/aws_foundational_security_secretsmanager_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_secretsmanager_3.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether an AWS Secrets Manager secret has been accessed within the specified time frame. The control fails if a secret is unused beyond the specified time frame. Unless you provide a custom parameter value for the access period, Security Hub uses a default value of 90 days ID: aws_foundational_security_secretsmanager_3 -Title: "3 Remove unused Secrets Manager secrets" -Description: "This control checks whether an AWS Secrets Manager secret has been accessed within the specified time frame. The control fails if a secret is unused beyond the specified time frame. Unless you provide a custom parameter value for the access period, Security Hub uses a default value of 90 days" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when last_accessed_date is null then 'alarm'\n when date(current_date) - date(last_accessed_date) <= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when last_accessed_date is null then title || ' never accessed.'\n else\n title || ' last used ' || extract(day from current_timestamp - last_accessed_date) || ' day(s) ago.'\n end as reason\n \n \nfrom\n aws_secretsmanager_secret;" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN last_accessed_date IS NULL THEN 'alarm' + WHEN DATE(current_date) - DATE(last_accessed_date) <= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN last_accessed_date IS NULL THEN title || ' never accessed.' + ELSE + title || ' last used ' || EXTRACT(DAY FROM current_timestamp - last_accessed_date) || ' day(s) ago.' + END AS reason + FROM + aws_secretsmanager_secret; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Remove unused Secrets Manager secrets \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_secretsmanager_4.yaml b/compliance/controls/aws/aws_foundational_security_secretsmanager_4.yaml old mode 100755 new mode 100644 index a18ada4ef..233118749 --- a/compliance/controls/aws/aws_foundational_security_secretsmanager_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_secretsmanager_4.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether your secrets have been rotated at least once within 90 days. Rotating secrets can help you to reduce the risk of an unauthorized use of your secrets in your AWS account. Examples include database credentials, passwords, third-party API keys, and even arbitrary text. If you do not change your secrets for a long period of time, the secrets are more likely to be compromised. ID: aws_foundational_security_secretsmanager_4 -Title: "4 Secrets Manager secrets should be rotated within a specified number of days" -Description: "This control checks whether your secrets have been rotated at least once within 90 days. Rotating secrets can help you to reduce the risk of an unauthorized use of your secrets in your AWS account. Examples include database credentials, passwords, third-party API keys, and even arbitrary text. If you do not change your secrets for a long period of time, the secrets are more likely to be compromised." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when rotation_rules is not null and rotation_lambda_arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when rotation_rules is not null and rotation_lambda_arn is not null then title || ' scheduled for rotation using Lambda function.'\n else title || ' automatic rotation using Lambda function disabled.'\n end as reason\n \n \nfrom\n aws_secretsmanager_secret;" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN rotation_rules IS NOT NULL AND rotation_lambda_arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN rotation_rules IS NOT NULL AND rotation_lambda_arn IS NOT NULL THEN title || ' scheduled for rotation using Lambda function.' + ELSE title || ' automatic rotation using Lambda function disabled.' + END AS reason + FROM + aws_secretsmanager_secret; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 Secrets Manager secrets should be rotated within a specified number of days \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_sfn_1.yaml b/compliance/controls/aws/aws_foundational_security_sfn_1.yaml old mode 100755 new mode 100644 index 86ea748a2..ec8c9c4cf --- a/compliance/controls/aws/aws_foundational_security_sfn_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_sfn_1.yaml @@ -1,14 +1,28 @@ +Description: This controls checks whether an AWS Step Functions state machine has logging turned on. The control fails if a state machine doesn't have logging turned on. If you provide a custom value for the logLevel parameter, the control passes only if the state machine has the specified logging level turned on. ID: aws_foundational_security_sfn_1 -Title: "1 Step Functions state machines should have logging turned on" -Description: "This controls checks whether an AWS Step Functions state machine has logging turned on. The control fails if a state machine doesn't have logging turned on. If you provide a custom value for the logLevel parameter, the control passes only if the state machine has the specified logging level turned on." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when logging_configuration ->> 'Level' = 'OFF' then 'alarm'\n else 'ok'\n end as status,\n case\n when logging_configuration ->> 'Level' = 'OFF' then title || ' loggging disabled.'\n else title || ' loggging enabled.'\n end as reason\n \n \nfrom\n aws_sfn_state_machine;" - PrimaryTable: aws_sfn_state_machine ListOfTables: - aws_sfn_state_machine Parameters: [] + PrimaryTable: aws_sfn_state_machine + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logging_configuration ->> 'Level' = 'OFF' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN logging_configuration ->> 'Level' = 'OFF' THEN title || ' logging disabled.' + ELSE title || ' logging enabled.' + END AS reason + FROM + aws_sfn_state_machine; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Step Functions state machines should have logging turned on \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_sns_1.yaml b/compliance/controls/aws/aws_foundational_security_sns_1.yaml old mode 100755 new mode 100644 index 60777d277..7e7bca241 --- a/compliance/controls/aws/aws_foundational_security_sns_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_sns_1.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an SNS topic is encrypted at rest using AWS KMS. ID: aws_foundational_security_sns_1 -Title: "1 SNS topics should be encrypted at rest using AWS KMS" -Description: "This control checks whether an SNS topic is encrypted at rest using AWS KMS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - topic_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when kms_master_key_id is null then 'alarm' - else 'ok' - end as status, - case - when kms_master_key_id is null then title || ' encryption at rest disabled.' - else title || ' encryption at rest enabled.' - end as reason - from - aws_sns_topic; - PrimaryTable: aws_sns_topic ListOfTables: - aws_sns_topic Parameters: [] + PrimaryTable: aws_sns_topic + QueryToExecute: | + SELECT + topic_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_master_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_master_key_id IS NULL THEN title || ' encryption at rest disabled.' + ELSE title || ' encryption at rest enabled.' + END AS reason + FROM + aws_sns_topic; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: SNS topics should be encrypted at rest using AWS KMS \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_sns_2.yaml b/compliance/controls/aws/aws_foundational_security_sns_2.yaml old mode 100755 new mode 100644 index 602bcd93d..01fbce047 --- a/compliance/controls/aws/aws_foundational_security_sns_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_sns_2.yaml @@ -1,36 +1,36 @@ +Description: This control checks whether logging is enabled for the delivery status of notification messages sent to an Amazon SNS topic for the endpoints. This control fails if the delivery status notification for messages is not enabled. ID: aws_foundational_security_sns_2 -Title: "2 Logging of delivery status should be enabled for notification messages sent to a topic" -Description: "This control checks whether logging is enabled for the delivery status of notification messages sent to an Amazon SNS topic for the endpoints. This control fails if the delivery status notification for messages is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - topic_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when application_failure_feedback_role_arn is null - and firehose_failure_feedback_role_arn is null - and http_failure_feedback_role_arn is null - and lambda_failure_feedback_role_arn is null - and sqs_failure_feedback_role_arn is null then 'alarm' - else 'ok' - end as status, - case - when application_failure_feedback_role_arn is null - and firehose_failure_feedback_role_arn is null - and http_failure_feedback_role_arn is null - and lambda_failure_feedback_role_arn is null - and sqs_failure_feedback_role_arn is null then title || ' has delivery status logging for notification messages disabled.' - else title || ' has delivery status logging for notification messages enabled.' - end as reason - from - aws_sns_topic; - PrimaryTable: aws_sns_topic ListOfTables: - aws_sns_topic Parameters: [] + PrimaryTable: aws_sns_topic + QueryToExecute: | + SELECT + topic_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN application_failure_feedback_role_arn IS NULL + AND firehose_failure_feedback_role_arn IS NULL + AND http_failure_feedback_role_arn IS NULL + AND lambda_failure_feedback_role_arn IS NULL + AND sqs_failure_feedback_role_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN application_failure_feedback_role_arn IS NULL + AND firehose_failure_feedback_role_arn IS NULL + AND http_failure_feedback_role_arn IS NULL + AND lambda_failure_feedback_role_arn IS NULL + AND sqs_failure_feedback_role_arn IS NULL THEN title || ' has delivery status logging for notification messages disabled.' + ELSE title || ' has delivery status logging for notification messages enabled.' + END AS reason + FROM + aws_sns_topic; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 Logging of delivery status should be enabled for notification messages sent to a topic \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_sqs_1.yaml b/compliance/controls/aws/aws_foundational_security_sqs_1.yaml old mode 100755 new mode 100644 index 9ab2812c9..2e2d3d943 --- a/compliance/controls/aws/aws_foundational_security_sqs_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_sqs_1.yaml @@ -1,30 +1,30 @@ +Description: This control checks whether Amazon SQS queues are encrypted at rest. ID: aws_foundational_security_sqs_1 -Title: "1 Amazon SQS queues should be encrypted at rest" -Description: "This control checks whether Amazon SQS queues are encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - queue_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when sqs_managed_sse_enabled then 'ok' - when kms_master_key_id is null then 'alarm' - else 'ok' - end as status, - case - when sqs_managed_sse_enabled then title || ' secured with managed SQS-SSE.' - when kms_master_key_id is null then title || ' encryption at rest disabled.' - else title || ' encryption at rest enabled.' - end as reason - from - aws_sqs_queue; - PrimaryTable: aws_sqs_queue ListOfTables: - aws_sqs_queue Parameters: [] + PrimaryTable: aws_sqs_queue + QueryToExecute: | + SELECT + queue_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN sqs_managed_sse_enabled THEN 'ok' + WHEN kms_master_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sqs_managed_sse_enabled THEN title || ' secured with managed SQS-SSE.' + WHEN kms_master_key_id IS NULL THEN title || ' encryption at rest disabled.' + ELSE title || ' encryption at rest enabled.' + END AS reason + FROM + aws_sqs_queue; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 Amazon SQS queues should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ssm_1.yaml b/compliance/controls/aws/aws_foundational_security_ssm_1.yaml old mode 100755 new mode 100644 index 1d47b2e00..9de0112d7 --- a/compliance/controls/aws/aws_foundational_security_ssm_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_ssm_1.yaml @@ -1,15 +1,33 @@ +Description: This control checks whether the EC2 instances in your account are managed by AWS Systems Manager. Systems Manager is an AWS service that you can use to view and control your AWS infrastructure. To help you to maintain security and compliance, Systems Manager scans your managed instances. A managed instance is a machine that is configured for use with Systems Manager. Systems Manager then reports or takes corrective action on any policy violations that it detects. Systems Manager also helps you to configure and maintain your managed instances. ID: aws_foundational_security_ssm_1 -Title: "1 EC2 instances should be managed by AWS Systems Manager" -Description: "This control checks whether the EC2 instances in your account are managed by AWS Systems Manager. Systems Manager is an AWS service that you can use to view and control your AWS infrastructure. To help you to maintain security and compliance, Systems Manager scans your managed instances. A managed instance is a machine that is configured for use with Systems Manager. Systems Manager then reports or takes corrective action on any policy violations that it detects. Systems Manager also helps you to configure and maintain your managed instances." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n i.arn as resource,\n i.og_account_id as og_account_id,\n i.og_resource_id as og_resource_id,\n case\n when i.instance_state = 'stopped' then 'info'\n when m.instance_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when i.instance_state = 'stopped' then i.title || ' is in stopped state.'\n when m.instance_id is null then i.title || ' not managed by AWS SSM.'\n else i.title || ' managed by AWS SSM.'\n end as reason\n \n \nfrom\n aws_ec2_instance i\n left join aws_ssm_managed_instance m on m.instance_id = i.instance_id;" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance - aws_ssm_managed_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN i.instance_state = 'stopped' THEN 'info' + WHEN m.instance_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.instance_state = 'stopped' THEN i.title || ' is in stopped state.' + WHEN m.instance_id IS NULL THEN i.title || ' not managed by AWS SSM.' + ELSE i.title || ' managed by AWS SSM.' + END AS reason + FROM + aws_ec2_instance i + LEFT JOIN + aws_ssm_managed_instance m ON m.instance_id = i.instance_id; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 EC2 instances should be managed by AWS Systems Manager \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ssm_2.yaml b/compliance/controls/aws/aws_foundational_security_ssm_2.yaml old mode 100755 new mode 100644 index 7c21e9851..ac45a201e --- a/compliance/controls/aws/aws_foundational_security_ssm_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_ssm_2.yaml @@ -1,35 +1,35 @@ +Description: This control checks whether the compliance status of the Amazon EC2 Systems Manager patch compliance is COMPLIANT or non compliant after the patch installation on the instance. It only checks instances that are managed by Systems Manager Patch Manager. ID: aws_foundational_security_ssm_2 -Title: "2 All EC2 instances managed by Systems Manager should be compliant with patching requirements" -Description: "This control checks whether the compliance status of the Amazon EC2 Systems Manager patch compliance is COMPLIANT or non compliant after the patch installation on the instance. It only checks instances that are managed by Systems Manager Patch Manager." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when c.status = '' then 'skip' - when c.status = 'COMPLIANT' then 'ok' - else 'alarm' - end as status, - case - when c.status = '' then 'Patch is not applicable for instance ' || i.title || '.' - when c.status = 'COMPLIANT' then c.resource_id || ' patch ' || c.title || ' is compliant.' - else c.resource_id || ' patch ' || c.title || ' is non-compliant.' - end as reason - from - aws_ssm_managed_instance as i, - aws_ssm_managed_instance_compliance as c - where - c.resource_id = i.instance_id - and c.compliance_type = 'Patch'; - PrimaryTable: aws_ssm_managed_instance ListOfTables: - aws_ssm_managed_instance - aws_ssm_managed_instance_compliance Parameters: [] + PrimaryTable: aws_ssm_managed_instance + QueryToExecute: | + SELECT + i.id AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN c.status = '' THEN 'skip' + WHEN c.status = 'COMPLIANT' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.status = '' THEN 'Patch is not applicable for instance ' || i.title || '.' + WHEN c.status = 'COMPLIANT' THEN c.resource_id || ' patch ' || c.title || ' is compliant.' + ELSE c.resource_id || ' patch ' || c.title || ' is non-compliant.' + END AS reason + FROM + aws_ssm_managed_instance AS i, + aws_ssm_managed_instance_compliance AS c + WHERE + c.resource_id = i.instance_id + AND c.compliance_type = 'Patch'; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 All EC2 instances managed by Systems Manager should be compliant with patching requirements \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ssm_3.yaml b/compliance/controls/aws/aws_foundational_security_ssm_3.yaml old mode 100755 new mode 100644 index 632d29ab7..babb8f4e7 --- a/compliance/controls/aws/aws_foundational_security_ssm_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_ssm_3.yaml @@ -1,33 +1,33 @@ +Description: This control checks whether the status of the AWS Systems Manager association compliance is COMPLIANT or non compliant after the association is run on an instance. The control passes if the association compliance status is COMPLIANT. ID: aws_foundational_security_ssm_3 -Title: "3 Instances managed by Systems Manager should have an association compliance status of COMPLIANT" -Description: "This control checks whether the status of the AWS Systems Manager association compliance is COMPLIANT or non compliant after the association is run on an instance. The control passes if the association compliance status is COMPLIANT." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when c.status = 'COMPLIANT' then 'ok' - else 'alarm' - end as status, - case - when c.status = 'COMPLIANT' then c.resource_id || ' association ' || c.title || ' is compliant.' - else c.resource_id || ' association ' || c.title || ' is non-compliant.' - end as reason - from - aws_ssm_managed_instance as i, - aws_ssm_managed_instance_compliance as c - where - c.resource_id = i.instance_id - and c.compliance_type = 'Association'; - PrimaryTable: aws_ssm_managed_instance ListOfTables: - aws_ssm_managed_instance - aws_ssm_managed_instance_compliance Parameters: [] + PrimaryTable: aws_ssm_managed_instance + QueryToExecute: | + SELECT + id AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN c.status = 'COMPLIANT' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.status = 'COMPLIANT' THEN c.resource_id || ' association ' || c.title || ' is compliant.' + ELSE c.resource_id || ' association ' || c.title || ' is non-compliant.' + END AS reason + FROM + aws_ssm_managed_instance AS i, + aws_ssm_managed_instance_compliance AS c + WHERE + c.resource_id = i.instance_id + AND c.compliance_type = 'Association'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Instances managed by Systems Manager should have an association compliance status of COMPLIANT \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_ssm_4.yaml b/compliance/controls/aws/aws_foundational_security_ssm_4.yaml old mode 100755 new mode 100644 index d68bfc59e..71fdee54f --- a/compliance/controls/aws/aws_foundational_security_ssm_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_ssm_4.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether AWS Systems Manager documents that are owned by the account are public. This control fails if SSM documents with the owner Self are public. ID: aws_foundational_security_ssm_4 -Title: "4 SSM documents should not be public" -Description: "This control checks whether AWS Systems Manager documents that are owned by the account are public. This control fails if SSM documents with the owner Self are public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':ssm:' || region || ':' || account_id || ':document/' || name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_ids :: jsonb ? 'all' then 'alarm'\n else 'ok'\n end as status,\n case\n when account_ids :: jsonb ? 'all' then title || ' publicly accesible.'\n else title || ' not publicly accesible.'\n end as reason\n \n \nfrom\n aws_ssm_document\nwhere\n owner_type = 'Self';" - PrimaryTable: aws_ssm_document ListOfTables: - aws_ssm_document Parameters: [] + PrimaryTable: aws_ssm_document + QueryToExecute: | + SELECT + 'arn:' || partition || ':ssm:' || region || ':' || account_id || ':document/' || name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_ids :: jsonb ? 'all' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN account_ids :: jsonb ? 'all' THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_ssm_document + WHERE + owner_type = 'Self'; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 SSM documents should not be public \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_waf_1.yaml b/compliance/controls/aws/aws_foundational_security_waf_1.yaml old mode 100755 new mode 100644 index 857f0e45c..d56afd5b6 --- a/compliance/controls/aws/aws_foundational_security_waf_1.yaml +++ b/compliance/controls/aws/aws_foundational_security_waf_1.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether logging is enabled for an AWS WAF global web ACL. This control fails if logging is not enabled for the web ACL. ID: aws_foundational_security_waf_1 -Title: "1 AWS WAF Classic Global Web ACL logging should be enabled" -Description: "This control checks whether logging is enabled for an AWS WAF global web ACL. This control fails if logging is not enabled for the web ACL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when logging_configuration is null then 'alarm'\n else 'ok'\n end as status,\n case\n when logging_configuration is null then title || ' logging disabled.'\n else title || ' logging enabled.'\n end as reason\n \n \nfrom\n aws_waf_web_acl;" - PrimaryTable: aws_waf_web_acl ListOfTables: - aws_waf_web_acl Parameters: [] + PrimaryTable: aws_waf_web_acl + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logging_configuration IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN logging_configuration IS NULL THEN title || ' logging disabled.' + ELSE title || ' logging enabled.' + END AS reason + FROM + aws_waf_web_acl; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 AWS WAF Classic Global Web ACL logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_waf_10.yaml b/compliance/controls/aws/aws_foundational_security_waf_10.yaml old mode 100755 new mode 100644 index f2329281f..6182173fb --- a/compliance/controls/aws/aws_foundational_security_waf_10.yaml +++ b/compliance/controls/aws/aws_foundational_security_waf_10.yaml @@ -1,41 +1,41 @@ +Description: This control checks whether a WAFV2 web access control list (web ACL) contains at least one WAF rule or WAF rule group. The control fails if a web ACL does not contain any WAF rules or rule groups. ID: aws_foundational_security_waf_10 -Title: "10 AWS WAF web ACLs should have at least one rule or rule group" -Description: "This control checks whether a WAFV2 web access control list (web ACL) contains at least one WAF rule or WAF rule group. The control fails if a web ACL does not contain any WAF rules or rule groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with rule_group_count as ( - select + ListOfTables: + - aws_wafv2_web_acl + Parameters: [] + PrimaryTable: aws_wafv2_web_acl + QueryToExecute: | + WITH rule_group_count AS ( + SELECT arn, - count(*) as rule_group_count - from + COUNT(*) AS rule_group_count + FROM aws_wafv2_web_acl, - jsonb_array_elements(rules) as r - where - r -> 'Statement' -> 'RuleGroupReferenceStatement' ->> 'ARN' is not null - group by + jsonb_array_elements(rules) AS r + WHERE + r -> 'Statement' -> 'RuleGroupReferenceStatement' ->> 'ARN' IS NOT NULL + GROUP BY arn ) - select - a.arn as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when rules is null or jsonb_array_length(rules) = 0 then 'alarm' - else 'ok' - end as status, - case - when rules is null or jsonb_array_length(rules) = 0 then title || ' has no attached rules.' - else title || ' has ' || c.rule_group_count || ' rule group(s) and ' || (jsonb_array_length(rules) - c.rule_group_count) || ' rule(s) attached.' - end as reason - from - aws_wafv2_web_acl as a - left join rule_group_count as c on c.arn = a.arn; - PrimaryTable: aws_wafv2_web_acl - ListOfTables: - - aws_wafv2_web_acl - Parameters: [] + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN title || ' has no attached rules.' + ELSE title || ' has ' || c.rule_group_count || ' rule group(s) and ' || (jsonb_array_length(rules) - c.rule_group_count) || ' rule(s) attached.' + END AS reason + FROM + aws_wafv2_web_acl AS a + LEFT JOIN rule_group_count AS c ON c.arn = a.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 10 AWS WAF web ACLs should have at least one rule or rule group \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_waf_12.yaml b/compliance/controls/aws/aws_foundational_security_waf_12.yaml old mode 100755 new mode 100644 index 871de6471..8e6c25242 --- a/compliance/controls/aws/aws_foundational_security_waf_12.yaml +++ b/compliance/controls/aws/aws_foundational_security_waf_12.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an AWS WAF rule or rule group has Amazon CloudWatch metrics enabled. The control fails if the rule or rule group doesn't have CloudWatch metrics enabled. ID: aws_foundational_security_waf_12 -Title: "12 AWS WAF rules should have CloudWatch metrics enabled" -Description: "This control checks whether an AWS WAF rule or rule group has Amazon CloudWatch metrics enabled. The control fails if the rule or rule group doesn't have CloudWatch metrics enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when (visibility_config ->> 'CloudWatchMetricsEnabled')::bool then 'ok' - else 'alarm' - end as status, - case - when (visibility_config ->> 'CloudWatchMetricsEnabled')::bool then title || ' logging enabled.' - else title || ' logging disabled.' - end as reason - from - aws_wafv2_rule_group; - PrimaryTable: aws_wafv2_rule_group ListOfTables: - aws_wafv2_rule_group Parameters: [] + PrimaryTable: aws_wafv2_rule_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (visibility_config ->> 'CloudWatchMetricsEnabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (visibility_config ->> 'CloudWatchMetricsEnabled')::bool THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason + FROM + aws_wafv2_rule_group; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 12 AWS WAF rules should have CloudWatch metrics enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_waf_2.yaml b/compliance/controls/aws/aws_foundational_security_waf_2.yaml old mode 100755 new mode 100644 index a11a020fa..22ab3ea56 --- a/compliance/controls/aws/aws_foundational_security_waf_2.yaml +++ b/compliance/controls/aws/aws_foundational_security_waf_2.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an AWS WAF Regional rule has at least one condition. The control fails if no conditions are present within a rule. ID: aws_foundational_security_waf_2 -Title: "2 AWS WAF Classic Regional rules should have at least one condition" -Description: "This control checks whether an AWS WAF Regional rule has at least one condition. The control fails if no conditions are present within a rule." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n rule_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when predicates is null or jsonb_array_length(predicates) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when predicates is null or jsonb_array_length(predicates) = 0 then title || ' has no attached conditions.'\n else title || ' has ' || jsonb_array_length(predicates) || ' condition(s) attached.'\n end as reason\n \nfrom\n aws_wafregional_rule;" - PrimaryTable: aws_wafregional_rule ListOfTables: - aws_wafregional_rule Parameters: [] + PrimaryTable: aws_wafregional_rule + QueryToExecute: | + SELECT + rule_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN predicates IS NULL OR jsonb_array_length(predicates) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN predicates IS NULL OR jsonb_array_length(predicates) = 0 THEN title || ' has no attached conditions.' + ELSE title || ' has ' || jsonb_array_length(predicates) || ' condition(s) attached.' + END AS reason + FROM + aws_wafregional_rule; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 AWS WAF Classic Regional rules should have at least one condition \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_waf_3.yaml b/compliance/controls/aws/aws_foundational_security_waf_3.yaml old mode 100755 new mode 100644 index 038dfdb62..5910403b9 --- a/compliance/controls/aws/aws_foundational_security_waf_3.yaml +++ b/compliance/controls/aws/aws_foundational_security_waf_3.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an AWS WAF Regional rule group has at least one rule. The control fails if no rules are present within a rule group. ID: aws_foundational_security_waf_3 -Title: "3 AWS WAF Classic Regional rule groups should have at least one rule" -Description: "This control checks whether an AWS WAF Regional rule group has at least one rule. The control fails if no rules are present within a rule group." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when activated_rules is null or jsonb_array_length(activated_rules) = 0 then 'alarm' - else 'ok' - end as status, - case - when activated_rules is null or jsonb_array_length(activated_rules) = 0 then title || ' has no attached rules.' - else title || ' has ' || jsonb_array_length(activated_rules) || ' rule(s) attached.' - end as reason - from - aws_wafregional_rule_group; - PrimaryTable: aws_wafregional_rule_group ListOfTables: - aws_wafregional_rule_group Parameters: [] + PrimaryTable: aws_wafregional_rule_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN activated_rules IS NULL OR jsonb_array_length(activated_rules) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN activated_rules IS NULL OR jsonb_array_length(activated_rules) = 0 THEN title || ' has no attached rules.' + ELSE title || ' has ' || jsonb_array_length(activated_rules) || ' rule(s) attached.' + END AS reason + FROM + aws_wafregional_rule_group; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 AWS WAF Classic Regional rule groups should have at least one rule \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_waf_4.yaml b/compliance/controls/aws/aws_foundational_security_waf_4.yaml old mode 100755 new mode 100644 index afb1b94b3..89d801f02 --- a/compliance/controls/aws/aws_foundational_security_waf_4.yaml +++ b/compliance/controls/aws/aws_foundational_security_waf_4.yaml @@ -1,28 +1,29 @@ +Description: This control checks whether an AWS WAF Classic Regional web ACL contains any WAF rules or WAF rule groups. + This control fails if a web ACL does not contain any WAF rules or rule groups. ID: aws_foundational_security_waf_4 -Title: "4 AWS WAF Classic Regional web ACLs should have at least one rule or rule group" -Description: "This control checks whether an AWS WAF Classic Regional web ACL contains any WAF rules or WAF rule groups. This control fails if a web ACL does not contain any WAF rules or rule groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when rules is null or jsonb_array_length(rules) = 0 then 'alarm' - else 'ok' - end as status, - case - when rules is null or jsonb_array_length(rules) = 0 then title || ' has no attached rules.' - else title || ' has ' || jsonb_array_length(rules) || ' rule(s) attached.' - end as reason - from - aws_wafregional_web_acl; - PrimaryTable: aws_wafregional_web_acl ListOfTables: - aws_wafregional_web_acl Parameters: [] + PrimaryTable: aws_wafregional_web_acl + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN title || ' has no attached rules.' + ELSE title || ' has ' || jsonb_array_length(rules) || ' rule(s) attached.' + END AS reason + FROM + aws_wafregional_web_acl; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 AWS WAF Classic Regional web ACLs should have at least one rule or rule group \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_waf_6.yaml b/compliance/controls/aws/aws_foundational_security_waf_6.yaml old mode 100755 new mode 100644 index 6ba9abd3c..bc597eb39 --- a/compliance/controls/aws/aws_foundational_security_waf_6.yaml +++ b/compliance/controls/aws/aws_foundational_security_waf_6.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an AWS WAF global rule contains any conditions. The control fails if no conditions are present within a rule. ID: aws_foundational_security_waf_6 -Title: "6 AWS WAF Classic global rules should have at least one condition" -Description: "This control checks whether an AWS WAF global rule contains any conditions. The control fails if no conditions are present within a rule." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n rule_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when predicates is null or jsonb_array_length(predicates) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when predicates is null or jsonb_array_length(predicates) = 0 then title || ' has no attached conditions.'\n else title || ' has ' || jsonb_array_length(predicates) || ' attached conditions.'\n end as reason\n \n \nfrom\n aws_waf_rule;" - PrimaryTable: aws_waf_rule ListOfTables: - aws_waf_rule Parameters: [] + PrimaryTable: aws_waf_rule + QueryToExecute: | + SELECT + rule_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN predicates IS NULL OR jsonb_array_length(predicates) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN predicates IS NULL OR jsonb_array_length(predicates) = 0 THEN title || ' has no attached conditions.' + ELSE title || ' has ' || jsonb_array_length(predicates) || ' attached conditions.' + END AS reason + FROM + aws_waf_rule; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 AWS WAF Classic global rules should have at least one condition \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_waf_7.yaml b/compliance/controls/aws/aws_foundational_security_waf_7.yaml old mode 100755 new mode 100644 index 06fdcfc6a..29d0fc827 --- a/compliance/controls/aws/aws_foundational_security_waf_7.yaml +++ b/compliance/controls/aws/aws_foundational_security_waf_7.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether an AWS WAF global rule group has at least one rule. The control fails if no rules are present within a rule group. ID: aws_foundational_security_waf_7 -Title: "7 AWS WAF Classic global rule groups should have at least one rule" -Description: "This control checks whether an AWS WAF global rule group has at least one rule. The control fails if no rules are present within a rule group." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when activated_rules is null or jsonb_array_length(activated_rules) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when activated_rules is null or jsonb_array_length(activated_rules) = 0 then title || ' has no attached rules.'\n else title || ' has ' || jsonb_array_length(activated_rules) || ' rule(s) attached.'\n end as reason\n \n \nfrom\n aws_waf_rule_group;" - PrimaryTable: aws_waf_rule_group ListOfTables: - aws_waf_rule_group Parameters: [] + PrimaryTable: aws_waf_rule_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN activated_rules IS NULL OR jsonb_array_length(activated_rules) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN activated_rules IS NULL OR jsonb_array_length(activated_rules) = 0 THEN title || ' has no attached rules.' + ELSE title || ' has ' || jsonb_array_length(activated_rules) || ' rule(s) attached.' + END AS reason + FROM + aws_waf_rule_group; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 AWS WAF Classic global rule groups should have at least one rule \ No newline at end of file diff --git a/compliance/controls/aws/aws_foundational_security_waf_8.yaml b/compliance/controls/aws/aws_foundational_security_waf_8.yaml old mode 100755 new mode 100644 index 2309d4057..3ddd2e3a1 --- a/compliance/controls/aws/aws_foundational_security_waf_8.yaml +++ b/compliance/controls/aws/aws_foundational_security_waf_8.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an AWS WAF global web ACL contains at least one WAF rule or WAF rule group. The control fails if a web ACL does not contain any WAF rules or rule groups. ID: aws_foundational_security_waf_8 -Title: "8 AWS WAF Classic global web ACLs should have at least one rule or rule group" -Description: "This control checks whether an AWS WAF global web ACL contains at least one WAF rule or WAF rule group. The control fails if a web ACL does not contain any WAF rules or rule groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when rules is null or jsonb_array_length(rules) = 0 then 'alarm' - else 'ok' - end as status, - case - when rules is null or jsonb_array_length(rules) = 0 then title || ' has no attached rules.' - else title || ' has ' || jsonb_array_length(rules) || ' rule(s) attached.' - end as reason - from - aws_waf_web_acl; - PrimaryTable: aws_waf_web_acl ListOfTables: - aws_waf_web_acl Parameters: [] + PrimaryTable: aws_waf_web_acl + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN title || ' has no attached rules.' + ELSE title || ' has ' || jsonb_array_length(rules) || ' rule(s) attached.' + END AS reason + FROM + aws_waf_web_acl; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 8 AWS WAF Classic global web ACLs should have at least one rule or rule group \ No newline at end of file diff --git a/compliance/controls/aws/aws_fsx_file_system_copy_tags_to_backup_and_volume_enabled.yaml b/compliance/controls/aws/aws_fsx_file_system_copy_tags_to_backup_and_volume_enabled.yaml old mode 100755 new mode 100644 index f452c4c2d..15f2e3007 --- a/compliance/controls/aws/aws_fsx_file_system_copy_tags_to_backup_and_volume_enabled.yaml +++ b/compliance/controls/aws/aws_fsx_file_system_copy_tags_to_backup_and_volume_enabled.yaml @@ -1,32 +1,39 @@ +Description: This control checks if an Amazon FSx for OpenZFS file system is configured to copy tags to backups and volumes. The control fails if the OpenZFS file system isn't configured to copy tags to backups and volumes. ID: aws_fsx_file_system_copy_tags_to_backup_and_volume_enabled -Title: "FSx for OpenZFS file systems should be configured to copy tags to backups and volumes" -Description: "This control checks if an Amazon FSx for OpenZFS file system is configured to copy tags to backups and volumes. The control fails if the OpenZFS file system isn't configured to copy tags to backups and volumes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when file_system_type <> 'OPENZFS' then 'skip' - when (open_zfs_configuration ->> 'CopyTagsToBackups')::bool and (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool then 'ok' - else 'alarm' - end as status, - case - when file_system_type <> 'OPENZFS' then title || ' is of ' || file_system_type || ' type file system.' - when (open_zfs_configuration ->> 'CopyTagsToBackups')::bool and (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool then title || ' copy tags to backup and volume enabled.' - when (open_zfs_configuration ->> 'CopyTagsToBackups')::bool then title || ' copy tags to backup enabled but disabled for volume.' - when (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool then title || ' copy tags to volume enabled but disabled for backup.' - else title || ' copy tags to backup and volume disabled.' - end as reason - from - aws_fsx_file_system; - PrimaryTable: aws_fsx_file_system ListOfTables: - aws_fsx_file_system Parameters: [] + PrimaryTable: aws_fsx_file_system + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN file_system_type <> 'OPENZFS' THEN 'skip' + WHEN (open_zfs_configuration ->> 'CopyTagsToBackups')::bool + AND (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN file_system_type <> 'OPENZFS' + THEN title || ' is of ' || file_system_type || ' type file system.' + WHEN (open_zfs_configuration ->> 'CopyTagsToBackups')::bool + AND (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool + THEN title || ' copy tags to backup and volume enabled.' + WHEN (open_zfs_configuration ->> 'CopyTagsToBackups')::bool + THEN title || ' copy tags to backup enabled but disabled for volume.' + WHEN (open_zfs_configuration ->> 'CopyTagsToVolumes')::bool + THEN title || ' copy tags to volume enabled but disabled for backup.' + ELSE title || ' copy tags to backup and volume disabled.' + END AS reason + FROM + aws_fsx_file_system; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: FSx for OpenZFS file systems should be configured to copy tags to backups and volumes \ No newline at end of file diff --git a/compliance/controls/aws/aws_fsx_file_system_protected_by_backup_plan.yaml b/compliance/controls/aws/aws_fsx_file_system_protected_by_backup_plan.yaml old mode 100755 new mode 100644 index 21764e7ef..5b7f15ba6 --- a/compliance/controls/aws/aws_fsx_file_system_protected_by_backup_plan.yaml +++ b/compliance/controls/aws/aws_fsx_file_system_protected_by_backup_plan.yaml @@ -1,14 +1,43 @@ +Description: Checks if AWS FSx File Systems are protected by a backup plan. The rule is non-compliant if the AWS FSx File System is not covered by a backup plan. ID: aws_fsx_file_system_protected_by_backup_plan -Title: "FSx file system should be protected by backup plan" -Description: "Checks if AWS FSx File Systems are protected by a backup plan. The rule is non-compliant if the AWS FSx File System is not covered by a backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with backup_protected_fsx_file_system as (\n select\n resource_arn as arn\n from\n aws_backup_protected_resource as b\n where\n resource_type = 'FSx'\n)\nselect\n f.arn as resource,\n f.og_account_id as og_account_id,\n f.og_resource_id as og_resource_id,\n case\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is not null then f.title || ' is protected by backup plan.'\n else f.title || ' is not protected by backup plan.'\n end as reason\n \n , f.region, f.account_id\nfrom\n aws_fsx_file_system as f\n left join backup_protected_fsx_file_system as b on f.arn = b.arn;\n" - PrimaryTable: aws_fsx_file_system ListOfTables: - aws_backup_protected_resource - aws_fsx_file_system Parameters: [] + PrimaryTable: aws_fsx_file_system + QueryToExecute: | + WITH backup_protected_fsx_file_system AS ( + SELECT + resource_arn AS arn + FROM + aws_backup_protected_resource AS b + WHERE + resource_type = 'FSx' + ) + SELECT + f.arn AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NOT NULL THEN f.title || ' is protected by backup plan.' + ELSE f.title || ' is not protected by backup plan.' + END AS reason, + f.region, + f.account_id + FROM + aws_fsx_file_system AS f + LEFT JOIN + backup_protected_fsx_file_system AS b + ON + f.arn = b.arn; Severity: high Tags: cisa_cyber_essentials: @@ -35,5 +64,4 @@ Tags: - AWS/FSx soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: FSx file system should be protected by backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_gatewayv2_stage_access_logging_enabled.yaml b/compliance/controls/aws/aws_gatewayv2_stage_access_logging_enabled.yaml old mode 100755 new mode 100644 index dadc309bc..2ce3ed063 --- a/compliance/controls/aws/aws_gatewayv2_stage_access_logging_enabled.yaml +++ b/compliance/controls/aws/aws_gatewayv2_stage_access_logging_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks if AWS API Gateway V2 stages have access logging configured. This control fails if access log settings aren't defined. ID: aws_gatewayv2_stage_access_logging_enabled -Title: "Access logging should be configured for API Gateway V2 Stages" -Description: "This control checks if AWS API Gateway V2 stages have access logging configured. This control fails if access log settings aren't defined." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/stages/' || stage_name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when access_log_settings is null then 'alarm'\n else 'ok'\n end as status,\n case\n when access_log_settings is null then title || ' access logging disabled.'\n else title || ' access logging enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_api_gatewayv2_stage;\n" - PrimaryTable: aws_api_gatewayv2_stage ListOfTables: - aws_api_gatewayv2_stage Parameters: [] + PrimaryTable: aws_api_gatewayv2_stage + QueryToExecute: | + SELECT + 'arn:' || partition || ':apigateway:' || region || '::/apis/' || api_id || '/stages/' || stage_name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN access_log_settings IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN access_log_settings IS NULL THEN title || ' access logging disabled.' + ELSE title || ' access logging enabled.' + END AS reason, + region, + account_id + FROM + aws_api_gatewayv2_stage; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/APIGateway -IntegrationType: - - aws_cloud_account +Title: Access logging should be configured for API Gateway V2 Stages \ No newline at end of file diff --git a/compliance/controls/aws/aws_glacier_vault_restrict_public_access.yaml b/compliance/controls/aws/aws_glacier_vault_restrict_public_access.yaml old mode 100755 new mode 100644 index fe145d15b..48c0312e8 --- a/compliance/controls/aws/aws_glacier_vault_restrict_public_access.yaml +++ b/compliance/controls/aws/aws_glacier_vault_restrict_public_access.yaml @@ -1,46 +1,46 @@ +Description: Manage access to resources in the AWS Cloud by ensuring AWS Glacier vault cannot be publicly accessed. ID: aws_glacier_vault_restrict_public_access -Title: "Glacier vault should restrict public access" -Description: "Manage access to resources in the AWS Cloud by ensuring AWS Glacier vault cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with wildcard_action_policies as ( - select + ListOfTables: + - aws_glacier_vault + Parameters: [] + PrimaryTable: aws_glacier_vault + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT vault_arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_glacier_vault, - jsonb_array_elements(policy_std -> 'Statement') as s - where + jsonb_array_elements(policy_std -> 'Statement') AS s + WHERE s ->> 'Effect' = 'Allow' - and ( - ( s -> 'Principal' -> 'AWS') = '["*"]' - or s ->> 'Principal' = '*' + AND ( + (s -> 'Principal' -> 'AWS') = '["*"]' + OR s ->> 'Principal' = '*' ) - group by + GROUP BY vault_arn ) - select - g.vault_arn as resource, - g.og_account_id as og_account_id, - g.og_resource_id as og_resource_id, - case - when p.vault_arn is null then 'ok' - else 'alarm' - end as status, - case - when p.vault_arn is null then title || ' does not allow public access.' - else title || ' contains ' || coalesce(p.statements_num, 0) || + SELECT + g.vault_arn AS resource, + g.og_account_id AS og_account_id, + g.og_resource_id AS og_resource_id, + CASE + WHEN p.vault_arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.vault_arn IS NULL THEN title || ' does not allow public access.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || ' statements that allow public access.' - end as reason - from - aws_glacier_vault as g - left join wildcard_action_policies as p on p.vault_arn = g.vault_arn; - PrimaryTable: aws_glacier_vault - ListOfTables: - - aws_glacier_vault - Parameters: [] + END AS reason + FROM + aws_glacier_vault AS g + LEFT JOIN wildcard_action_policies AS p ON p.vault_arn = g.vault_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Glacier vault should restrict public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_glue_connection_ssl_enabled.yaml b/compliance/controls/aws/aws_glue_connection_ssl_enabled.yaml old mode 100755 new mode 100644 index a989f6895..de082b0d9 --- a/compliance/controls/aws/aws_glue_connection_ssl_enabled.yaml +++ b/compliance/controls/aws/aws_glue_connection_ssl_enabled.yaml @@ -1,28 +1,28 @@ +Description: Ensure Glue connection encryption SSL is enabled. ID: aws_glue_connection_ssl_enabled -Title: "Glue connection SSL should be enabled" -Description: "Ensure Glue connection encryption SSL is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when connection_properties ->> 'JDBC_ENFORCE_SSL' = 'true' then 'ok' - else 'alarm' - end as status, - case - when connection_properties ->> 'JDBC_ENFORCE_SSL' = 'true' then name || ' SSL enabled.' - else name || ' SSL disabled.' - end as reason - from - aws_glue_connection; - PrimaryTable: aws_glue_connection ListOfTables: - aws_glue_connection Parameters: [] + PrimaryTable: aws_glue_connection + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN connection_properties ->> 'JDBC_ENFORCE_SSL' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN connection_properties ->> 'JDBC_ENFORCE_SSL' = 'true' THEN name || ' SSL enabled.' + ELSE name || ' SSL disabled.' + END AS reason + FROM + aws_glue_connection; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Glue connection SSL should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_glue_data_catalog_encryption_settings_metadata_encryption_enabled.yaml b/compliance/controls/aws/aws_glue_data_catalog_encryption_settings_metadata_encryption_enabled.yaml old mode 100755 new mode 100644 index e5a06b00b..37f33b587 --- a/compliance/controls/aws/aws_glue_data_catalog_encryption_settings_metadata_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_glue_data_catalog_encryption_settings_metadata_encryption_enabled.yaml @@ -1,14 +1,30 @@ +Description: Ensure Glue data catalog metadata encryption is enabled to protect sensitive information at rest. ID: aws_glue_data_catalog_encryption_settings_metadata_encryption_enabled -Title: "Glue data catalog metadata encryption should be enabled" -Description: "Ensure Glue data catalog metadata encryption is enabled to protect sensitive information at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || '::' || region || ':' || account_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encryption_at_rest is not null and encryption_at_rest ->> 'CatalogEncryptionMode' != 'DISABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption_at_rest is not null and encryption_at_rest ->> 'CatalogEncryptionMode' != 'DISABLED' then 'Glue data catalog metadata encryption is enabled in ' || region || '.'\n else 'Glue data catalog metadata encryption is disabled in ' || region || '.'\n end as reason\n \nfrom\n aws_glue_data_catalog_encryption_settings;" - PrimaryTable: aws_glue_data_catalog_encryption_settings ListOfTables: - aws_glue_data_catalog_encryption_settings Parameters: [] + PrimaryTable: aws_glue_data_catalog_encryption_settings + QueryToExecute: | + SELECT + 'arn:' || partition || '::' || region || ':' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encryption_at_rest IS NOT NULL + AND encryption_at_rest ->> 'CatalogEncryptionMode' != 'DISABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_at_rest IS NOT NULL + AND encryption_at_rest ->> 'CatalogEncryptionMode' != 'DISABLED' THEN 'Glue data catalog metadata encryption is enabled in ' || region || '.' + ELSE 'Glue data catalog metadata encryption is disabled in ' || region || '.' + END AS reason + FROM + aws_glue_data_catalog_encryption_settings; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Glue data catalog metadata encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_glue_data_catalog_encryption_settings_password_encryption_enabled.yaml b/compliance/controls/aws/aws_glue_data_catalog_encryption_settings_password_encryption_enabled.yaml old mode 100755 new mode 100644 index 948b91ebd..7560182ce --- a/compliance/controls/aws/aws_glue_data_catalog_encryption_settings_password_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_glue_data_catalog_encryption_settings_password_encryption_enabled.yaml @@ -1,28 +1,30 @@ +Description: Ensure Glue data catalog connection password encryption is enabled to protect sensitive information at rest. ID: aws_glue_data_catalog_encryption_settings_password_encryption_enabled -Title: "Glue data catalog connection password encryption should be enabled" -Description: "Ensure Glue data catalog connection password encryption is enabled to protect sensitive information at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || partition || '::' || region || ':' || account_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when connection_password_encryption is not null and connection_password_encryption ->> 'ReturnConnectionPasswordEncrypted' != 'false' then 'ok' - else 'alarm' - end as status, - case - when connection_password_encryption is not null and connection_password_encryption ->> 'ReturnConnectionPasswordEncrypted' != 'false' then 'Glue data catalog connection password encryption enabled in ' || region || '.' - else 'Glue data catalog connection password encryption disabled in ' || region || '.' - end as reason - from - aws_glue_data_catalog_encryption_settings; - PrimaryTable: aws_glue_data_catalog_encryption_settings ListOfTables: - aws_glue_data_catalog_encryption_settings Parameters: [] + PrimaryTable: aws_glue_data_catalog_encryption_settings + QueryToExecute: | + SELECT + 'arn:' || partition || '::' || region || ':' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN connection_password_encryption IS NOT NULL + AND connection_password_encryption ->> 'ReturnConnectionPasswordEncrypted' != 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN connection_password_encryption IS NOT NULL + AND connection_password_encryption ->> 'ReturnConnectionPasswordEncrypted' != 'false' THEN 'Glue data catalog connection password encryption enabled in ' || region || '.' + ELSE 'Glue data catalog connection password encryption disabled in ' || region || '.' + END AS reason + FROM + aws_glue_data_catalog_encryption_settings; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Glue data catalog connection password encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_glue_job_bookmarks_encryption_enabled.yaml b/compliance/controls/aws/aws_glue_job_bookmarks_encryption_enabled.yaml old mode 100755 new mode 100644 index 7c3de7af5..ca90e6e58 --- a/compliance/controls/aws/aws_glue_job_bookmarks_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_glue_job_bookmarks_encryption_enabled.yaml @@ -1,30 +1,37 @@ +Description: Ensure Glue job bookmarks have encryption enabled to protect sensitive information at rest. ID: aws_glue_job_bookmarks_encryption_enabled -Title: "Glue jobs bookmarks encryption should be enabled" -Description: "Ensure Glue job bookmarks have encryption enabled to protect sensitive information at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - j.arn as resource, - j.og_account_id as og_account_id, - j.og_resource_id as og_resource_id, - case - when job_bookmarks_encryption is not null and job_bookmarks_encryption ->> 'JobBookmarksEncryptionMode' != 'DISABLED' then 'ok' - else 'alarm' - end as status, - case - when job_bookmarks_encryption is not null and job_bookmarks_encryption ->> 'JobBookmarksEncryptionMode' != 'DISABLED' then j.title || ' job bookmarks encryption enabled.' - else j.title || ' job bookmarks encryption disabled.' - end as reason - from - aws_glue_job as j - left join aws_glue_security_configuration as c on j.security_configuration = c.name; - PrimaryTable: aws_glue_job ListOfTables: - aws_glue_job - aws_glue_security_configuration Parameters: [] + PrimaryTable: aws_glue_job + QueryToExecute: | + SELECT + j.arn AS resource, + j.og_account_id AS og_account_id, + j.og_resource_id AS og_resource_id, + CASE + WHEN job_bookmarks_encryption IS NOT NULL + AND job_bookmarks_encryption ->> 'JobBookmarksEncryptionMode' != 'DISABLED' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN job_bookmarks_encryption IS NOT NULL + AND job_bookmarks_encryption ->> 'JobBookmarksEncryptionMode' != 'DISABLED' + THEN j.title || ' job bookmarks encryption enabled.' + ELSE j.title || ' job bookmarks encryption disabled.' + END AS reason + FROM + aws_glue_job AS j + LEFT JOIN + aws_glue_security_configuration AS c + ON + j.security_configuration = c.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Glue jobs bookmarks encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_guardduty_enabled.yaml b/compliance/controls/aws/aws_guardduty_enabled.yaml old mode 100755 new mode 100644 index 38f159d87..35060e9be --- a/compliance/controls/aws/aws_guardduty_enabled.yaml +++ b/compliance/controls/aws/aws_guardduty_enabled.yaml @@ -1,38 +1,39 @@ +Description: AWS GuardDuty can help to monitor and detect potential cybersecurity events by using threat intelligence feeds. ID: aws_guardduty_enabled -Title: "GuardDuty should be enabled" -Description: "AWS GuardDuty can help to monitor and detect potential cybersecurity events by using threat intelligence feeds." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - when r.region = any(array['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) then 'skip' - -- Skip any regions that are disabled in the account. - when r.opt_in_status = 'not-opted-in' then 'skip' - when status = 'ENABLED' and master_account ->> 'AccountId' is null then 'ok' - when status = 'ENABLED' and master_account ->> 'AccountId' is not null then 'info' - else 'alarm' - end as status, - case - when r.region = any(array['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) then r.region || ' region not supported.' - when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.' - when status is null then 'No GuardDuty detector found in ' || r.region || '.' - when status = 'ENABLED' and master_account ->> 'AccountId' is null then r.region || ' detector ' || d.title || ' enabled.' - when status = 'ENABLED' and master_account ->> 'AccountId' is not null then r.region || ' detector ' || d.title || ' is managed by account ' || (master_account ->> 'AccountId') || ' via delegated admin.' - else r.region || ' detector ' || d.title || ' disabled.' - end as reason - , r.region, r.account_id - from - aws_region as r - left join aws_guardduty_detector d on r.account_id = d.account_id and r.name = d.region; - PrimaryTable: aws_region ListOfTables: - aws_guardduty_detector - aws_region Parameters: [] + PrimaryTable: aws_region + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN r.region = ANY(ARRAY['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) THEN 'skip' + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN status = 'ENABLED' AND master_account ->> 'AccountId' IS NULL THEN 'ok' + WHEN status = 'ENABLED' AND master_account ->> 'AccountId' IS NOT NULL THEN 'info' + ELSE 'alarm' + END AS status, + CASE + WHEN r.region = ANY(ARRAY['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) THEN r.region || ' region not supported.' + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN status IS NULL THEN 'No GuardDuty detector found in ' || r.region || '.' + WHEN status = 'ENABLED' AND master_account ->> 'AccountId' IS NULL THEN r.region || ' detector ' || d.title || ' enabled.' + WHEN status = 'ENABLED' AND master_account ->> 'AccountId' IS NOT NULL THEN r.region || ' detector ' || d.title || ' is managed by account ' || (master_account ->> 'AccountId') || ' via delegated admin.' + ELSE r.region || ' detector ' || d.title || ' disabled.' + END AS reason, + r.region, + r.account_id + FROM + aws_region AS r + LEFT JOIN aws_guardduty_detector d ON r.account_id = d.account_id AND r.name = d.region; Severity: medium Tags: category: @@ -55,12 +56,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -71,5 +72,4 @@ Tags: - AWS/GuardDuty soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: GuardDuty should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_guardduty_finding_archived.yaml b/compliance/controls/aws/aws_guardduty_finding_archived.yaml old mode 100755 new mode 100644 index 7a47e0b59..c2f59d0c5 --- a/compliance/controls/aws/aws_guardduty_finding_archived.yaml +++ b/compliance/controls/aws/aws_guardduty_finding_archived.yaml @@ -1,28 +1,30 @@ +Description: 'AWS GuardDuty helps you understand the impact of an incident by classifying findings by severity: low, medium, and high.' ID: aws_guardduty_finding_archived -Title: "GuardDuty findings should be archived" -Description: "AWS GuardDuty helps you understand the impact of an incident by classifying findings by severity: low, medium, and high." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when service ->> 'Archived' = 'false' then 'alarm' - else 'ok' - end as status, - case - when service ->> 'Archived' = 'false' then title || ' not archived.' - else title || ' archived.' - end as reason - , region, account_id - from - aws_guardduty_finding; - PrimaryTable: aws_guardduty_finding ListOfTables: - aws_guardduty_finding Parameters: [] + PrimaryTable: aws_guardduty_finding + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN service ->> 'Archived' = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN service ->> 'Archived' = 'false' THEN title || ' not archived.' + ELSE title || ' archived.' + END AS reason, + region, + account_id + FROM + aws_guardduty_finding; Severity: high Tags: category: @@ -39,12 +41,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -57,5 +59,4 @@ Tags: - AWS/GuardDuty soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: GuardDuty findings should be archived \ No newline at end of file diff --git a/compliance/controls/aws/aws_guardduty_no_high_severity_findings.yaml b/compliance/controls/aws/aws_guardduty_no_high_severity_findings.yaml old mode 100755 new mode 100644 index 9d3167973..022ee8407 --- a/compliance/controls/aws/aws_guardduty_no_high_severity_findings.yaml +++ b/compliance/controls/aws/aws_guardduty_no_high_severity_findings.yaml @@ -1,11 +1,17 @@ +Description: GuardDuty generates a finding whenever it detects unexpected and potentially malicious activity in your AWS environment. If critical findings are not addressed threats can spread in the environment. This rule is non-compliant if there are high severity findings. ID: aws_guardduty_no_high_severity_findings -Title: "GuardDuty Detector should not have high severity findings" -Description: "GuardDuty generates a finding whenever it detects unexpected and potentially malicious activity in your AWS environment. If critical findings are not addressed threats can spread in the environment. This rule is non-compliant if there are high severity findings." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with detectors as ( - select + ListOfTables: + - aws_guardduty_detector + - aws_guardduty_finding + Parameters: [] + PrimaryTable: aws_guardduty_detector + QueryToExecute: | + WITH detectors AS ( + SELECT detector_id, arn, title, @@ -14,40 +20,34 @@ Query: status, og_account_id, og_resource_id - from + FROM aws_guardduty_detector - ), finding_count as ( - select + ), finding_count AS ( + SELECT f.detector_id, - count(*) as count - from - aws_guardduty_finding as f - group by + COUNT(*) AS count + FROM + aws_guardduty_finding AS f + GROUP BY f.detector_id ) - select - arn as resource, - d.og_account_id as og_account_id, - d.og_resource_id as og_resource_id, - case - when status <> 'ENABLED' then 'skip' - when fc.count = 0 or fc.count is NULL then 'ok' - else 'alarm' - end as status, - case - when status <> 'ENABLED' then d.detector_id || ' is disabled.' - when fc.count = 0 or fc.count is NULL then d.detector_id || ' is enabled and does not have high severity findings.' - else d.detector_id || ' is enabled and has ' || fc.count || ' high severity findings.' - end as reason - from - detectors as d - left join finding_count as fc on fc.detector_id = d.detector_id; - PrimaryTable: aws_guardduty_detector - ListOfTables: - - aws_guardduty_detector - - aws_guardduty_finding - Parameters: [] + SELECT + arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN status <> 'ENABLED' THEN 'skip' + WHEN fc.count = 0 OR fc.count IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN status <> 'ENABLED' THEN d.detector_id || ' is disabled.' + WHEN fc.count = 0 OR fc.count IS NULL THEN d.detector_id || ' is enabled and does not have high severity findings.' + ELSE d.detector_id || ' is enabled and has ' || fc.count || ' high severity findings.' + END AS reason + FROM + detectors AS d + LEFT JOIN finding_count AS fc ON fc.detector_id = d.detector_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: GuardDuty Detector should not have high severity findings \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_access_analyzer_enabled.yaml b/compliance/controls/aws/aws_iam_access_analyzer_enabled.yaml old mode 100755 new mode 100644 index a154b451d..403943979 --- a/compliance/controls/aws/aws_iam_access_analyzer_enabled.yaml +++ b/compliance/controls/aws/aws_iam_access_analyzer_enabled.yaml @@ -1,15 +1,60 @@ +Description: This control checks whether IAM Access analyzer is enabled for all regions. The control fails if IAM Access analyzer is not enabled for all regions. ID: aws_iam_access_analyzer_enabled -Title: "Ensure that IAM Access analyzer is enabled for all regions" -Description: "This control checks whether IAM Access analyzer is enabled for all regions. The control fails if IAM Access analyzer is not enabled for all regions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with regions as (\n select\n 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource,\n r.og_account_id as og_account_id,\n r.og_resource_id as og_resource_id,\n case\n when r.opt_in_status = 'not-opted-in' then 1\n when aa.arn is not null then 0\n else 2\n end as status,\n r.region, r.account_id\n from\n aws_region as r\n left join aws_accessanalyzer_analyzer as aa on r.account_id = aa.account_id and r.region = aa.region\n),\nresults as (\n SELECT\n account_id AS resource,\n og_account_id as og_account_id,\n og_account_id as og_resource_id,\n case\n when max(status) = 2 then 'alarm'\n when max(status) = 1 then 'skip'\n when max(status) = 0 then 'ok'\n end as status,\n case\n when max(status) = 2 then 'IAM Access analyzer is not enabled for this account on regions: [' || string_agg(region, ',') || ']' \n when max(status) = 1 then 'Account is not opted in regions: [' || string_agg(region, ',') || ']'\n when max(status) = 0 then 'IAM Access analyzer is enabled for this account on regions: [' || string_agg(region, ',') || ']'\n end as reason\n FROM regions\n GROUP BY account_id, og_account_id\n)\nSELECT \n r.resource AS resource,\n r.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n r.status as status,\n r.reason as reason\nFROM results as r JOIN aws_account as a ON r.og_account_id = a.og_account_id\n" - PrimaryTable: aws_account ListOfTables: - aws_accessanalyzer_analyzer - aws_account - aws_region Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH regions AS ( + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN 1 + WHEN aa.arn IS NOT NULL THEN 0 + ELSE 2 + END AS status, + r.region, + r.account_id + FROM + aws_region AS r + LEFT JOIN aws_accessanalyzer_analyzer AS aa + ON r.account_id = aa.account_id AND r.region = aa.region + ), + results AS ( + SELECT + account_id AS resource, + og_account_id AS og_account_id, + og_account_id AS og_resource_id, + CASE + WHEN MAX(status) = 2 THEN 'alarm' + WHEN MAX(status) = 1 THEN 'skip' + WHEN MAX(status) = 0 THEN 'ok' + END AS status, + CASE + WHEN MAX(status) = 2 THEN 'IAM Access analyzer is not enabled for this account on regions: [' || STRING_AGG(region, ',') || ']' + WHEN MAX(status) = 1 THEN 'Account is not opted in regions: [' || STRING_AGG(region, ',') || ']' + WHEN MAX(status) = 0 THEN 'IAM Access analyzer is enabled for this account on regions: [' || STRING_AGG(region, ',') || ']' + END AS reason + FROM regions + GROUP BY account_id, og_account_id + ) + SELECT + r.resource AS resource, + r.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + r.status AS status, + r.reason AS reason + FROM results AS r + JOIN aws_account AS a + ON r.og_account_id = a.og_account_id Severity: high Tags: category: @@ -30,5 +75,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure that IAM Access analyzer is enabled for all regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_account_password_policy_min_length_14.yaml b/compliance/controls/aws/aws_iam_account_password_policy_min_length_14.yaml old mode 100755 new mode 100644 index 595e0b963..db84b89c5 --- a/compliance/controls/aws/aws_iam_account_password_policy_min_length_14.yaml +++ b/compliance/controls/aws/aws_iam_account_password_policy_min_length_14.yaml @@ -1,30 +1,32 @@ +Description: Password policies, in part, enforce password complexity requirements. Use IAM password policies to ensure that passwords are at least a given length. Security Hub recommends that the password policy require a minimum password length of 14 characters. ID: aws_iam_account_password_policy_min_length_14 -Title: "Ensure IAM password policy requires a minimum length of 14 or greater" -Description: "Password policies, in part, enforce password complexity requirements. Use IAM password policies to ensure that passwords are at least a given length. Security Hub recommends that the password policy require a minimum password length of 14 characters." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when minimum_password_length >= 14 then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - else 'Minimum password length set to ' || minimum_password_length || '.' - end as reason - , a.account_id - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN minimum_password_length >= 14 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + ELSE 'Minimum password length set to ' || minimum_password_length || '.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: high Tags: category: @@ -43,5 +45,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure IAM password policy requires a minimum length of 14 or greater \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_account_password_policy_one_lowercase_letter.yaml b/compliance/controls/aws/aws_iam_account_password_policy_one_lowercase_letter.yaml old mode 100755 new mode 100644 index 1679219e3..2bc899ab0 --- a/compliance/controls/aws/aws_iam_account_password_policy_one_lowercase_letter.yaml +++ b/compliance/controls/aws/aws_iam_account_password_policy_one_lowercase_letter.yaml @@ -1,31 +1,35 @@ +Description: Password policies, in part, enforce password complexity requirements. Use IAM password policies to ensure that passwords use different character sets. Security Hub recommends that the password policy require at least one lowercase letter. Setting a password complexity policy increases account resiliency against brute force login attempts. ID: aws_iam_account_password_policy_one_lowercase_letter -Title: "Ensure IAM password policy requires at least one lowercase letter" -Description: "Password policies, in part, enforce password complexity requirements. Use IAM password policies to ensure that passwords use different character sets. Security Hub recommends that the password policy require at least one lowercase letter. Setting a password complexity policy increases account resiliency against brute force login attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when require_lowercase_characters then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - when require_lowercase_characters then 'Lowercase character required.' - else 'Lowercase character not required.' - end as reason - , a.account_id - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN require_lowercase_characters THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN require_lowercase_characters THEN 'Lowercase character required.' + ELSE 'Lowercase character not required.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON + a.account_id = pol.account_id; Severity: low Tags: category: @@ -46,5 +50,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure IAM password policy requires at least one lowercase letter \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_account_password_policy_one_number.yaml b/compliance/controls/aws/aws_iam_account_password_policy_one_number.yaml old mode 100755 new mode 100644 index cc0477911..01d2af082 --- a/compliance/controls/aws/aws_iam_account_password_policy_one_number.yaml +++ b/compliance/controls/aws/aws_iam_account_password_policy_one_number.yaml @@ -1,31 +1,32 @@ +Description: Password policies, in part, enforce password complexity requirements. Use IAM password policies to ensure that passwords use different character sets. ID: aws_iam_account_password_policy_one_number -Title: "Ensure IAM password policy requires at least one number" -Description: "Password policies, in part, enforce password complexity requirements. Use IAM password policies to ensure that passwords use different character sets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when require_numbers then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - when require_numbers then 'Number required.' - else 'Number not required.' - end as reason - , a.account_id - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN require_numbers THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN require_numbers THEN 'Number required.' + ELSE 'Number not required.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: medium Tags: category: @@ -46,5 +47,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure IAM password policy requires at least one number \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_account_password_policy_one_symbol.yaml b/compliance/controls/aws/aws_iam_account_password_policy_one_symbol.yaml old mode 100755 new mode 100644 index f170f4a50..b2cde6e75 --- a/compliance/controls/aws/aws_iam_account_password_policy_one_symbol.yaml +++ b/compliance/controls/aws/aws_iam_account_password_policy_one_symbol.yaml @@ -1,31 +1,33 @@ +Description: Password policies, in part, enforce password complexity requirements. Use IAM password policies to ensure that passwords use different character sets. Security Hub recommends that the password policy require at least one symbol. Setting a password complexity policy increases account resiliency against brute force login attempts. ID: aws_iam_account_password_policy_one_symbol -Title: "Ensure IAM password policy requires at least one symbol" -Description: "Password policies, in part, enforce password complexity requirements. Use IAM password policies to ensure that passwords use different character sets. Security Hub recommends that the password policy require at least one symbol. Setting a password complexity policy increases account resiliency against brute force login attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when require_symbols then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - when require_symbols then 'Symbol required.' - else 'Symbol not required.' - end as reason - , a.account_id - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN require_symbols THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN require_symbols THEN 'Symbol required.' + ELSE 'Symbol not required.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN aws_iam_account_password_policy AS pol + ON a.account_id = pol.account_id; Severity: medium Tags: category: @@ -46,5 +48,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure IAM password policy requires at least one symbol \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_account_password_policy_one_uppercase_letter.yaml b/compliance/controls/aws/aws_iam_account_password_policy_one_uppercase_letter.yaml old mode 100755 new mode 100644 index 4b30dafde..773d58c19 --- a/compliance/controls/aws/aws_iam_account_password_policy_one_uppercase_letter.yaml +++ b/compliance/controls/aws/aws_iam_account_password_policy_one_uppercase_letter.yaml @@ -1,31 +1,33 @@ +Description: Password policies, in part, enforce password complexity requirements. Use IAM password policies to ensure that passwords use different character sets. ID: aws_iam_account_password_policy_one_uppercase_letter -Title: "Ensure IAM password policy requires at least one uppercase letter" -Description: "Password policies, in part, enforce password complexity requirements. Use IAM password policies to ensure that passwords use different character sets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when require_uppercase_characters then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - when require_uppercase_characters then 'Uppercase character required.' - else 'Uppercase character not required.' - end as reason - , a.account_id - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN require_uppercase_characters THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN require_uppercase_characters THEN 'Uppercase character required.' + ELSE 'Uppercase character not required.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: medium Tags: category: @@ -46,5 +48,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure IAM password policy requires at least one uppercase letter \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_account_password_policy_reuse_24.yaml b/compliance/controls/aws/aws_iam_account_password_policy_reuse_24.yaml old mode 100755 new mode 100644 index fa0c4a6ad..458725dd4 --- a/compliance/controls/aws/aws_iam_account_password_policy_reuse_24.yaml +++ b/compliance/controls/aws/aws_iam_account_password_policy_reuse_24.yaml @@ -1,31 +1,36 @@ +Description: This control checks whether the number of passwords to remember is set to 24. + The control fails if the value is not 24. IAM password policies can prevent the reuse of a given password by the same user. ID: aws_iam_account_password_policy_reuse_24 -Title: "Ensure IAM password policy prevents password reuse" -Description: "This control checks whether the number of passwords to remember is set to 24. The control fails if the value is not 24. IAM password policies can prevent the reuse of a given password by the same user." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when password_reuse_prevention >= 24 then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - when password_reuse_prevention is null then 'Password reuse prevention not set.' - else 'Password reuse prevention set to ' || password_reuse_prevention || '.' - end as reason - , a.account_id - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN password_reuse_prevention >= 24 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN password_reuse_prevention IS NULL THEN 'Password reuse prevention not set.' + ELSE 'Password reuse prevention set to ' || password_reuse_prevention || '.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON + a.account_id = pol.account_id; Severity: high Tags: category: @@ -46,5 +51,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure IAM password policy prevents password reuse \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_account_password_policy_strong_min_length_8.yaml b/compliance/controls/aws/aws_iam_account_password_policy_strong_min_length_8.yaml old mode 100755 new mode 100644 index 57268ba35..4df03bec4 --- a/compliance/controls/aws/aws_iam_account_password_policy_strong_min_length_8.yaml +++ b/compliance/controls/aws/aws_iam_account_password_policy_strong_min_length_8.yaml @@ -1,43 +1,45 @@ +Description: This control checks whether the account password policy for IAM users uses the recommended configurations. ID: aws_iam_account_password_policy_strong_min_length_8 -Title: "Password policies for IAM users should have strong configurations with minimum length of 8 or greater" -Description: "This control checks whether the account password policy for IAM users uses the recommended configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when - minimum_password_length >= 8 - and require_lowercase_characters = 'true' - and require_uppercase_characters = 'true' - and require_numbers = 'true' - and require_symbols = 'true' - then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - when - minimum_password_length >= 8 - and require_lowercase_characters = 'true' - and require_uppercase_characters = 'true' - and require_numbers = 'true' - and require_symbols = 'true' - then 'Strong password policies configured.' - else 'Strong password policies not configured.' - end as reason - , a.account_id - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN + minimum_password_length >= 8 + AND require_lowercase_characters = 'true' + AND require_uppercase_characters = 'true' + AND require_numbers = 'true' + AND require_symbols = 'true' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN + minimum_password_length >= 8 + AND require_lowercase_characters = 'true' + AND require_uppercase_characters = 'true' + AND require_numbers = 'true' + AND require_symbols = 'true' + THEN 'Strong password policies configured.' + ELSE 'Strong password policies not configured.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN aws_iam_account_password_policy AS pol + ON a.account_id = pol.account_id; Severity: medium Tags: aws_foundational_security: @@ -52,5 +54,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Password policies for IAM users should have strong configurations with minimum length of 8 or greater \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_account_password_policy_strong_min_reuse_24.yaml b/compliance/controls/aws/aws_iam_account_password_policy_strong_min_reuse_24.yaml old mode 100755 new mode 100644 index 0e536b26c..b550eabbf --- a/compliance/controls/aws/aws_iam_account_password_policy_strong_min_reuse_24.yaml +++ b/compliance/controls/aws/aws_iam_account_password_policy_strong_min_reuse_24.yaml @@ -1,47 +1,48 @@ +Description: The identities and the credentials are issued, managed, and verified based on an organizational IAM password policy. ID: aws_iam_account_password_policy_strong_min_reuse_24 -Title: "IAM password policies for users should have strong configurations" -Description: "The identities and the credentials are issued, managed, and verified based on an organizational IAM password policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when - minimum_password_length >= 14 - and password_reuse_prevention >= 24 - and require_lowercase_characters = 'true' - and require_uppercase_characters = 'true' - and require_numbers = 'true' - and require_symbols = 'true' - and max_password_age <= 90 - then 'ok' - else 'alarm' - end as status, - case - when minimum_password_length is null then 'No password policy set.' - when - minimum_password_length >= 14 - and password_reuse_prevention >= 24 - and require_lowercase_characters = 'true' - and require_uppercase_characters = 'true' - and require_numbers = 'true' - and require_symbols = 'true' - and max_password_age <= 90 - then 'Strong password policies configured.' - else 'Strong password policies not configured.' - end as reason - , a.account_id - from - aws_account as a - left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN + minimum_password_length >= 14 + AND password_reuse_prevention >= 24 + AND require_lowercase_characters = 'true' + AND require_uppercase_characters = 'true' + AND require_numbers = 'true' + AND require_symbols = 'true' + AND max_password_age <= 90 + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN + minimum_password_length >= 14 + AND password_reuse_prevention >= 24 + AND require_lowercase_characters = 'true' + AND require_uppercase_characters = 'true' + AND require_numbers = 'true' + AND require_symbols = 'true' + AND max_password_age <= 90 + THEN 'Strong password policies configured.' + ELSE 'Strong password policies not configured.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: medium Tags: category: @@ -52,10 +53,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -68,5 +69,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM password policies for users should have strong configurations \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_all_policy_no_service_wild_card.yaml b/compliance/controls/aws/aws_iam_all_policy_no_service_wild_card.yaml old mode 100755 new mode 100644 index f22bfc40b..361aca0d3 --- a/compliance/controls/aws/aws_iam_all_policy_no_service_wild_card.yaml +++ b/compliance/controls/aws/aws_iam_all_policy_no_service_wild_card.yaml @@ -1,49 +1,49 @@ +Description: Checks if AWS Identity and Access Management (IAM) policies grant permissions to all actions on individual AWS resources. The rule is non-compliant if the managed IAM policy allows full access to at least 1 AWS service. ID: aws_iam_all_policy_no_service_wild_card -Title: "Ensure IAM policy should not grant full access to service" -Description: "Checks if AWS Identity and Access Management (IAM) policies grant permissions to all actions on individual AWS resources. The rule is non-compliant if the managed IAM policy allows full access to at least 1 AWS service." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with wildcard_action_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where - not is_aws_managed - and s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - action like '%:*' - or action = '*' + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + NOT is_aws_managed + AND s ->> 'Effect' = 'Allow' + AND resource = '*' + AND ( + action LIKE '%:*' + OR action = '*' ) - group by + GROUP BY arn ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when w.arn is null then 'ok' - else 'alarm' - end status, - p.name || ' contains ' || coalesce(w.statements_num,0) || - ' statements that allow action "*" on at least 1 AWS service on resource "*".' as reason - from - aws_iam_policy as p - left join wildcard_action_policies as w on p.arn = w.arn - where - not p.is_aws_managed; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN w.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + p.name || ' contains ' || COALESCE(w.statements_num, 0) || + ' statements that allow action "*" on at least 1 AWS service on resource "*".' AS reason + FROM + aws_iam_policy AS p + LEFT JOIN wildcard_action_policies AS w ON p.arn = w.arn + WHERE + NOT p.is_aws_managed; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure IAM policy should not grant full access to service \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_custom_policy_unattached_no_star_star.yaml b/compliance/controls/aws/aws_iam_custom_policy_unattached_no_star_star.yaml old mode 100755 new mode 100644 index 583f85248..12c5b9d74 --- a/compliance/controls/aws/aws_iam_custom_policy_unattached_no_star_star.yaml +++ b/compliance/controls/aws/aws_iam_custom_policy_unattached_no_star_star.yaml @@ -1,52 +1,51 @@ +Description: 'AWS Identity and Access Management (IAM) can help you incorporate the principles of least privilege and separation of duties with access permissions and authorizations, restricting policies from containing ''Effect'': ''Allow'' with ''Action'': ''*'' over ''Resource'': ''*''.' ID: aws_iam_custom_policy_unattached_no_star_star -Title: "IAM unattached custom policy should not have statements with admin access" -Description: "AWS Identity and Access Management (IAM) can help you incorporate the principles of least privilege and separation of duties with access permissions and authorizations, restricting policies from containing 'Effect': 'Allow' with 'Action': '*' over 'Resource': '*'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH bad_policies AS ( + SELECT arn, - count(*) as num_bad_statements - from + COUNT(*) AS num_bad_statements + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where - not is_aws_managed - and not is_attached - and s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - (action = '*' - or action = '*:*' - ) + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + NOT is_aws_managed + AND NOT is_attached + AND s ->> 'Effect' = 'Allow' + AND resource = '*' + AND ( + action = '*' + OR action = '*:*' ) - group by + GROUP BY arn ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when bad.arn is null then 'ok' - else 'alarm' - end status, - p.name || ' contains ' || coalesce(bad.num_bad_statements, 0) || - ' statements that allow action "*" on resource "*".' as reason - from - aws_iam_policy as p - left join bad_policies as bad on p.arn = bad.arn - where - not p.is_aws_managed - and not is_attached; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN bad.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + p.name || ' contains ' || COALESCE(bad.num_bad_statements, 0) || + ' statements that allow action "*" on resource "*".' AS reason + FROM + aws_iam_policy AS p + LEFT JOIN bad_policies AS bad ON p.arn = bad.arn + WHERE + NOT p.is_aws_managed + AND NOT is_attached; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM unattached custom policy should not have statements with admin access \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_group_not_empty.yaml b/compliance/controls/aws/aws_iam_group_not_empty.yaml old mode 100755 new mode 100644 index cdfa4db9c..3bc2564cb --- a/compliance/controls/aws/aws_iam_group_not_empty.yaml +++ b/compliance/controls/aws/aws_iam_group_not_empty.yaml @@ -1,28 +1,29 @@ +Description: AWS Identity and Access Management (IAM) can help you incorporate the principles of least privilege and separation of duties with access permissions and authorizations, by ensuring that IAM groups have at least one IAM user. ID: aws_iam_group_not_empty -Title: "IAM groups should have at least one user" -Description: "AWS Identity and Access Management (IAM) can help you incorporate the principles of least privilege and separation of duties with access permissions and authorizations, by ensuring that IAM groups have at least one IAM user." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when users is null then 'alarm' - else 'ok' - end as status, - case - when users is null then title || ' not associated with any IAM user.' - else title || ' associated with IAM user.' - end as reason - , account_id - from - aws_iam_group; - PrimaryTable: aws_iam_group ListOfTables: - aws_iam_group Parameters: [] + PrimaryTable: aws_iam_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN users IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN users IS NULL THEN title || ' not associated with any IAM user.' + ELSE title || ' associated with IAM user.' + END AS reason, + account_id + FROM + aws_iam_group; Severity: low Tags: category: @@ -41,10 +42,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -53,5 +54,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM groups should have at least one user \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_group_user_role_no_inline_policies.yaml b/compliance/controls/aws/aws_iam_group_user_role_no_inline_policies.yaml old mode 100755 new mode 100644 index 849d1ecd6..da7983dab --- a/compliance/controls/aws/aws_iam_group_user_role_no_inline_policies.yaml +++ b/compliance/controls/aws/aws_iam_group_user_role_no_inline_policies.yaml @@ -1,58 +1,59 @@ +Description: Ensure an AWS Identity and Access Management (IAM) user, IAM role or IAM group does not have an inline policy to control access to systems and assets. ID: aws_iam_group_user_role_no_inline_policies -Title: "IAM groups, users, and roles should not have any inline policies" -Description: "Ensure an AWS Identity and Access Management (IAM) user, IAM role or IAM group does not have an inline policy to control access to systems and assets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_iam_user' as og_table_name, - case - when inline_policies is null then 'ok' - else 'alarm' - end status, - 'User ' || title || ' has ' || coalesce(jsonb_array_length(inline_policies), 0) || ' inline policies.' as reason - , account_id - from - aws_iam_user - union - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_iam_role' as og_table_name, - case - when inline_policies is null then 'ok' - else 'alarm' - end status, - 'Role ' || title || ' has ' || coalesce(jsonb_array_length(inline_policies), 0) || ' inline policies.' as reason - , account_id - from - aws_iam_role - where - arn not like '%service-role/%' - union - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_iam_group' as og_table_name, - case - when inline_policies is null then 'ok' - else 'alarm' - end status, - 'Group ' || title || ' has ' || coalesce(jsonb_array_length(inline_policies), 0) || ' inline policies.' as reason - , account_id - from - aws_iam_group; - PrimaryTable: "" ListOfTables: - aws_iam_group - aws_iam_role - aws_iam_user Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_iam_user' AS og_table_name, + CASE + WHEN inline_policies IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + 'User ' || title || ' has ' || COALESCE(jsonb_array_length(inline_policies), 0) || ' inline policies.' AS reason, + account_id + FROM + aws_iam_user + UNION + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_iam_role' AS og_table_name, + CASE + WHEN inline_policies IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + 'Role ' || title || ' has ' || COALESCE(jsonb_array_length(inline_policies), 0) || ' inline policies.' AS reason, + account_id + FROM + aws_iam_role + WHERE + arn NOT LIKE '%service-role/%' + UNION + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_iam_group' AS og_table_name, + CASE + WHEN inline_policies IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + 'Group ' || title || ' has ' || COALESCE(jsonb_array_length(inline_policies), 0) || ' inline policies.' AS reason, + account_id + FROM + aws_iam_group; Severity: high Tags: category: @@ -71,12 +72,12 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -87,5 +88,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM groups, users, and roles should not have any inline policies \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_inline_policy_no_administrative_privileges.yaml b/compliance/controls/aws/aws_iam_inline_policy_no_administrative_privileges.yaml old mode 100755 new mode 100644 index 6c10738ba..f40610183 --- a/compliance/controls/aws/aws_iam_inline_policy_no_administrative_privileges.yaml +++ b/compliance/controls/aws/aws_iam_inline_policy_no_administrative_privileges.yaml @@ -1,91 +1,90 @@ +Description: Ensure that no inline IAM policies exist that allow administrative privileges. ID: aws_iam_inline_policy_no_administrative_privileges -Title: "IAM inline policy should not have administrative privileges" -Description: "Ensure that no inline IAM policies exist that allow administrative privileges." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with full_administrative_privilege_policies as ( - select + ListOfTables: + - aws_iam_user + - aws_iam_role + - aws_iam_group + Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + WITH full_administrative_privilege_policies AS ( + SELECT arn, inline_policies_std, name, account_id, region, _ctx, - 'iam_user' as type, + 'iam_user' AS type, og_account_id, og_resource_id - from + FROM aws_iam_user - union - select + UNION + SELECT arn, inline_policies_std, name, account_id, region, _ctx, - 'iam_role' as type, + 'iam_role' AS type, og_account_id, og_resource_id - from + FROM aws_iam_role - union - select + UNION + SELECT arn, inline_policies_std, name, account_id, region, _ctx, - 'iam_group' as type, + 'iam_group' AS type, og_account_id, og_resource_id - from + FROM aws_iam_group ), - bad_policies as ( - select + bad_policies AS ( + SELECT arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM full_administrative_privilege_policies, - jsonb_array_elements(inline_policies_std) as policy_std, - jsonb_array_elements(policy_std -> 'PolicyDocument' -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where + jsonb_array_elements(inline_policies_std) AS policy_std, + jsonb_array_elements(policy_std -> 'PolicyDocument' -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE s ->> 'Effect' = 'Allow' - and resource = '*' - and ( + AND resource = '*' + AND ( (action = '*' - or action = '*:*' + OR action = '*:*' ) ) - group by + GROUP BY arn ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when bad.arn is null then 'ok' - else 'alarm' - end status, - p.name || ' contains ' || coalesce(bad.statements_num,0) || - ' statements that allow action "*" on resource "*".' as reason - - from - full_administrative_privilege_policies as p - left join bad_policies as bad on p.arn = bad.arn; - PrimaryTable: aws_iam_user - ListOfTables: - - aws_iam_user - - aws_iam_role - - aws_iam_group - Parameters: [] + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN bad.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + p.name || ' contains ' || COALESCE(bad.statements_num, 0) || + ' statements that allow action "*" on resource "*".' AS reason + FROM + full_administrative_privilege_policies AS p + LEFT JOIN bad_policies AS bad ON p.arn = bad.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM inline policy should not have administrative privileges \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_managed_policy_attached_to_role.yaml b/compliance/controls/aws/aws_iam_managed_policy_attached_to_role.yaml old mode 100755 new mode 100644 index 86fb5f039..af4711af4 --- a/compliance/controls/aws/aws_iam_managed_policy_attached_to_role.yaml +++ b/compliance/controls/aws/aws_iam_managed_policy_attached_to_role.yaml @@ -1,15 +1,39 @@ +Description: This control checks if all AWS managed policies specified in the list of managed policies are attached to the AWS Identity and Access Management (IAM) role. The rule is non-compliant if an AWS managed policy is not attached to the IAM role. ID: aws_iam_managed_policy_attached_to_role -Title: "IAM AWS managed policies should be attached to IAM role" -Description: "This control checks if all AWS managed policies specified in the list of managed policies are attached to the AWS Identity and Access Management (IAM) role. The rule is non-compliant if an AWS managed policy is not attached to the IAM role." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with role_attached_policies as (\n select\n jsonb_array_elements_text(attached_policy_arns) as policy_arn\n from\n aws_iam_role\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when arn in (select policy_arn from role_attached_policies) then 'ok'\n else 'alarm'\n end as status,\n case\n when arn in (select policy_arn from role_attached_policies) then title || ' attached to IAM role.'\n else title || ' not attached to IAM role.'\n end as reason\n \n , account_id\nfrom\n aws_iam_policy\nwhere\n is_aws_managed;\n" - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_policy - aws_iam_role - aws_managed Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH role_attached_policies AS ( + SELECT + jsonb_array_elements_text(attached_policy_arns) AS policy_arn + FROM + aws_iam_role + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN arn IN (SELECT policy_arn FROM role_attached_policies) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN arn IN (SELECT policy_arn FROM role_attached_policies) THEN title || ' attached to IAM role.' + ELSE title || ' not attached to IAM role.' + END AS reason, + account_id + FROM + aws_iam_policy + WHERE + is_aws_managed; Severity: medium Tags: category: @@ -26,5 +50,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM AWS managed policies should be attached to IAM role \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_policy_all_attached_no_star_star.yaml b/compliance/controls/aws/aws_iam_policy_all_attached_no_star_star.yaml old mode 100755 new mode 100644 index a8a9fcfa1..1bc1b7a83 --- a/compliance/controls/aws/aws_iam_policy_all_attached_no_star_star.yaml +++ b/compliance/controls/aws/aws_iam_policy_all_attached_no_star_star.yaml @@ -1,14 +1,59 @@ +Description: IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges. ID: aws_iam_policy_all_attached_no_star_star -Title: "Ensure IAM policies that allow full \\\"*:*\\\" administrative privileges are not attached" -Description: "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant least privilege -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks, instead of allowing full administrative privileges." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with star_access_policies as (\n select\n arn,\n is_aws_managed,\n count(*) as num_bad_statements\n from\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Resource') as resource,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n s ->> 'Effect' = 'Allow'\n and resource = '*'\n and (\n (action = '*'\n or action = '*:*'\n )\n )\n and is_attached\n group by\n arn,\n is_aws_managed\n)\nselect\n p.arn as resource,\n p.og_account_id as og_account_id,\n p.og_resource_id as og_resource_id,\n case\n when s.arn is not null and s.is_aws_managed then 'info'\n when s.arn is null then 'ok'\n else 'alarm'\n end status,\n case\n when s.arn is not null and s.is_aws_managed then p.name || ' is an AWS managed policy with ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action \"*\" on resource \"*\".'\n else p.name || ' contains ' || coalesce(s.num_bad_statements, 0) || ' statements that allow action \"*\" on resource \"*\".'\n end as reason\n \n , p.account_id\nfrom\n aws_iam_policy as p\n left join star_access_policies as s on p.arn = s.arn\nwhere\n p.is_attached;\n" - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_policy - aws_managed Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH star_access_policies AS ( + SELECT + arn, + is_aws_managed, + COUNT(*) AS num_bad_statements + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + s ->> 'Effect' = 'Allow' + AND resource = '*' + AND ( + action = '*' + OR action = '*:*' + ) + AND is_attached + GROUP BY + arn, + is_aws_managed + ) + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN 'info' + WHEN s.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN s.arn IS NOT NULL AND s.is_aws_managed THEN + p.name || ' is an AWS managed policy with ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + ELSE + p.name || ' contains ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' + END AS reason, + p.account_id + FROM + aws_iam_policy AS p + LEFT JOIN star_access_policies AS s + ON p.arn = s.arn + WHERE + p.is_attached; Severity: high Tags: category: @@ -29,5 +74,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure IAM policies that allow full "*:*" administrative privileges are not attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_policy_custom_attached_no_star_star.yaml b/compliance/controls/aws/aws_iam_policy_custom_attached_no_star_star.yaml old mode 100755 new mode 100644 index e7fe9da30..1d4152086 --- a/compliance/controls/aws/aws_iam_policy_custom_attached_no_star_star.yaml +++ b/compliance/controls/aws/aws_iam_policy_custom_attached_no_star_star.yaml @@ -1,14 +1,50 @@ +Description: 'This control checks whether the default version of IAM policies (also known as customer managed policies) has administrator access that includes a statement with ''Effect'': ''Allow'' with ''Action'': ''*'' over ''Resource'': ''*''. The control only checks the customer managed policies that you create. It does not check inline and AWS managed policies.' ID: aws_iam_policy_custom_attached_no_star_star -Title: "IAM policies should not allow full '*' administrative privileges" -Description: "This control checks whether the default version of IAM policies (also known as customer managed policies) has administrator access that includes a statement with 'Effect': 'Allow' with 'Action': '*' over 'Resource': '*'. The control only checks the customer managed policies that you create. It does not check inline and AWS managed policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "-- This query checks the customer managed policies having * access and attached to IAM resource(s)\nwith star_access_policies as (\n select\n arn,\n count(*) as num_bad_statements\n from\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Resource') as resource,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n not is_aws_managed\n and s ->> 'Effect' = 'Allow'\n and resource = '*'\n and (\n (action = '*'\n or action = '*:*'\n )\n )\n and is_attached\n group by arn\n)\nselect\n p.arn as resource,\n p.og_account_id as og_account_id,\n p.og_resource_id as og_resource_id,\n case\n when s.arn is null then 'ok'\n else 'alarm'\n end status,\n p.name || ' contains ' || coalesce(s.num_bad_statements,0) || ' statements that allow action \"*\" on resource \"*\".' as reason\n \n , p.account_id\nfrom\n aws_iam_policy as p\n left join star_access_policies as s on p.arn = s.arn\nwhere\n not p.is_aws_managed;\n" - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_policy - aws_managed Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH star_access_policies AS ( + SELECT + arn, + COUNT(*) AS num_bad_statements + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + NOT is_aws_managed + AND s ->> 'Effect' = 'Allow' + AND resource = '*' + AND ( + action = '*' + OR action = '*:*' + ) + AND is_attached + GROUP BY arn + ) + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN s.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + p.name || ' contains ' || COALESCE(s.num_bad_statements, 0) || ' statements that allow action "*" on resource "*".' AS reason, + p.account_id + FROM + aws_iam_policy AS p + LEFT JOIN star_access_policies AS s ON p.arn = s.arn + WHERE + NOT p.is_aws_managed; Severity: high Tags: aws_foundational_security: @@ -23,5 +59,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: IAM policies should not allow full '*' administrative privileges \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_policy_custom_no_assume_role.yaml b/compliance/controls/aws/aws_iam_policy_custom_no_assume_role.yaml old mode 100755 new mode 100644 index da10f8d94..f543051a8 --- a/compliance/controls/aws/aws_iam_policy_custom_no_assume_role.yaml +++ b/compliance/controls/aws/aws_iam_policy_custom_no_assume_role.yaml @@ -1,42 +1,42 @@ +Description: Role assume policies can provide access to roles in external AWS accounts. ID: aws_iam_policy_custom_no_assume_role -Title: "IAM roles should not have any assume role policies attached" -Description: "Role assume policies can provide access to roles in external AWS accounts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with filter_users as ( - select + ListOfTables: + - aws_iam_user + Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + WITH filter_users AS ( + SELECT user_id, name, policies - from + FROM aws_iam_user, - jsonb_array_elements_text(inline_policies) as policies - where - policies like '%AssumeRole%' + JSONB_ARRAY_ELEMENTS_TEXT(inline_policies) AS policies + WHERE + policies LIKE '%AssumeRole%' ) - select - u.arn as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when fu.user_id is not null then 'alarm' - else 'ok' - end as status, - case - when fu.user_id is not null then u.name || ' custom policies allow STS Role assumption.' - else u.name || ' custom policies does not allow STS Role assumption.' - end as reason - from - aws_iam_user as u - left join filter_users as fu on u.user_id = fu.user_id - order by + SELECT + u.arn AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN fu.user_id IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN fu.user_id IS NOT NULL THEN u.name || ' custom policies allow STS Role assumption.' + ELSE u.name || ' custom policies does not allow STS Role assumption.' + END AS reason + FROM + aws_iam_user AS u + LEFT JOIN filter_users AS fu ON u.user_id = fu.user_id + ORDER BY u.name; - PrimaryTable: aws_iam_user - ListOfTables: - - aws_iam_user - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM roles should not have any assume role policies attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_policy_custom_no_blocked_kms_actions.yaml b/compliance/controls/aws/aws_iam_policy_custom_no_blocked_kms_actions.yaml old mode 100755 new mode 100644 index 9696182c5..511e2da71 --- a/compliance/controls/aws/aws_iam_policy_custom_no_blocked_kms_actions.yaml +++ b/compliance/controls/aws/aws_iam_policy_custom_no_blocked_kms_actions.yaml @@ -1,14 +1,46 @@ +Description: Checks if the managed AWS Identity and Access Management (IAM) policies that you create do not allow blocked actions on AWS KMS keys. The rule is non-compliant if any blocked action is allowed on AWS KMS keys by the managed IAM policy. ID: aws_iam_policy_custom_no_blocked_kms_actions -Title: "Ensure managed IAM policies should not allow blocked actions on KMS keys" -Description: "Checks if the managed AWS Identity and Access Management (IAM) policies that you create do not allow blocked actions on AWS KMS keys. The rule is non - compliant if any blocked action is allowed on AWS KMS keys by the managed IAM policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with kms_blocked_actions as (\n select\n arn,\n count(*) as statements_num\n from\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Resource') as resource,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n not is_aws_managed\n and s ->> 'Effect' = 'Allow'\n and action like any(array['kms:decrypt', 'kms:reencryptfrom'])\n group by\n arn\n)\nselect\n p.arn as resource,\n p.og_account_id as og_account_id,\n p.og_resource_id as og_resource_id,\n case\n when w.arn is null then 'ok'\n else 'alarm'\n end status,\n p.name || ' contains ' || coalesce(w.statements_num,0) || ' statements that allow blocked actions on AWS KMS keys.' as reason\n \n , p.account_id\nfrom\n aws_iam_policy as p\n left join kms_blocked_actions as w on p.arn = w.arn\nwhere\n not p.is_aws_managed;\n" - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_policy - aws_managed Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH kms_blocked_actions AS ( + SELECT + arn, + COUNT(*) AS statements_num + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + NOT is_aws_managed + AND s ->> 'Effect' = 'Allow' + AND action LIKE ANY(ARRAY['kms:decrypt', 'kms:reencryptfrom']) + GROUP BY + arn + ) + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN w.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + p.name || ' contains ' || COALESCE(w.statements_num, 0) || ' statements that allow blocked actions on AWS KMS keys.' AS reason, + p.account_id + FROM + aws_iam_policy AS p + LEFT JOIN kms_blocked_actions AS w ON p.arn = w.arn + WHERE + NOT p.is_aws_managed; Severity: high Tags: category: @@ -35,5 +67,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure managed IAM policies should not allow blocked actions on KMS keys \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_policy_custom_no_permissive_role_assumption.yaml b/compliance/controls/aws/aws_iam_policy_custom_no_permissive_role_assumption.yaml old mode 100755 new mode 100644 index 2b6aa5031..f545aa335 --- a/compliance/controls/aws/aws_iam_policy_custom_no_permissive_role_assumption.yaml +++ b/compliance/controls/aws/aws_iam_policy_custom_no_permissive_role_assumption.yaml @@ -1,51 +1,50 @@ +Description: Ensure that no custom IAM policies exist which allow permissive role assumption. ID: aws_iam_policy_custom_no_permissive_role_assumption -Title: "IAM custom policy should not have overly permissive STS role assumption" -Description: "Ensure that no custom IAM policies exist which allow permissive role assumption." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bad_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH bad_policies AS ( + SELECT arn, - count(*) as num - from + COUNT(*) AS num + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where - not is_aws_managed - and s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - ( action = '*' - or action = 'sts:*' - or action = 'sts:AssumeRole' - ) + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + NOT is_aws_managed + AND s ->> 'Effect' = 'Allow' + AND resource = '*' + AND ( + action = '*' + OR action = 'sts:*' + OR action = 'sts:AssumeRole' ) - group by + GROUP BY arn ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when b.arn is not null then 'alarm' - else 'ok' - end as status, - p.name || ' contains ' || coalesce(b.num, 0) || - ' statements that allow overly permissive STS role assumption.' as reason - from - aws_iam_policy as p - left join bad_policies as b on p.arn = b.arn - where - not is_aws_managed; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + p.name || ' contains ' || COALESCE(b.num, 0) || + ' statements that allow overly permissive STS role assumption.' AS reason + FROM + aws_iam_policy AS p + LEFT JOIN bad_policies AS b ON p.arn = b.arn + WHERE + NOT is_aws_managed; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM custom policy should not have overly permissive STS role assumption \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_policy_inline_no_blocked_kms_actions.yaml b/compliance/controls/aws/aws_iam_policy_inline_no_blocked_kms_actions.yaml old mode 100755 new mode 100644 index e47733a74..504c99f60 --- a/compliance/controls/aws/aws_iam_policy_inline_no_blocked_kms_actions.yaml +++ b/compliance/controls/aws/aws_iam_policy_inline_no_blocked_kms_actions.yaml @@ -1,85 +1,86 @@ +Description: Checks if the inline policies attached to IAM users, roles, and groups do not allow blocked actions on all AWS Key Management Service (KMS) keys. The rule is non-compliant if any blocked action is allowed on all KMS keys in an inline policy. ID: aws_iam_policy_inline_no_blocked_kms_actions -Title: "Ensure inline policies attached to IAM users, roles, and groups should not allow blocked actions on KMS keys" -Description: "Checks if the inline policies attached to IAM users, roles, and groups do not allow blocked actions on all AWS Key Management Service (KMS) keys. The rule is non - compliant if any blocked action is allowed on all KMS keys in an inline policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_iam_group + - aws_iam_role + - aws_iam_user + Parameters: [] + PrimaryTable: "" QueryToExecute: | - with iam_resource_types as ( - select + WITH iam_resource_types AS ( + SELECT arn, inline_policies_std, name, account_id, region, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_iam_user' as og_table_name, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_iam_user' AS og_table_name, _ctx - from + FROM aws_iam_user - union - select + UNION + SELECT arn, inline_policies_std, name, account_id, region, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_iam_role' as og_table_name, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_iam_role' AS og_table_name, _ctx - from + FROM aws_iam_role - union - select + UNION + SELECT arn, inline_policies_std, name, account_id, region, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_iam_group' as og_table_name, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_iam_group' AS og_table_name, _ctx - from + FROM aws_iam_group ), - kms_blocked_actions as ( - select + kms_blocked_actions AS ( + SELECT arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM iam_resource_types, - jsonb_array_elements(inline_policies_std) as policy_std, - jsonb_array_elements(policy_std -> 'PolicyDocument' -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where + jsonb_array_elements(inline_policies_std) AS policy_std, + jsonb_array_elements(policy_std -> 'PolicyDocument' -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE s ->> 'Effect' = 'Allow' - and action like any(array['kms:decrypt','kms:decrypt*', 'kms:reencryptfrom', 'kms:*', 'kms:reencrypt*']) - group by + AND action LIKE ANY(ARRAY['kms:decrypt','kms:decrypt*', 'kms:reencryptfrom', 'kms:*', 'kms:reencrypt*']) + GROUP BY arn ) - select - u.arn as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - u.og_table_name as og_table_name, - case - when w.arn is null then 'ok' - else 'alarm' - end status, - u.name || ' contains ' || coalesce(w.statements_num,0) || ' inline policy statement(s) that allow blocked actions on AWS KMS keys.' as reason - , u.account_id - from - iam_resource_types as u - left join kms_blocked_actions as w on u.arn = w.arn; - PrimaryTable: "" - ListOfTables: - - aws_iam_group - - aws_iam_role - - aws_iam_user - Parameters: [] + SELECT + u.arn AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + u.og_table_name AS og_table_name, + CASE + WHEN w.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + u.name || ' contains ' || COALESCE(w.statements_num, 0) || ' inline policy statement(s) that allow blocked actions on AWS KMS keys.' AS reason, + u.account_id + FROM + iam_resource_types AS u + LEFT JOIN kms_blocked_actions AS w ON u.arn = w.arn; Severity: high Tags: category: @@ -102,5 +103,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure inline policies attached to IAM users, roles, and groups should not allow blocked actions on KMS keys \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_policy_no_full_access_to_cloudtrail.yaml b/compliance/controls/aws/aws_iam_policy_no_full_access_to_cloudtrail.yaml old mode 100755 new mode 100644 index fe9e03bea..3fdad4558 --- a/compliance/controls/aws/aws_iam_policy_no_full_access_to_cloudtrail.yaml +++ b/compliance/controls/aws/aws_iam_policy_no_full_access_to_cloudtrail.yaml @@ -1,46 +1,46 @@ +Description: CloudTrail is a critical service and IAM policies should follow least privilege model for this service in particular. This control is non-compliant if the managed IAM policy allows full access to cloudtrail service. ID: aws_iam_policy_no_full_access_to_cloudtrail -Title: "IAM policy should not grant full access to cloudtrail service" -Description: "CloudTrail is a critical service and IAM policies should follow least privilege model for this service in particular. This control is non-compliant if the managed IAM policy allows full access to cloudtrail service." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with cloudtrail_full_access_policies as ( - select + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH cloudtrail_full_access_policies AS ( + SELECT arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where - not is_aws_managed - and s ->> 'Effect' = 'Allow' - and resource = '*' - and action = 'cloudtrail:*' - group by + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + NOT is_aws_managed + AND s ->> 'Effect' = 'Allow' + AND resource = '*' + AND action = 'cloudtrail:*' + GROUP BY arn ) - select - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when w.arn is null then 'ok' - else 'alarm' - end status, - p.name || ' contains ' || coalesce(w.statements_num,0) || - ' statements that allow action "*" on at cloudtrail service on resource "*".' as reason - from - aws_iam_policy as p - left join cloudtrail_full_access_policies as w on p.arn = w.arn - where - not p.is_aws_managed; - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN w.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + p.name || ' contains ' || COALESCE(w.statements_num, 0) || + ' statements that allow action "*" on cloudtrail service on resource "*".' AS reason + FROM + aws_iam_policy AS p + LEFT JOIN cloudtrail_full_access_policies AS w ON p.arn = w.arn + WHERE + NOT p.is_aws_managed; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM policy should not grant full access to cloudtrail service \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_policy_no_full_access_to_kms.yaml b/compliance/controls/aws/aws_iam_policy_no_full_access_to_kms.yaml old mode 100755 new mode 100644 index dd19ac84f..884fedb7a --- a/compliance/controls/aws/aws_iam_policy_no_full_access_to_kms.yaml +++ b/compliance/controls/aws/aws_iam_policy_no_full_access_to_kms.yaml @@ -1,14 +1,46 @@ +Description: KMS is a critical service and IAM policies should follow least privilege model for this service in particular. This control is non-compliant if the managed IAM policy allows full access to KMS service. ID: aws_iam_policy_no_full_access_to_kms -Title: "IAM policy should not grant full access to KMS service" -Description: "KMS is a critical service and IAM policies should follow least privilege model for this service in particular. This control is non-compliant if the managed IAM policy allows full access to KMS service." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with cloudtrail_full_access_policies as (\n select\n arn,\n count(*) as statements_num\n from\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Resource') as resource,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n not is_aws_managed\n and s ->> 'Effect' = 'Allow'\n and resource = '*'\n and action = 'cloudtrail:*'\n group by\n arn\n)\nselect\n p.arn as resource,\n p.og_account_id as og_account_id,\n p.og_resource_id as og_resource_id,\n case\n when w.arn is null then 'ok'\n else 'alarm'\n end status,\n p.name || ' contains ' || coalesce(w.statements_num,0) ||\n ' statements that allow action \"*\" on at cloudtrail service on resource \"*\".' as reason\n \n \nfrom\n aws_iam_policy as p\n left join cloudtrail_full_access_policies as w on p.arn = w.arn\nwhere\n not p.is_aws_managed;" - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_policy Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH cloudtrail_full_access_policies AS ( + SELECT + arn, + COUNT(*) AS statements_num + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + NOT is_aws_managed + AND s ->> 'Effect' = 'Allow' + AND resource = '*' + AND action = 'cloudtrail:*' + GROUP BY + arn + ) + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN w.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + p.name || ' contains ' || COALESCE(w.statements_num,0) || + ' statements that allow action "*" on cloudtrail service on resource "*".' AS reason + FROM + aws_iam_policy AS p + LEFT JOIN cloudtrail_full_access_policies AS w ON p.arn = w.arn + WHERE + NOT p.is_aws_managed; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM policy should not grant full access to KMS service \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_policy_no_star_star.yaml b/compliance/controls/aws/aws_iam_policy_no_star_star.yaml old mode 100755 new mode 100644 index 0795d35b6..8f7a8631c --- a/compliance/controls/aws/aws_iam_policy_no_star_star.yaml +++ b/compliance/controls/aws/aws_iam_policy_no_star_star.yaml @@ -1,51 +1,49 @@ +Description: 'AWS Identity and Access Management (IAM) can help you incorporate the principles of least privilege and separation of duties with access permissions and authorizations, restricting policies from containing ''Effect'': ''Allow'' with ''Action'': ''*'' over ''Resource'': ''*''.' ID: aws_iam_policy_no_star_star -Title: "IAM policy should not have statements with admin access" -Description: "AWS Identity and Access Management (IAM) can help you incorporate the principles of least privilege and separation of duties with access permissions and authorizations, restricting policies from containing 'Effect': 'Allow' with 'Action': '*' over 'Resource': '*'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_iam_policy + Parameters: [] + PrimaryTable: aws_iam_policy QueryToExecute: | - with bad_policies as ( - select + WITH bad_policies AS ( + SELECT arn, - count(*) as num_bad_statements - from + COUNT(*) AS num_bad_statements + FROM aws_iam_policy, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Resource') as resource, - jsonb_array_elements_text(s -> 'Action') as action - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Resource') AS resource, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE s ->> 'Effect' = 'Allow' - and resource = '*' - and ( - (action = '*' - or action = '*:*' - ) - ) - group by + AND resource = '*' + AND ( + action = '*' + OR action = '*:*' + ) + GROUP BY arn ) - select - -- Required Columns - p.arn as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when bad.arn is null then 'ok' - else 'alarm' - end status, - p.name || ' contains ' || coalesce(bad.num_bad_statements,0) || - ' statements that allow action "*" on resource "*".' as reason, - -- Additional Dimensions + SELECT + p.arn AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN bad.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + p.name || ' contains ' || COALESCE(bad.num_bad_statements, 0) || + ' statements that allow action "*" on resource "*".' AS reason, p.account_id - from - aws_iam_policy as p - left join bad_policies as bad on p.arn = bad.arn - where - p.arn not like 'arn:aws:iam::aws:policy%' - PrimaryTable: aws_iam_policy - ListOfTables: - - aws_iam_policy - Parameters: [] + FROM + aws_iam_policy AS p + LEFT JOIN bad_policies AS bad ON p.arn = bad.arn + WHERE + p.arn NOT LIKE 'arn:aws:iam::aws:policy%' Severity: low Tags: pci: @@ -60,5 +58,4 @@ Tags: - aws service: - iam -IntegrationType: - - aws_cloud_account +Title: IAM policy should not have statements with admin access \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_policy_unused.yaml b/compliance/controls/aws/aws_iam_policy_unused.yaml old mode 100755 new mode 100644 index 799e6693b..f9984a24a --- a/compliance/controls/aws/aws_iam_policy_unused.yaml +++ b/compliance/controls/aws/aws_iam_policy_unused.yaml @@ -1,16 +1,56 @@ +Description: This control checks whether the IAM policy ARN is attached to an IAM user, or a group with one or more IAM users, or an IAM role with one or more trusted entity. ID: aws_iam_policy_unused -Title: "IAM policy should be in use" -Description: "This control checks whether the IAM policy ARN is attached to an IAM user, or a group with one or more IAM users, or an IAM role with one or more trusted entity." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with in_use_policies as (\n select\n attached_policy_arns\n from\n aws_iam_user\n union\n select\n attached_policy_arns\n from\n aws_iam_group\n where\n jsonb_array_length(users) > 0\n union\n select\n attached_policy_arns\n from\n aws_iam_role\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when arn in (select jsonb_array_elements_text(attached_policy_arns) from in_use_policies) then 'ok'\n else 'alarm'\n end as status,\n case\n when arn in (select jsonb_array_elements_text(attached_policy_arns) from in_use_policies) then title || ' in use.'\n else title || ' not in use.'\n end as reason\n \n , account_id\nfrom\n aws_iam_policy;\n" - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_group - aws_iam_policy - aws_iam_role - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH in_use_policies AS ( + SELECT + attached_policy_arns + FROM + aws_iam_user + UNION + SELECT + attached_policy_arns + FROM + aws_iam_group + WHERE + jsonb_array_length(users) > 0 + UNION + SELECT + attached_policy_arns + FROM + aws_iam_role + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN arn IN ( + SELECT jsonb_array_elements_text(attached_policy_arns) + FROM in_use_policies + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN arn IN ( + SELECT jsonb_array_elements_text(attached_policy_arns) + FROM in_use_policies + ) THEN title || ' in use.' + ELSE title || ' not in use.' + END AS reason, + account_id + FROM + aws_iam_policy; Severity: high Tags: category: @@ -27,5 +67,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM policy should be in use \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_role_no_administrator_access_policy_attached.yaml b/compliance/controls/aws/aws_iam_role_no_administrator_access_policy_attached.yaml old mode 100755 new mode 100644 index b43efcf44..c0cf7fd81 --- a/compliance/controls/aws/aws_iam_role_no_administrator_access_policy_attached.yaml +++ b/compliance/controls/aws/aws_iam_role_no_administrator_access_policy_attached.yaml @@ -1,42 +1,42 @@ +Description: AWS IAM role should not be attached Administratoraccess policy. ID: aws_iam_role_no_administrator_access_policy_attached -Title: "Ensure IAM role not attached with Administratoraccess policy" -Description: "AWS IAM role should not be attached Administratoraccess policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with admin_roles as ( - select + ListOfTables: + - aws_iam_role + Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH admin_roles AS ( + SELECT arn, name, attachments - from + FROM aws_iam_role, - jsonb_array_elements_text(attached_policy_arns) as attachments - where - split_part(attachments, '/', 2) = 'AdministratorAccess' + JSONB_ARRAY_ELEMENTS_TEXT(attached_policy_arns) AS attachments + WHERE + SPLIT_PART(attachments, '/', 2) = 'AdministratorAccess' ) - select - r.arn as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - case - when ar.arn is not null then 'alarm' - else 'ok' - end as status, - case - when ar.arn is not null then r.name || ' have AdministratorAccess policy attached.' - else r.name || ' does not have AdministratorAccess policy attached.' - end as reason - from - aws_iam_role as r - left join admin_roles ar on r.arn = ar.arn - order by + SELECT + r.arn AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN ar.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ar.arn IS NOT NULL THEN r.name || ' have AdministratorAccess policy attached.' + ELSE r.name || ' does not have AdministratorAccess policy attached.' + END AS reason + FROM + aws_iam_role AS r + LEFT JOIN admin_roles ar ON r.arn = ar.arn + ORDER BY r.name; - PrimaryTable: aws_iam_role - ListOfTables: - - aws_iam_role - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure IAM role not attached with Administratoraccess policy \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_role_should_not_have_trust_to_cognito_full_access.yaml b/compliance/controls/aws/aws_iam_role_should_not_have_trust_to_cognito_full_access.yaml old mode 100755 new mode 100644 index 311fb0524..ceb599c32 --- a/compliance/controls/aws/aws_iam_role_should_not_have_trust_to_cognito_full_access.yaml +++ b/compliance/controls/aws/aws_iam_role_should_not_have_trust_to_cognito_full_access.yaml @@ -1,38 +1,40 @@ -ID: aws_iam_role_should_not_have_trust_to_cognito_full_access -Title: "AWS IAM role should not have permissive trust with the Cognito Identity service and \"FullAccess\" permissions" Description: "" +ID: aws_iam_role_should_not_have_trust_to_cognito_full_access +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with cognito_access as ( - select role_id, - count(*) as num_cognito_access - from aws_iam_role, - jsonb_array_elements(assume_role_policy->'Statement') as stmt - where stmt->'Principal'->>'Federated' = 'cognito-identity.amazonaws.com' - and split_part(permissions_boundary_arn, '/', 2) like '%FullAccess%' - group by role_id - having count(*) > 0 - ) - select role.arn as resource, - role.og_account_id as og_account_id, - role.og_resource_id as og_resource_id, - case - when cognito_access.role_id is null then 'ok' - else 'alarm' - end as status, - case - when cognito_access.role_id is null then role.role_id || ' does not have cognito access' - else role.role_id || ' contains ' || cognito_access.num_cognito_access || ' cognito access' - end as reason, - role.region, - role.account_id - from aws_iam_role as role - left join cognito_access on cognito_access.role_id = role.role_id; - PrimaryTable: aws_iam_role ListOfTables: - aws_iam_role Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH cognito_access AS ( + SELECT role_id, + COUNT(*) AS num_cognito_access + FROM aws_iam_role, + jsonb_array_elements(assume_role_policy->'Statement') AS stmt + WHERE stmt->'Principal'->>'Federated' = 'cognito-identity.amazonaws.com' + AND split_part(permissions_boundary_arn, '/', 2) LIKE '%FullAccess%' + GROUP BY role_id + HAVING COUNT(*) > 0 + ) + + SELECT role.arn AS resource, + role.og_account_id AS og_account_id, + role.og_resource_id AS og_resource_id, + CASE + WHEN cognito_access.role_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cognito_access.role_id IS NULL THEN role.role_id || ' does not have cognito access' + ELSE role.role_id || ' contains ' || cognito_access.num_cognito_access || ' cognito access' + END AS reason, + role.region, + role.account_id + FROM aws_iam_role AS role + LEFT JOIN cognito_access ON cognito_access.role_id = role.role_id; Severity: critical Tags: category: [] @@ -47,5 +49,4 @@ Tags: x-kaytu-explanation: [] x-kaytu-noncompliance-cost: [] x-kaytu-usefulness-example: [] -IntegrationType: - - aws_cloud_account +Title: AWS IAM role should not have permissive trust with the Cognito Identity service and "FullAccess" permissions \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_role_unused_60.yaml b/compliance/controls/aws/aws_iam_role_unused_60.yaml old mode 100755 new mode 100644 index fae06e27f..5320f9876 --- a/compliance/controls/aws/aws_iam_role_unused_60.yaml +++ b/compliance/controls/aws/aws_iam_role_unused_60.yaml @@ -1,14 +1,31 @@ +Description: This control checks whether the IAM role has been used in 60 days. Unused accounts and roles increase the attack surface area. ID: aws_iam_role_unused_60 -Title: "IAM roles that have not been used in 60 days should be removed" -Description: "This control checks whether the IAM role has been used in 60 days. Unused accounts and roles increase the attack surface area." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when role_last_used_date <= (current_date - interval '60' day) or role_last_used_date is null\n then 'alarm'\n else 'ok'\n end as status,\n case\n when role_last_used_date is null\n then name || ' was never used.'\n else\n name || ' was last used ' || to_char(role_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_date - role_last_used_date) || ' days ago).'\n end as reason\n \nfrom\n aws_iam_role;" - PrimaryTable: aws_iam_role ListOfTables: - aws_iam_role Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN role_last_used_date <= (CURRENT_DATE - INTERVAL '60' DAY) OR role_last_used_date IS NULL + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN role_last_used_date IS NULL + THEN name || ' was never used.' + ELSE name || ' was last used ' || TO_CHAR(role_last_used_date , 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM CURRENT_DATE - role_last_used_date) || ' days ago).' + END AS reason + FROM + aws_iam_role; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM roles that have not been used in 60 days should be removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_root_last_used.yaml b/compliance/controls/aws/aws_iam_root_last_used.yaml old mode 100755 new mode 100644 index 8a644e4d2..36cd9e534 --- a/compliance/controls/aws/aws_iam_root_last_used.yaml +++ b/compliance/controls/aws/aws_iam_root_last_used.yaml @@ -1,40 +1,41 @@ +Description: This control checks whether the root user has been used in the last 90 days. The control fails if the root user has been used in the last 90 days. ID: aws_iam_root_last_used -Title: "Eliminate use of the 'root' user for administrative and daily tasks" -Description: "This control checks whether the root user has been used in the last 90 days. The control fails if the root user has been used in the last 90 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when password_last_used >= (current_date - interval '90' day) then 'alarm' - when access_key_1_last_used_date <= (current_date - interval '90' day) then 'alarm' - when access_key_2_last_used_date <= (current_date - interval '90' day) then 'alarm' - else 'ok' - end as status, - case - when password_last_used is null then 'Root never logged in with password.' - else 'Root password used ' || to_char(password_last_used , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - password_last_used) || ' days).' - end || - case - when access_key_1_last_used_date is null then ' Access Key 1 never used.' - else ' Access Key 1 used ' || to_char(access_key_1_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_1_last_used_date) || ' days).' - end || - case - when access_key_2_last_used_date is null then ' Access Key 2 never used.' - else ' Access Key 2 used ' || to_char(access_key_2_last_used_date , 'DD-Mon-YYYY') || ' (' || extract(day from current_timestamp - access_key_2_last_used_date) || ' days).' - end as reason - , account_id - from - aws_iam_credential_report - where - user_name = ''; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_last_used >= (current_date - INTERVAL '90' day) THEN 'alarm' + WHEN access_key_1_last_used_date <= (current_date - INTERVAL '90' day) THEN 'alarm' + WHEN access_key_2_last_used_date <= (current_date - INTERVAL '90' day) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN password_last_used IS NULL THEN 'Root never logged in with password.' + ELSE 'Root password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM current_timestamp - password_last_used) || ' days).' + END || + CASE + WHEN access_key_1_last_used_date IS NULL THEN ' Access Key 1 never used.' + ELSE ' Access Key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM current_timestamp - access_key_1_last_used_date) || ' days).' + END || + CASE + WHEN access_key_2_last_used_date IS NULL THEN ' Access Key 2 never used.' + ELSE ' Access Key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || ' (' || EXTRACT(day FROM current_timestamp - access_key_2_last_used_date) || ' days).' + END AS reason, + account_id + FROM + aws_iam_credential_report + WHERE + user_name = ''; Severity: high Tags: category: @@ -55,5 +56,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Eliminate use of the 'root' user for administrative and daily tasks \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_root_user_hardware_mfa_enabled.yaml b/compliance/controls/aws/aws_iam_root_user_hardware_mfa_enabled.yaml old mode 100755 new mode 100644 index 013b4ed1b..b22c83139 --- a/compliance/controls/aws/aws_iam_root_user_hardware_mfa_enabled.yaml +++ b/compliance/controls/aws/aws_iam_root_user_hardware_mfa_enabled.yaml @@ -1,31 +1,35 @@ +Description: Manage access to resources in the AWS Cloud by ensuring hardware MFA is enabled for the root user. ID: aws_iam_root_user_hardware_mfa_enabled -Title: "IAM root user hardware MFA should be enabled" -Description: "Manage access to resources in the AWS Cloud by ensuring hardware MFA is enabled for the root user." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || s.partition || ':::' || s.account_id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when account_mfa_enabled and serial_number is null then 'ok' - else 'alarm' - end status, - case - when account_mfa_enabled = false then 'MFA not enabled for root account.' - when serial_number is not null then 'MFA enabled for root account, but the MFA associated is a virtual device.' - else 'Hardware MFA device enabled for root account.' - end reason - , s.account_id - from - aws_iam_account_summary as s - left join aws_iam_virtual_mfa_device on serial_number = 'arn:' || s.partition || ':iam::' || s.account_id || ':mfa/root-account-mfa-device'; - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary - aws_iam_virtual_mfa_device Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || s.partition || ':::' || s.account_id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN account_mfa_enabled AND serial_number IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN account_mfa_enabled = FALSE THEN 'MFA not enabled for root account.' + WHEN serial_number IS NOT NULL THEN 'MFA enabled for root account, but the MFA associated is a virtual device.' + ELSE 'Hardware MFA device enabled for root account.' + END reason, + s.account_id + FROM + aws_iam_account_summary AS s + LEFT JOIN + aws_iam_virtual_mfa_device + ON + serial_number = 'arn:' || s.partition || ':iam::' || s.account_id || ':mfa/root-account-mfa-device'; Severity: high Tags: category: @@ -48,12 +52,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -64,5 +68,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM root user hardware MFA should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_root_user_mfa_enabled.yaml b/compliance/controls/aws/aws_iam_root_user_mfa_enabled.yaml old mode 100755 new mode 100644 index 2b19ee7bc..545042089 --- a/compliance/controls/aws/aws_iam_root_user_mfa_enabled.yaml +++ b/compliance/controls/aws/aws_iam_root_user_mfa_enabled.yaml @@ -1,28 +1,29 @@ +Description: Manage access to resources in the AWS Cloud by ensuring MFA is enabled for the root user. ID: aws_iam_root_user_mfa_enabled -Title: "IAM root user MFA should be enabled" -Description: "Manage access to resources in the AWS Cloud by ensuring MFA is enabled for the root user." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || partition || ':::' || account_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when account_mfa_enabled then 'ok' - else 'alarm' - end status, - case - when account_mfa_enabled then 'MFA enabled for root account.' - else 'MFA not enabled for root account.' - end reason - , account_id - from - aws_iam_account_summary; - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_mfa_enabled THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN account_mfa_enabled THEN 'MFA enabled for root account.' + ELSE 'MFA not enabled for root account.' + END reason, + account_id + FROM + aws_iam_account_summary; Severity: critical Tags: audit_manager_control_tower: @@ -47,12 +48,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -61,5 +62,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM root user MFA should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_root_user_no_access_keys.yaml b/compliance/controls/aws/aws_iam_root_user_no_access_keys.yaml old mode 100755 new mode 100644 index 9d8cdf3b2..4e6de5028 --- a/compliance/controls/aws/aws_iam_root_user_no_access_keys.yaml +++ b/compliance/controls/aws/aws_iam_root_user_no_access_keys.yaml @@ -1,28 +1,29 @@ +Description: Access to systems and assets can be controlled by checking that the root user does not have access keys attached to their AWS Identity and Access Management (IAM) role. ID: aws_iam_root_user_no_access_keys -Title: "IAM root user should not have access keys" -Description: "Access to systems and assets can be controlled by checking that the root user does not have access keys attached to their AWS Identity and Access Management (IAM) role." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || partition || ':::' || account_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when account_access_keys_present > 0 then 'alarm' - else 'ok' - end status, - case - when account_access_keys_present > 0 then 'Root user access keys exist.' - else 'No root user access keys exist.' - end reason - , account_id - from - aws_iam_account_summary; - PrimaryTable: aws_iam_account_summary ListOfTables: - aws_iam_account_summary Parameters: [] + PrimaryTable: aws_iam_account_summary + QueryToExecute: | + SELECT + 'arn:' || partition || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_access_keys_present > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN account_access_keys_present > 0 THEN 'Root user access keys exist.' + ELSE 'No root user access keys exist.' + END AS reason, + account_id + FROM + aws_iam_account_summary; Severity: high Tags: category: @@ -45,12 +46,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -63,5 +64,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM root user should not have access keys \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_security_audit_role.yaml b/compliance/controls/aws/aws_iam_security_audit_role.yaml old mode 100755 new mode 100644 index da71dea52..dca838382 --- a/compliance/controls/aws/aws_iam_security_audit_role.yaml +++ b/compliance/controls/aws/aws_iam_security_audit_role.yaml @@ -1,51 +1,53 @@ +Description: Ensure IAM Security Audit role is created. By creating an IAM role with a security audit policy, a distinct segregation of responsibilities is established between the security team and other teams within the organization. ID: aws_iam_security_audit_role -Title: "IAM Security Audit role should be created to conduct security audits" -Description: "Ensure IAM Security Audit role is created. By creating an IAM role with a security audit policy, a distinct segregation of responsibilities is established between the security team and other teams within the organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with security_audit_role_count as( - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - count(policy_arn), + ListOfTables: + - aws_account + - aws_iam_role + Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH security_audit_role_count AS ( + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + COUNT(policy_arn), a.account_id, a._ctx, a.og_account_id, a.og_resource_id - from - aws_account as a - left join aws_iam_role as r on r.account_id = a.account_id - left join jsonb_array_elements_text(attached_policy_arns) as policy_arn on true - where + FROM + aws_account AS a + LEFT JOIN aws_iam_role AS r + ON r.account_id = a.account_id + LEFT JOIN jsonb_array_elements_text(attached_policy_arns) AS policy_arn + ON TRUE + WHERE policy_arn = 'arn:aws:iam::aws:policy/SecurityAudit' - group by + GROUP BY a.account_id, a.partition, a._ctx, a.og_account_id, a.og_resource_id ) - select + SELECT resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when count > 0 then 'ok' - else 'alarm' - end as status, - case - when count = 1 then 'SecurityAudit policy attached to 1 role.' - when count > 1 then 'SecurityAudit policy attached to ' || count || ' roles.' - else 'SecurityAudit policy not attached to any role.' - end as reason - from + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN COUNT > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT = 1 THEN 'SecurityAudit policy attached to 1 role.' + WHEN COUNT > 1 THEN 'SecurityAudit policy attached to ' || COUNT || ' roles.' + ELSE 'SecurityAudit policy not attached to any role.' + END AS reason + FROM security_audit_role_count; - PrimaryTable: aws_iam_role - ListOfTables: - - aws_account - - aws_iam_role - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM Security Audit role should be created to conduct security audits \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_server_certificate_not_expired.yaml b/compliance/controls/aws/aws_iam_server_certificate_not_expired.yaml old mode 100755 new mode 100644 index 0430ed558..5aec413b5 --- a/compliance/controls/aws/aws_iam_server_certificate_not_expired.yaml +++ b/compliance/controls/aws/aws_iam_server_certificate_not_expired.yaml @@ -1,13 +1,31 @@ +Description: To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console. ID: aws_iam_server_certificate_not_expired -Title: "Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed" -Description: "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case when expiration < (current_date - interval '1' second) then 'alarm'\n else 'ok'\n end as status,\n case when expiration < (current_date - interval '1' second) then\n name || ' expired ' || to_char(expiration, 'DD-Mon-YYYY') || '.'\n else\n name || ' valid until ' || to_char(expiration, 'DD-Mon-YYYY') || '.'\n end as reason\n \n , account_id\nfrom\n aws_iam_server_certificate;\n" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: [] + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN expiration < (current_date - INTERVAL '1' SECOND) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expiration < (current_date - INTERVAL '1' SECOND) THEN + name || ' expired ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + ELSE + name || ' valid until ' || TO_CHAR(expiration, 'DD-Mon-YYYY') || '.' + END AS reason, + account_id + FROM + aws_iam_server_certificate; Severity: medium Tags: category: @@ -28,5 +46,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure that all the expired SSL/TLS certificates stored in AWS IAM are removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_support_role.yaml b/compliance/controls/aws/aws_iam_support_role.yaml old mode 100755 new mode 100644 index 3879aeef5..1f06f5ea1 --- a/compliance/controls/aws/aws_iam_support_role.yaml +++ b/compliance/controls/aws/aws_iam_support_role.yaml @@ -1,54 +1,53 @@ +Description: AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. ID: aws_iam_support_role -Title: "Ensure a support role has been created to manage incidents with AWS Support" -Description: "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_account + - aws_iam_role + Parameters: [] + PrimaryTable: aws_account QueryToExecute: | - -- pgFormatter-ignore - with support_role_count as - ( - select - 'arn:' || a.partition || ':::' || a.account_id as resource, - count(policy_arn), + WITH support_role_count AS ( + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + COUNT(policy_arn), a.account_id, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, a._ctx - from - aws_account as a - left join aws_iam_role as r on r.account_id = a.account_id - left join jsonb_array_elements_text(attached_policy_arns) as policy_arn on true - where - split_part(policy_arn, '/', 2) = 'AWSSupportAccess' - or policy_arn is null - group by + FROM + aws_account AS a + LEFT JOIN aws_iam_role AS r ON r.account_id = a.account_id + LEFT JOIN jsonb_array_elements_text(attached_policy_arns) AS policy_arn ON true + WHERE + SPLIT_PART(policy_arn, '/', 2) = 'AWSSupportAccess' + OR policy_arn IS NULL + GROUP BY a.account_id, a.partition, a.og_account_id, a.og_resource_id, a._ctx ) - select + SELECT resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when count > 0 then 'ok' - else 'alarm' - end as status, - case - when count = 1 then 'AWSSupportAccess policy attached to 1 role.' - when count > 1 then 'AWSSupportAccess policy attached to ' || count || ' roles.' - else 'AWSSupportAccess policy not attached to any role.' - end as reason - , account_id - from + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN COUNT > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT = 1 THEN 'AWSSupportAccess policy attached to 1 role.' + WHEN COUNT > 1 THEN 'AWSSupportAccess policy attached to ' || COUNT || ' roles.' + ELSE 'AWSSupportAccess policy not attached to any role.' + END AS reason, + account_id + FROM support_role_count; - PrimaryTable: aws_account - ListOfTables: - - aws_account - - aws_iam_role - Parameters: [] Severity: low Tags: category: @@ -71,5 +70,4 @@ Tags: - Problem Identities service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure a support role has been created to manage incidents with AWS Support \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_access_key_age_90.yaml b/compliance/controls/aws/aws_iam_user_access_key_age_90.yaml old mode 100755 new mode 100644 index 2c9fd2d77..3d0d720ea --- a/compliance/controls/aws/aws_iam_user_access_key_age_90.yaml +++ b/compliance/controls/aws/aws_iam_user_access_key_age_90.yaml @@ -1,27 +1,27 @@ +Description: The credentials are audited for authorized devices, users, and processes by ensuring IAM access keys are rotated as per organizational policy. ID: aws_iam_user_access_key_age_90 -Title: "IAM user access keys should be rotated at least every 90 days" -Description: "The credentials are audited for authorized devices, users, and processes by ensuring IAM access keys are rotated as per organizational policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when create_date <= (current_date - interval '90' day) then 'alarm' - else 'ok' - end status, - user_name || ' ' || access_key_id || ' created ' || to_char(create_date , 'DD-Mon-YYYY') || - ' (' || extract(day from current_timestamp - create_date) || ' days).' - as reason - , account_id - from - aws_iam_access_key; - PrimaryTable: aws_iam_access_key ListOfTables: - aws_iam_access_key Parameters: [] + PrimaryTable: aws_iam_access_key + QueryToExecute: | + SELECT + 'arn:' || partition || ':iam::' || account_id || ':user/' || user_name || '/accesskey/' || access_key_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN create_date <= (CURRENT_DATE - INTERVAL '90' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || ' ' || access_key_id || ' created ' || TO_CHAR(create_date, 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - create_date) || ' days).' AS reason, + account_id + FROM + aws_iam_access_key; Severity: high Tags: category: @@ -42,5 +42,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: IAM user access keys should be rotated at least every 90 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_access_key_unused_45.yaml b/compliance/controls/aws/aws_iam_user_access_key_unused_45.yaml old mode 100755 new mode 100644 index f7fe569b1..bf9d8af43 --- a/compliance/controls/aws/aws_iam_user_access_key_unused_45.yaml +++ b/compliance/controls/aws/aws_iam_user_access_key_unused_45.yaml @@ -1,14 +1,40 @@ +Description: AWS IAM users can access AWS resources using access keys. It is recommended that access keys that have been unused in 45 or greater days be deactivated or removed. ID: aws_iam_user_access_key_unused_45 -Title: "Ensure IAM users with access keys unused for 45 days or greater are disabled" -Description: "AWS IAM users can access AWS resources using access keys. It is recommended that access keys that have been unused in 45 or greater days be deactivated or removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when not access_key_1_active then 'ok'\n when access_key_1_active and access_key_1_last_used_date is null then 'alarm'\n when access_key_1_active and access_key_1_last_used_date < (current_date - interval '45' day) then 'alarm'\n when not access_key_2_active then 'ok'\n when access_key_2_active and access_key_2_last_used_date is null then 'alarm'\n when access_key_2_active and access_key_2_last_used_date < (current_date - interval '45' day) then 'alarm'\n else 'ok'\n end as status,\n user_name ||\n case\n when not access_key_1_active then ' key 1 not enabled,'\n when access_key_1_active and access_key_1_last_used_date is null then ' key 1 created ' || to_char(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,'\n else ' key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ','\n end ||\n case\n when not access_key_2_active then ' key 2 not enabled.'\n when access_key_2_active and access_key_2_last_used_date is null then ' key 2 created ' || to_char(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.'\n else ' key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.'\n end as reason\n \nfrom\n aws_iam_credential_report;\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT access_key_1_active THEN 'ok' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date < (CURRENT_DATE - INTERVAL '45' DAY) THEN 'alarm' + WHEN NOT access_key_2_active THEN 'ok' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date < (CURRENT_DATE - INTERVAL '45' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || + CASE + WHEN NOT access_key_1_active THEN ' key 1 not enabled,' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL THEN ' key 1 created ' || TO_CHAR(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' + ELSE ' key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_2_active THEN ' key 2 not enabled.' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL THEN ' key 2 created ' || TO_CHAR(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' + ELSE ' key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure IAM users with access keys unused for 45 days or greater are disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_access_keys_and_password_at_setup.yaml b/compliance/controls/aws/aws_iam_user_access_keys_and_password_at_setup.yaml old mode 100755 new mode 100644 index 3e909ae72..f20bfff38 --- a/compliance/controls/aws/aws_iam_user_access_keys_and_password_at_setup.yaml +++ b/compliance/controls/aws/aws_iam_user_access_keys_and_password_at_setup.yaml @@ -1,32 +1,34 @@ +Description: This control checks whether the IAM users have access keys and passwords at setup. + The control fails if the IAM users do not have access keys and passwords at setup. ID: aws_iam_user_access_keys_and_password_at_setup -Title: "Ensure IAM users are assigned access keys and passwords at setup" -Description: "This control checks whether the IAM users have access keys and passwords at setup. The control fails if the IAM users do not have access keys and passwords at setup." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - -- alarm when password is enabled and the key was created within 10 seconds of the user - when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) then 'alarm' - else 'ok' - end as status, - case - when not password_enabled then user_name || ' password login disabled.' - when access_key_1_last_rotated is null then user_name || ' has no access keys.' - when password_enabled and (extract(epoch from (access_key_1_last_rotated - user_creation_time)) < 10) - then user_name || ' has access key created during user creation and password login enabled.' - else user_name || ' has access key not created during user creation.' - end as reason - , account_id - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND (EXTRACT(EPOCH FROM (access_key_1_last_rotated - user_creation_time)) < 10) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN access_key_1_last_rotated IS NULL THEN user_name || ' has no access keys.' + WHEN password_enabled AND (EXTRACT(EPOCH FROM (access_key_1_last_rotated - user_creation_time)) < 10) + THEN user_name || ' has access key created during user creation and password login enabled.' + ELSE user_name || ' has access key not created during user creation.' + END AS reason, + account_id + FROM + aws_iam_credential_report; Severity: high Tags: category: @@ -47,5 +49,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure IAM users are assigned access keys and passwords at setup \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_console_access_mfa_enabled.yaml b/compliance/controls/aws/aws_iam_user_console_access_mfa_enabled.yaml old mode 100755 new mode 100644 index d8a195fa2..9fd5d00f1 --- a/compliance/controls/aws/aws_iam_user_console_access_mfa_enabled.yaml +++ b/compliance/controls/aws/aws_iam_user_console_access_mfa_enabled.yaml @@ -1,29 +1,30 @@ +Description: Manage access to resources in the AWS Cloud by ensuring that MFA is enabled for all AWS Identity and Access Management (IAM) users that have a console password. ID: aws_iam_user_console_access_mfa_enabled -Title: "IAM users with console access should have MFA enabled" -Description: "Manage access to resources in the AWS Cloud by ensuring that MFA is enabled for all AWS Identity and Access Management (IAM) users that have a console password." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when password_enabled and not mfa_active then 'alarm' - else 'ok' - end as status, - case - when not password_enabled then user_name || ' password login disabled.' - when password_enabled and not mfa_active then user_name || ' password login enabled but no MFA device configured.' - else user_name || ' password login enabled and MFA device configured.' - end as reason - , account_id - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN password_enabled AND NOT mfa_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN user_name || ' password login disabled.' + WHEN password_enabled AND NOT mfa_active THEN user_name || ' password login enabled but no MFA device configured.' + ELSE user_name || ' password login enabled and MFA device configured.' + END AS reason, + account_id + FROM + aws_iam_credential_report; Severity: high Tags: audit_manager_control_tower: @@ -48,12 +49,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -64,5 +65,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM users with console access should have MFA enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_console_access_unused_45.yaml b/compliance/controls/aws/aws_iam_user_console_access_unused_45.yaml old mode 100755 new mode 100644 index f88025fdc..00281c450 --- a/compliance/controls/aws/aws_iam_user_console_access_unused_45.yaml +++ b/compliance/controls/aws/aws_iam_user_console_access_unused_45.yaml @@ -1,32 +1,31 @@ +Description: AWS IAM users can access AWS resources using console access. It is recommended that console access that have been unused in 45 or greater days be deactivated or removed. ID: aws_iam_user_console_access_unused_45 -Title: "Ensure IAM users with console access unused for 45 days or greater are disabled" -Description: "AWS IAM users can access AWS resources using console access. It is recommended that console access that have been unused in 45 or greater days be deactivated or removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not password_enabled then 'ok' - when password_enabled and password_last_used is null then 'alarm' - when password_enabled and password_last_used < (current_date - interval '45' day) then 'alarm' - else 'ok' - end status, - user_name || - case - when not password_enabled then ' password not enabled.' - when password_enabled and password_last_used is null then ' password created ' || to_char(password_last_changed, 'DD-Mon-YYYY') || ' never used.' - else ' password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || '.' - end as reason - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT password_enabled THEN 'ok' + WHEN password_enabled AND password_last_used IS NULL THEN 'alarm' + WHEN password_enabled AND password_last_used < (CURRENT_DATE - INTERVAL '45' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || + CASE + WHEN NOT password_enabled THEN ' password not enabled.' + WHEN password_enabled AND password_last_used IS NULL THEN ' password created ' || TO_CHAR(password_last_changed, 'DD-Mon-YYYY') || ' never used.' + ELSE ' password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || '.' + END AS reason + FROM aws_iam_credential_report; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure IAM users with console access unused for 45 days or greater are disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_group_role_cloudshell_fullaccess_restricted.yaml b/compliance/controls/aws/aws_iam_user_group_role_cloudshell_fullaccess_restricted.yaml old mode 100755 new mode 100644 index 8e3d55d08..fbcd0c0de --- a/compliance/controls/aws/aws_iam_user_group_role_cloudshell_fullaccess_restricted.yaml +++ b/compliance/controls/aws/aws_iam_user_group_role_cloudshell_fullaccess_restricted.yaml @@ -1,65 +1,72 @@ +Description: This control checks whether the AWSCloudShellFullAccess policy is attached to any IAM user, group, or role. The control fails if the policy is attached to any IAM user, group, or role. ID: aws_iam_user_group_role_cloudshell_fullaccess_restricted -Title: "Ensure access to AWSCloudShellFullAccess is restricted" -Description: "This control checks whether the AWSCloudShellFullAccess policy is attached to any IAM user, group, or role. The control fails if the policy is attached to any IAM user, group, or role." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_iam_user' as og_table_name, - case - when attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' then 'alarm' - else 'ok' - end status, - case - when attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' then 'User ' || title || ' has access to AWSCloudShellFullAccess.' - else 'User ' || title || ' access to AWSCloudShellFullAccess is restricted.' - end as reason - , account_id - from - aws_iam_user - union - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_iam_role' as og_table_name, - case - when attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' then 'alarm' - else 'ok' - end status, - case - when attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' then 'Role ' || title || ' has access to AWSCloudShellFullAccess.' - else 'Role ' || title || ' access to AWSCloudShellFullAccess is restricted.' - end as reason - , account_id - from - aws_iam_role - union - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'aws_iam_group' as og_table_name, - case - when attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' then 'alarm' - else 'ok' - end status, - case - when attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' then 'Group ' || title || ' has access to AWSCloudShellFullAccess.' - else 'Group ' || title || ' access to AWSCloudShellFullAccess is restricted.' - end as reason - , account_id - from - aws_iam_group; - PrimaryTable: "" ListOfTables: - aws_iam_group - aws_iam_role - aws_iam_user Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_iam_user' AS og_table_name, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' + THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' + THEN 'User ' || title || ' has access to AWSCloudShellFullAccess.' + ELSE 'User ' || title || ' access to AWSCloudShellFullAccess is restricted.' + END AS reason, + account_id + FROM + aws_iam_user + UNION + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_iam_role' AS og_table_name, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' + THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' + THEN 'Role ' || title || ' has access to AWSCloudShellFullAccess.' + ELSE 'Role ' || title || ' access to AWSCloudShellFullAccess is restricted.' + END AS reason, + account_id + FROM + aws_iam_role + UNION + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_iam_group' AS og_table_name, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' + THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' + THEN 'Group ' || title || ' has access to AWSCloudShellFullAccess.' + ELSE 'Group ' || title || ' access to AWSCloudShellFullAccess is restricted.' + END AS reason, + account_id + FROM + aws_iam_group; Severity: high Tags: category: @@ -81,5 +88,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure access to AWSCloudShellFullAccess is restricted \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_in_group.yaml b/compliance/controls/aws/aws_iam_user_in_group.yaml old mode 100755 new mode 100644 index d8b3ff2a3..d5463bc2d --- a/compliance/controls/aws/aws_iam_user_in_group.yaml +++ b/compliance/controls/aws/aws_iam_user_in_group.yaml @@ -1,13 +1,29 @@ +Description: AWS Identity and Access Management (IAM) can help you restrict access permissions and authorizations, by ensuring IAM users are members of at least one group. ID: aws_iam_user_in_group -Title: "IAM users should be in at least one group" -Description: "AWS Identity and Access Management (IAM) can help you restrict access permissions and authorizations, by ensuring IAM users are members of at least one group." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(groups) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when jsonb_array_length(groups) = 0 then title || ' not associated with any IAM group.'\n else title || ' associated with IAM group.'\n end as reason\n \n , account_id\nfrom\n aws_iam_user;\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(groups) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN jsonb_array_length(groups) = 0 THEN title || ' not associated with any IAM group.' + ELSE title || ' associated with IAM group.' + END AS reason, + account_id + FROM + aws_iam_user; Severity: high Tags: category: @@ -26,12 +42,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -40,5 +56,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM users should be in at least one group \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_mfa_enabled.yaml b/compliance/controls/aws/aws_iam_user_mfa_enabled.yaml old mode 100755 new mode 100644 index af68da05b..7ebf410e1 --- a/compliance/controls/aws/aws_iam_user_mfa_enabled.yaml +++ b/compliance/controls/aws/aws_iam_user_mfa_enabled.yaml @@ -1,28 +1,29 @@ +Description: Enable this rule to restrict access to resources in the AWS Cloud. ID: aws_iam_user_mfa_enabled -Title: "IAM user MFA should be enabled" -Description: "Enable this rule to restrict access to resources in the AWS Cloud." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not mfa_active then 'alarm' - else 'ok' - end as status, - case - when not mfa_active then user_name || ' MFA device not configured.' - else user_name || ' MFA device configured.' - end as reason - , account_id - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT mfa_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT mfa_active THEN user_name || ' MFA device not configured.' + ELSE user_name || ' MFA device configured.' + END AS reason, + account_id + FROM + aws_iam_credential_report; Severity: high Tags: audit_manager_control_tower: @@ -45,12 +46,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -61,5 +62,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM user MFA should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_no_inline_attached_policies.yaml b/compliance/controls/aws/aws_iam_user_no_inline_attached_policies.yaml old mode 100755 new mode 100644 index 52efc60f2..5e636d247 --- a/compliance/controls/aws/aws_iam_user_no_inline_attached_policies.yaml +++ b/compliance/controls/aws/aws_iam_user_no_inline_attached_policies.yaml @@ -1,13 +1,27 @@ +Description: This rule ensures AWS Identity and Access Management (IAM) policies are attached only to groups or roles to control access to systems and assets. ID: aws_iam_user_no_inline_attached_policies -Title: "IAM user should not have any inline or attached policies" -Description: "This rule ensures AWS Identity and Access Management (IAM) policies are attached only to groups or roles to control access to systems and assets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when inline_policies is null and attached_policy_arns is null then 'ok'\n else 'alarm'\n end status,\n name || ' has ' || coalesce(jsonb_array_length(inline_policies),0) || ' inline and ' ||\n coalesce(jsonb_array_length(attached_policy_arns),0) || ' directly attached policies.' as reason\n \n , account_id\nfrom\n aws_iam_user;\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN inline_policies IS NULL AND attached_policy_arns IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' has ' || COALESCE(jsonb_array_length(inline_policies), 0) || ' inline and ' || + COALESCE(jsonb_array_length(attached_policy_arns), 0) || ' directly attached policies.' AS reason, + account_id + FROM + aws_iam_user; Severity: high Tags: category: @@ -30,12 +44,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +62,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM user should not have any inline or attached policies \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_no_policies.yaml b/compliance/controls/aws/aws_iam_user_no_policies.yaml old mode 100755 new mode 100644 index 4d9ca6ea7..8c378511d --- a/compliance/controls/aws/aws_iam_user_no_policies.yaml +++ b/compliance/controls/aws/aws_iam_user_no_policies.yaml @@ -1,13 +1,26 @@ +Description: By default, IAM users, groups, and roles have no access to AWS resources. IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended that IAM policies be applied directly to groups and roles but not users. ID: aws_iam_user_no_policies -Title: "Ensure IAM policies are attached only to groups or roles" -Description: "By default, IAM users, groups, and roles have no access to AWS resources. IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended that IAM policies be applied directly to groups and roles but not users." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when attached_policy_arns is null then 'ok'\n else 'alarm'\n end status,\n name || ' has ' || coalesce(jsonb_array_length(attached_policy_arns),0) || ' attached policies.' as reason\n \n , account_id\nfrom\n aws_iam_user;\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN attached_policy_arns IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' has ' || COALESCE(jsonb_array_length(attached_policy_arns), 0) || ' attached policies.' AS reason, + account_id + FROM + aws_iam_user; Severity: medium Tags: category: @@ -30,5 +43,4 @@ Tags: - Problem Identities service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure IAM policies are attached only to groups or roles \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_one_active_key.yaml b/compliance/controls/aws/aws_iam_user_one_active_key.yaml old mode 100755 new mode 100644 index e79dbee9f..594a78536 --- a/compliance/controls/aws/aws_iam_user_one_active_key.yaml +++ b/compliance/controls/aws/aws_iam_user_one_active_key.yaml @@ -1,14 +1,42 @@ +Description: Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK). ID: aws_iam_user_one_active_key -Title: "Ensure there is only one active access key available for any single IAM user" -Description: "Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n u.arn as resource,\n u.og_account_id as og_account_id,\n u.og_resource_id as og_resource_id,\n case\n when count(k.*) > 1 then 'alarm'\n else 'ok'\n end as status,\n u.name || ' has ' || count(k.*) || ' active access key(s).' as reason\n \n , u.account_id\nfrom\n aws_iam_user as u\n left join aws_iam_access_key as k on u.name = k.user_name and u.account_id = k.account_id\nwhere\n k.status = 'Active' or k.status is null\ngroup by\n u.arn,\n u.name,\n u.account_id,\n u.tags,\n u.og_account_id,\n u.og_resource_id,\n u._ctx;\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_access_key - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + u.arn AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(k.*) > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + u.name || ' has ' || COUNT(k.*) || ' active access key(s).' AS reason, + u.account_id + FROM + aws_iam_user AS u + LEFT JOIN + aws_iam_access_key AS k + ON + u.name = k.user_name + AND u.account_id = k.account_id + WHERE + k.status = 'Active' OR k.status IS NULL + GROUP BY + u.arn, + u.name, + u.account_id, + u.tags, + u.og_account_id, + u.og_resource_id, + u._ctx; Severity: high Tags: category: @@ -29,5 +57,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure there is only one active access key available for any single IAM user \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_unused_credentials_45.yaml b/compliance/controls/aws/aws_iam_user_unused_credentials_45.yaml old mode 100755 new mode 100644 index a6fec9f63..08cccb295 --- a/compliance/controls/aws/aws_iam_user_unused_credentials_45.yaml +++ b/compliance/controls/aws/aws_iam_user_unused_credentials_45.yaml @@ -1,64 +1,72 @@ +Description: AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed. ID: aws_iam_user_unused_credentials_45 -Title: "Ensure credentials unused for 45 days or greater are disabled" -Description: "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - --root_account will have always password associated even though AWS credential report returns 'not_supported' for password_enabled - when user_name = '' - then 'info' - when password_enabled and password_last_used is null and password_last_changed < (current_date - interval '45' day) - then 'alarm' - when password_enabled and password_last_used < (current_date - interval '45' day) - then 'alarm' - when access_key_1_active and access_key_1_last_used_date is null and access_key_1_last_rotated < (current_date - interval '45' day) - then 'alarm' - when access_key_1_active and access_key_1_last_used_date < (current_date - interval '45' day) - then 'alarm' - when access_key_2_active and access_key_2_last_used_date is null and access_key_2_last_rotated < (current_date - interval '45' day) - then 'alarm' - when access_key_2_active and access_key_2_last_used_date < (current_date - interval '45' day) - then 'alarm' - else 'ok' - end status, - user_name || - case - when not password_enabled - then ' password not enabled,' - when password_enabled and password_last_used is null - then ' password created ' || to_char(password_last_changed, 'DD-Mon-YYYY') || ' never used,' - else - ' password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || ',' - end || - case - when not access_key_1_active - then ' key 1 not enabled,' - when access_key_1_active and access_key_1_last_used_date is null - then ' key 1 created ' || to_char(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' - else - ' key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' - end || - case - when not access_key_2_active - then ' key 2 not enabled.' - when access_key_2_active and access_key_2_last_used_date is null - then ' key 2 created ' || to_char(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' - else - ' key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' - end - as reason - , account_id - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_name = '' + THEN 'info' + WHEN password_enabled + AND password_last_used IS NULL + AND password_last_changed < (current_date - INTERVAL '45' DAY) + THEN 'alarm' + WHEN password_enabled + AND password_last_used < (current_date - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_1_active + AND access_key_1_last_used_date IS NULL + AND access_key_1_last_rotated < (current_date - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_1_active + AND access_key_1_last_used_date < (current_date - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_2_active + AND access_key_2_last_used_date IS NULL + AND access_key_2_last_rotated < (current_date - INTERVAL '45' DAY) + THEN 'alarm' + WHEN access_key_2_active + AND access_key_2_last_used_date < (current_date - INTERVAL '45' DAY) + THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || + CASE + WHEN NOT password_enabled + THEN ' password not enabled,' + WHEN password_enabled + AND password_last_used IS NULL + THEN ' password created ' || TO_CHAR(password_last_changed, 'DD-Mon-YYYY') || ' never used,' + ELSE ' password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_1_active + THEN ' key 1 not enabled,' + WHEN access_key_1_active + AND access_key_1_last_used_date IS NULL + THEN ' key 1 created ' || TO_CHAR(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' + ELSE ' key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_2_active + THEN ' key 2 not enabled.' + WHEN access_key_2_active + AND access_key_2_last_used_date IS NULL + THEN ' key 2 created ' || TO_CHAR(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' + ELSE ' key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' + END AS reason, + account_id + FROM + aws_iam_credential_report; Severity: high Tags: category: @@ -79,5 +87,4 @@ Tags: - aws service: - AWS/IAM -IntegrationType: - - aws_cloud_account +Title: Ensure credentials unused for 45 days or greater are disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_unused_credentials_90.yaml b/compliance/controls/aws/aws_iam_user_unused_credentials_90.yaml old mode 100755 new mode 100644 index 455a111c8..27bcdbda9 --- a/compliance/controls/aws/aws_iam_user_unused_credentials_90.yaml +++ b/compliance/controls/aws/aws_iam_user_unused_credentials_90.yaml @@ -1,63 +1,63 @@ +Description: AWS Identity and Access Management (IAM) can help you with access permissions and authorizations by checking for IAM passwords and access keys that are not used for a specified time period. ID: aws_iam_user_unused_credentials_90 -Title: "IAM user credentials that have not been used in 90 days should be disabled" -Description: "AWS Identity and Access Management (IAM) can help you with access permissions and authorizations by checking for IAM passwords and access keys that are not used for a specified time period." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - user_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when user_name = '' - then 'info' - when password_enabled and password_last_used is null and password_last_changed < (current_date - interval '90' day) - then 'alarm' - when password_enabled and password_last_used < (current_date - interval '90' day) - then 'alarm' - when access_key_1_active and access_key_1_last_used_date is null and access_key_1_last_rotated < (current_date - interval '90' day) - then 'alarm' - when access_key_1_active and access_key_1_last_used_date < (current_date - interval '90' day) - then 'alarm' - when access_key_2_active and access_key_2_last_used_date is null and access_key_2_last_rotated < (current_date - interval '90' day) - then 'alarm' - when access_key_2_active and access_key_2_last_used_date < (current_date - interval '90' day) - then 'alarm' - else 'ok' - end status, - user_name || - case - when not password_enabled - then ' password not enabled,' - when password_enabled and password_last_used is null - then ' password created ' || to_char(password_last_changed, 'DD-Mon-YYYY') || ' never used,' - else - ' password used ' || to_char(password_last_used, 'DD-Mon-YYYY') || ',' - end || - case - when not access_key_1_active - then ' key 1 not enabled,' - when access_key_1_active and access_key_1_last_used_date is null - then ' key 1 created ' || to_char(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' - else - ' key 1 used ' || to_char(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' - end || - case - when not access_key_2_active - then ' key 2 not enabled.' - when access_key_2_active and access_key_2_last_used_date is null - then ' key 2 created ' || to_char(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' - else - ' key 2 used ' || to_char(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' - end - as reason - , account_id - from - aws_iam_credential_report; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_name = '' + THEN 'info' + WHEN password_enabled AND password_last_used IS NULL AND password_last_changed < (current_date - INTERVAL '90' day) + THEN 'alarm' + WHEN password_enabled AND password_last_used < (current_date - INTERVAL '90' day) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL AND access_key_1_last_rotated < (current_date - INTERVAL '90' day) + THEN 'alarm' + WHEN access_key_1_active AND access_key_1_last_used_date < (current_date - INTERVAL '90' day) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL AND access_key_2_last_rotated < (current_date - INTERVAL '90' day) + THEN 'alarm' + WHEN access_key_2_active AND access_key_2_last_used_date < (current_date - INTERVAL '90' day) + THEN 'alarm' + ELSE 'ok' + END AS status, + user_name || + CASE + WHEN NOT password_enabled + THEN ' password not enabled,' + WHEN password_enabled AND password_last_used IS NULL + THEN ' password created ' || TO_CHAR(password_last_changed, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' password used ' || TO_CHAR(password_last_used, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_1_active + THEN ' key 1 not enabled,' + WHEN access_key_1_active AND access_key_1_last_used_date IS NULL + THEN ' key 1 created ' || TO_CHAR(access_key_1_last_rotated, 'DD-Mon-YYYY') || ' never used,' + ELSE + ' key 1 used ' || TO_CHAR(access_key_1_last_used_date, 'DD-Mon-YYYY') || ',' + END || + CASE + WHEN NOT access_key_2_active + THEN ' key 2 not enabled.' + WHEN access_key_2_active AND access_key_2_last_used_date IS NULL + THEN ' key 2 created ' || TO_CHAR(access_key_2_last_rotated, 'DD-Mon-YYYY') || ' never used.' + ELSE + ' key 2 used ' || TO_CHAR(access_key_2_last_used_date, 'DD-Mon-YYYY') || '.' + END AS reason, + account_id + FROM + aws_iam_credential_report; Severity: high Tags: category: @@ -80,12 +80,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -96,5 +96,4 @@ Tags: - AWS/IAM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: IAM user credentials that have not been used in 90 days should be disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_user_with_administrator_access_mfa_enabled.yaml b/compliance/controls/aws/aws_iam_user_with_administrator_access_mfa_enabled.yaml old mode 100755 new mode 100644 index d1b31971c..19df9570b --- a/compliance/controls/aws/aws_iam_user_with_administrator_access_mfa_enabled.yaml +++ b/compliance/controls/aws/aws_iam_user_with_administrator_access_mfa_enabled.yaml @@ -1,44 +1,44 @@ +Description: Manage access to resources in the AWS Cloud by ensuring MFA is enabled for users with administrative privileges. ID: aws_iam_user_with_administrator_access_mfa_enabled -Title: "IAM administrator users should have MFA enabled" -Description: "Manage access to resources in the AWS Cloud by ensuring MFA is enabled for users with administrative privileges." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with admin_users as ( - select + ListOfTables: + - aws_iam_user + Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + WITH admin_users AS ( + SELECT user_id, name, attachments - from + FROM aws_iam_user, - jsonb_array_elements_text(attached_policy_arns) as attachments - where + jsonb_array_elements_text(attached_policy_arns) AS attachments + WHERE split_part(attachments, '/', 2) = 'AdministratorAccess' ) - select - u.arn as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when au.user_id is null then 'skip' - when au.user_id is not null and u.mfa_enabled then 'ok' - else 'alarm' - end as status, - case - when au.user_id is null then u.name || ' does not have administrator access.' - when au.user_id is not null and u.mfa_enabled then u.name || ' has MFA token enabled.' - else u.name || ' has MFA token disabled.' - end as reason - from - aws_iam_user as u - left join admin_users au on u.user_id = au.user_id - order by + SELECT + u.arn AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN au.user_id IS NULL THEN 'skip' + WHEN au.user_id IS NOT NULL AND u.mfa_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN au.user_id IS NULL THEN u.name || ' does not have administrator access.' + WHEN au.user_id IS NOT NULL AND u.mfa_enabled THEN u.name || ' has MFA token enabled.' + ELSE u.name || ' has MFA token disabled.' + END AS reason + FROM + aws_iam_user AS u + LEFT JOIN admin_users au ON u.user_id = au.user_id + ORDER BY u.name; - PrimaryTable: aws_iam_user - ListOfTables: - - aws_iam_user - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM administrator users should have MFA enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_users_with_api_keys_should_have_keys_rotated_every_x_days.yaml b/compliance/controls/aws/aws_iam_users_with_api_keys_should_have_keys_rotated_every_x_days.yaml old mode 100755 new mode 100644 index ded7c386b..75fbbe12f --- a/compliance/controls/aws/aws_iam_users_with_api_keys_should_have_keys_rotated_every_x_days.yaml +++ b/compliance/controls/aws/aws_iam_users_with_api_keys_should_have_keys_rotated_every_x_days.yaml @@ -1,20 +1,52 @@ +Description: IAM Users with API Keys should have keys rotated every X days ID: aws_iam_users_with_api_keys_should_have_keys_rotated_every_x_days -Title: "IAM Users with API Keys should have keys rotated every X days" -Description: "IAM Users with API Keys should have keys rotated every X days" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n (date(current_timestamp) - date(access_key_1_last_rotated)),\n (date(current_timestamp) - date(access_key_2_last_rotated)),\n case\n when \n (access_key_1_active and\n (date(current_timestamp) - date(access_key_1_last_rotated)) > '{{.awsIamUserKeyRotateDays}}'::int) or\n (access_key_2_active and\n (date(current_timestamp) - date(access_key_2_last_rotated)) > '{{.awsIamUserKeyRotateDays}}'::int) then 'alarm'\n else 'ok'\n end as status,\n case\n when (access_key_1_active and\n (date(current_timestamp) - date(access_key_1_last_rotated)) > '{{.awsIamUserKeyRotateDays}}'::int) or\n (access_key_2_active and\n (date(current_timestamp) - date(access_key_2_last_rotated)) > '{{.awsIamUserKeyRotateDays}}'::int) then \n case\n when (access_key_1_last_rotated is null) then 'key last rotated in ' || (date(current_timestamp) - date(access_key_2_last_rotated)) || ' days'\n when (access_key_2_last_rotated is null) then 'key last rotated in ' || (date(current_timestamp) - date(access_key_1_last_rotated)) || ' days'\n else 'key last rotated in ' || greatest((date(current_timestamp) - date(access_key_1_last_rotated)), (date(current_timestamp) - date(access_key_2_last_rotated))) || ' days'\n end\n else 'keys rotated recently'\n end as reason\n , region, account_id\nfrom\n aws_iam_credential_report\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: - Key: awsIamUserKeyRotateDays Required: true + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + (DATE(current_timestamp) - DATE(access_key_1_last_rotated)), + (DATE(current_timestamp) - DATE(access_key_2_last_rotated)), + CASE + WHEN + (access_key_1_active AND + (DATE(current_timestamp) - DATE(access_key_1_last_rotated)) > '{{.awsIamUserKeyRotateDays}}'::int) OR + (access_key_2_active AND + (DATE(current_timestamp) - DATE(access_key_2_last_rotated)) > '{{.awsIamUserKeyRotateDays}}'::int) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (access_key_1_active AND + (DATE(current_timestamp) - DATE(access_key_1_last_rotated)) > '{{.awsIamUserKeyRotateDays}}'::int) OR + (access_key_2_active AND + (DATE(current_timestamp) - DATE(access_key_2_last_rotated)) > '{{.awsIamUserKeyRotateDays}}'::int) + THEN + CASE + WHEN (access_key_1_last_rotated IS NULL) THEN 'key last rotated in ' || (DATE(current_timestamp) - DATE(access_key_2_last_rotated)) || ' days' + WHEN (access_key_2_last_rotated IS NULL) THEN 'key last rotated in ' || (DATE(current_timestamp) - DATE(access_key_1_last_rotated)) || ' days' + ELSE 'key last rotated in ' || GREATEST((DATE(current_timestamp) - DATE(access_key_1_last_rotated)), (DATE(current_timestamp) - DATE(access_key_2_last_rotated))) || ' days' + END + ELSE 'keys rotated recently' + END AS reason, + region, + account_id + FROM + aws_iam_credential_report Severity: medium Tags: category: - Compliance score_service_name: - AWS Identity and Access Management (IAM) -IntegrationType: - - aws_cloud_account +Title: IAM Users with API Keys should have keys rotated every X days \ No newline at end of file diff --git a/compliance/controls/aws/aws_iam_users_with_console_access_are_requried_to_have_MFA.yaml b/compliance/controls/aws/aws_iam_users_with_console_access_are_requried_to_have_MFA.yaml old mode 100755 new mode 100644 index 7e50ba08b..3647d0221 --- a/compliance/controls/aws/aws_iam_users_with_console_access_are_requried_to_have_MFA.yaml +++ b/compliance/controls/aws/aws_iam_users_with_console_access_are_requried_to_have_MFA.yaml @@ -1,17 +1,36 @@ -ID: aws_iam_users_with_console_access_are_requried_to_have_MFA -Title: "IAM Users with Console Access are requried to have MFA" -Description: "IAM Users with Console Access are requried to have MFA" +Description: IAM Users with Console Access are required to have MFA +ID: aws_iam_users_with_console_access_are_required_to_have_MFA +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select \n user_arn as resource,\n case \n when not(mfa_active::bool) then 'alarm'\n else 'ok'\n end as status,\n case \n when not(mfa_active::bool) then 'MFA is not enabled for ' || user_name\n else user_name || ' has MFA'\n end as reason,\n u.og_resource_id,\n u.og_account_id,\n u.account_id\nfrom \n aws_iam_credential_report cr inner join aws_iam_user u on cr.user_arn = u.arn \nwhere \n not(login_profile ->> 'UserName' is null)\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_credential_report - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + user_arn AS resource, + CASE + WHEN NOT(mfa_active::bool) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT(mfa_active::bool) THEN 'MFA is not enabled for ' || user_name + ELSE user_name || ' has MFA' + END AS reason, + u.og_resource_id, + u.og_account_id, + u.account_id + FROM + aws_iam_credential_report cr + INNER JOIN aws_iam_user u + ON cr.user_arn = u.arn + WHERE + NOT(login_profile ->> 'UserName' IS NULL) Severity: low Tags: score_service_name: - AWS Identity and Access Management (IAM) -IntegrationType: - - aws_cloud_account +Title: IAM Users with Console Access are required to have MFA \ No newline at end of file diff --git a/compliance/controls/aws/aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled.yaml b/compliance/controls/aws/aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled.yaml old mode 100755 new mode 100644 index d6beb0ef9..8d9b98d77 --- a/compliance/controls/aws/aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled.yaml @@ -1,14 +1,28 @@ +Description: Enable server side encryption (SSE) of your Kinesis firehose delivery stream, in order to protect your data and metadata from breaches or unauthorized access, and fulfill compliance requirements for data-at-rest encryption within your organization. ID: aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled -Title: "Kinesis firehose delivery streams should have server side encryption enabled" -Description: "Enable server side encryption (SSE) of your Kinesis firehose delivery stream, in order to protect your data and metadata from breaches or unauthorized access, and fulfill compliance requirements for data-at-rest encryption within your organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when delivery_stream_encryption_configuration ->> 'Status' = 'ENABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when delivery_stream_encryption_configuration ->> 'Status' = 'ENABLED' then title || ' server side encryption enabled.'\n else title || ' server side encryption disabled.'\n end as reason\n \n \nfrom\n aws_kinesis_firehose_delivery_stream;" - PrimaryTable: aws_kinesis_firehose_delivery_stream ListOfTables: - aws_kinesis_firehose_delivery_stream Parameters: [] + PrimaryTable: aws_kinesis_firehose_delivery_stream + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN delivery_stream_encryption_configuration ->> 'Status' = 'ENABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN delivery_stream_encryption_configuration ->> 'Status' = 'ENABLED' THEN title || ' server side encryption enabled.' + ELSE title || ' server side encryption disabled.' + END AS reason + FROM + aws_kinesis_firehose_delivery_stream; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Kinesis firehose delivery streams should have server side encryption enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_kinesis_stream_encrypted_with_kms_cmk.yaml b/compliance/controls/aws/aws_kinesis_stream_encrypted_with_kms_cmk.yaml old mode 100755 new mode 100644 index fb04a7a69..b578307ff --- a/compliance/controls/aws/aws_kinesis_stream_encrypted_with_kms_cmk.yaml +++ b/compliance/controls/aws/aws_kinesis_stream_encrypted_with_kms_cmk.yaml @@ -1,14 +1,28 @@ +Description: Ensure Kinesis streams are encrypted using CMK. Using KMS CMK, you gain full control over who can use the keys to access AWS Kinesis data (including the system metadata). ID: aws_kinesis_stream_encrypted_with_kms_cmk -Title: "Kinesis streams should be encrypted with CMK" -Description: "Ensure Kinesis streams are encrypted using CMK. Using KMS CMK, you gain full control over who can use the keys to access AWS Kinesis data (including the system metadata)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n stream_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encryption_type = 'KMS' and key_id <> 'alias/aws/kinesis' then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption_type = 'KMS' and key_id <> 'alias/aws/kinesis' then title || ' encrypted with CMK.'\n else title || ' not encrypted with CMK.'\n end as reason\n \n \nfrom\n aws_kinesis_stream;" - PrimaryTable: aws_kinesis_stream ListOfTables: - aws_kinesis_stream Parameters: [] + PrimaryTable: aws_kinesis_stream + QueryToExecute: | + SELECT + stream_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'KMS' AND key_id <> 'alias/aws/kinesis' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'KMS' AND key_id <> 'alias/aws/kinesis' THEN title || ' encrypted with CMK.' + ELSE title || ' not encrypted with CMK.' + END AS reason + FROM + aws_kinesis_stream; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Kinesis streams should be encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/aws/aws_kinesis_stream_server_side_encryption_enabled.yaml b/compliance/controls/aws/aws_kinesis_stream_server_side_encryption_enabled.yaml old mode 100755 new mode 100644 index 704d5c170..29bf2e85f --- a/compliance/controls/aws/aws_kinesis_stream_server_side_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_kinesis_stream_server_side_encryption_enabled.yaml @@ -1,13 +1,30 @@ +Description: Enable server side encryption (SSE) of your AWS Kinesis Server data at rest, in order to protect your data and metadata from breaches or unauthorized access, and fulfill compliance requirements for data-at-rest encryption within your organization. ID: aws_kinesis_stream_server_side_encryption_enabled -Title: "Kinesis streams should have server side encryption enabled" -Description: "Enable server side encryption (SSE) of your AWS Kinesis Server data at rest, in order to protect your data and metadata from breaches or unauthorized access, and fulfill compliance requirements for data-at-rest encryption within your organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n stream_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encryption_type = 'KMS' then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption_type = 'KMS' then title || ' server side encryption enabled.'\n else title || ' server side encryption disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_kinesis_stream;\n" - PrimaryTable: aws_kinesis_stream ListOfTables: - aws_kinesis_stream Parameters: [] + PrimaryTable: aws_kinesis_stream + QueryToExecute: | + SELECT + stream_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'KMS' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'KMS' THEN title || ' server side encryption enabled.' + ELSE title || ' server side encryption disabled.' + END AS reason, + region, + account_id + FROM + aws_kinesis_stream; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/Kinesis -IntegrationType: - - aws_cloud_account +Title: Kinesis streams should have server side encryption enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_kms_cmk_policy_prohibit_public_access.yaml b/compliance/controls/aws/aws_kms_cmk_policy_prohibit_public_access.yaml old mode 100755 new mode 100644 index b38af63b2..97a032d90 --- a/compliance/controls/aws/aws_kms_cmk_policy_prohibit_public_access.yaml +++ b/compliance/controls/aws/aws_kms_cmk_policy_prohibit_public_access.yaml @@ -1,14 +1,48 @@ +Description: Manage access to resources in the AWS Cloud by ensuring AWS KMS CMK cannot be publicly accessed. ID: aws_kms_cmk_policy_prohibit_public_access -Title: "KMS CMK policies should prohibit public access" -Description: "Manage access to resources in the AWS Cloud by ensuring AWS KMS CMK cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with wildcard_action_policies as (\n select\n arn,\n count(*) as statements_num\n from\n aws_kms_key,\n jsonb_array_elements(policy_std -> 'Statement') as s\n where\n s ->> 'Effect' = 'Allow'\n and (\n ( s -> 'Principal' -> 'AWS') = '[\"*\"]'\n or s ->> 'Principal' = '*'\n )\n and key_manager = 'CUSTOMER'\n group by\n arn\n)\nselect\n k.arn as resource,\n k.og_account_id as og_account_id,\n k.og_resource_id as og_resource_id,\n case\n when p.arn is null then 'ok'\n else 'alarm'\n end status,\n case\n when p.arn is null then title || ' does not allow public access.'\n else title || ' contains ' || coalesce(p.statements_num, 0) ||\n ' statements that allow public access.'\n end as reason\n \n \nfrom\n aws_kms_key as k\n left join wildcard_action_policies as p on p.arn = k.arn\nwhere\n key_manager = 'CUSTOMER';" - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT + arn, + COUNT(*) AS statements_num + FROM + aws_kms_key, + jsonb_array_elements(policy_std -> 'Statement') AS s + WHERE + s ->> 'Effect' = 'Allow' + AND ( + (s -> 'Principal' -> 'AWS') = '[\"*\"]' + OR s ->> 'Principal' = '*' + ) + AND key_manager = 'CUSTOMER' + GROUP BY + arn + ) + SELECT + k.arn AS resource, + k.og_account_id AS og_account_id, + k.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' does not allow public access.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || ' statements that allow public access.' + END AS reason + FROM + aws_kms_key AS k + LEFT JOIN wildcard_action_policies AS p ON p.arn = k.arn + WHERE + key_manager = 'CUSTOMER'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: KMS CMK policies should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_kms_cmk_rotation_enabled.yaml b/compliance/controls/aws/aws_kms_cmk_rotation_enabled.yaml old mode 100755 new mode 100644 index 86983f253..b5984ab0c --- a/compliance/controls/aws/aws_kms_cmk_rotation_enabled.yaml +++ b/compliance/controls/aws/aws_kms_cmk_rotation_enabled.yaml @@ -1,13 +1,38 @@ +Description: Enable key rotation to ensure that keys are rotated once they have reached the end of their crypto period. ID: aws_kms_cmk_rotation_enabled -Title: "KMS CMK rotation should be enabled" -Description: "Enable key rotation to ensure that keys are rotated once they have reached the end of their crypto period." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when origin = 'EXTERNAL' then 'skip'\n when key_state = 'PendingDeletion' then 'skip'\n when key_state = 'Disabled' then 'skip'\n when not key_rotation_enabled then 'alarm'\n else 'ok'\n end as status,\n case\n when origin = 'EXTERNAL' then title || ' has imported key material.'\n when key_state = 'PendingDeletion' then title || ' is pending deletion.'\n when key_state = 'Disabled' then title || ' is disabled.'\n when not key_rotation_enabled then title || ' key rotation disabled.'\n else title || ' key rotation enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_kms_key\nwhere\n key_manager = 'CUSTOMER';\n" - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN origin = 'EXTERNAL' THEN 'skip' + WHEN key_state = 'PendingDeletion' THEN 'skip' + WHEN key_state = 'Disabled' THEN 'skip' + WHEN NOT key_rotation_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN origin = 'EXTERNAL' THEN title || ' has imported key material.' + WHEN key_state = 'PendingDeletion' THEN title || ' is pending deletion.' + WHEN key_state = 'Disabled' THEN title || ' is disabled.' + WHEN NOT key_rotation_enabled THEN title || ' key rotation disabled.' + ELSE title || ' key rotation enabled.' + END AS reason, + region, + account_id + FROM + aws_kms_key + WHERE + key_manager = 'CUSTOMER'; Severity: medium Tags: category: @@ -24,12 +49,12 @@ Tags: - "true" gxp_21_cfr_part_11: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -38,5 +63,4 @@ Tags: - "true" service: - AWS/KMS -IntegrationType: - - aws_cloud_account +Title: KMS CMK rotation should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_kms_cmk_unused.yaml b/compliance/controls/aws/aws_kms_cmk_unused.yaml old mode 100755 new mode 100644 index 86d21d929..6ae873cac --- a/compliance/controls/aws/aws_kms_cmk_unused.yaml +++ b/compliance/controls/aws/aws_kms_cmk_unused.yaml @@ -1,32 +1,32 @@ +Description: This control checks whether there are any unused CMK (Customer Master Key) KMS (Key Management Service) keys. ID: aws_kms_cmk_unused -Title: "KMS key should be in use" -Description: "This control checks whether there are any unused CMK (Customer Master Key) KMS (Key Management Service) keys." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not enabled and key_state = 'PendingDeletion' then 'ok' - when not enabled and key_state <> 'PendingDeletion' then 'alarm' - else 'ok' - end as status, - case - when not enabled and key_state = 'PendingDeletion' then title || ' scheduled for deletion in ' || extract(day from deletion_date - current_timestamp) || ' day(s).' - when not enabled and key_state <> 'PendingDeletion' then title || ' is unused.' - else title || ' is in use.' - end as reason - from - aws_kms_key - where - key_manager = 'CUSTOMER'; - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT enabled AND key_state = 'PendingDeletion' THEN 'ok' + WHEN NOT enabled AND key_state <> 'PendingDeletion' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT enabled AND key_state = 'PendingDeletion' THEN title || ' scheduled for deletion in ' || EXTRACT(DAY FROM deletion_date - CURRENT_TIMESTAMP) || ' day(s).' + WHEN NOT enabled AND key_state <> 'PendingDeletion' THEN title || ' is unused.' + ELSE title || ' is in use.' + END AS reason + FROM + aws_kms_key + WHERE + key_manager = 'CUSTOMER'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: KMS key should be in use \ No newline at end of file diff --git a/compliance/controls/aws/aws_kms_key_decryption_restricted_in_iam_customer_managed_policy.yaml b/compliance/controls/aws/aws_kms_key_decryption_restricted_in_iam_customer_managed_policy.yaml old mode 100755 new mode 100644 index e8beeb330..8641d21b5 --- a/compliance/controls/aws/aws_kms_key_decryption_restricted_in_iam_customer_managed_policy.yaml +++ b/compliance/controls/aws/aws_kms_key_decryption_restricted_in_iam_customer_managed_policy.yaml @@ -1,14 +1,46 @@ +Description: Checks whether the default version of IAM customer managed policies allow principals to use the AWS KMS decryption actions on all resources. This control uses Zelkova, an automated reasoning engine, to validate and warn you about policies that may grant broad access to your secrets across AWS accounts. This control fails if the kms:Decrypt or kms:ReEncryptFrom actions are allowed on all KMS keys. The control evaluates both attached and unattached customer managed policies. It does not check inline policies or AWS managed policies. ID: aws_kms_key_decryption_restricted_in_iam_customer_managed_policy -Title: "KMS key decryption should be restricted in IAM customer managed policy" -Description: "Checks whether the default version of IAM customer managed policies allow principals to use the AWS KMS decryption actions on all resources. This control uses Zelkova, an automated reasoning engine, to validate and warn you about policies that may grant broad access to your secrets across AWS accounts. This control fails if the kms:Decrypt or kms:ReEncryptFrom actions are allowed on all KMS keys. The control evaluates both attached and unattached customer managed policies. It does not check inline policies or AWS managed policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with policy_with_decrypt_grant as (\n select\n distinct arn\n from\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') as statement\n where\n not is_aws_managed\n and statement ->> 'Effect' = 'Allow'\n and statement -> 'Resource' ?| array['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*']\n and statement -> 'Action' ?| array['*', 'kms:*', 'kms:decrypt', 'kms:reencryptfrom', 'kms:reencrypt*']\n)\nselect\n i.arn as resource,\n i.og_account_id as og_account_id,\n i.og_resource_id as og_resource_id,\n case\n when d.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when d.arn is null then i.title || ' doesn''t allow decryption actions on all keys.'\n else i.title || ' allows decryption actions on all keys.'\n end as reason\n \n , i.account_id\nfrom\n aws_iam_policy i\nleft join policy_with_decrypt_grant d on i.arn = d.arn\nwhere\n not is_aws_managed;\n" - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_policy - aws_managed Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + WITH policy_with_decrypt_grant AS ( + SELECT + DISTINCT arn + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS statement + WHERE + NOT is_aws_managed + AND statement ->> 'Effect' = 'Allow' + AND statement -> 'Resource' ?| ARRAY['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] + AND statement -> 'Action' ?| ARRAY['*', 'kms:*', 'kms:decrypt', 'kms:reencryptfrom', 'kms:reencrypt*'] + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN d.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.arn IS NULL THEN i.title || ' doesn''t allow decryption actions on all keys.' + ELSE i.title || ' allows decryption actions on all keys.' + END AS reason, + i.account_id + FROM + aws_iam_policy i + LEFT JOIN policy_with_decrypt_grant d + ON i.arn = d.arn + WHERE + NOT is_aws_managed Severity: medium Tags: aws_foundational_security: @@ -23,5 +55,4 @@ Tags: - aws service: - AWS/KMS -IntegrationType: - - aws_cloud_account +Title: KMS key decryption should be restricted in IAM customer managed policy \ No newline at end of file diff --git a/compliance/controls/aws/aws_kms_key_decryption_restricted_in_iam_inline_policy.yaml b/compliance/controls/aws/aws_kms_key_decryption_restricted_in_iam_inline_policy.yaml old mode 100755 new mode 100644 index fe26002a2..e3528d1e3 --- a/compliance/controls/aws/aws_kms_key_decryption_restricted_in_iam_inline_policy.yaml +++ b/compliance/controls/aws/aws_kms_key_decryption_restricted_in_iam_inline_policy.yaml @@ -1,108 +1,107 @@ +Description: Checks whether the inline policies that are embedded in your IAM identities (role, user, or group) allow the AWS KMS decryption actions on all KMS keys. This control uses Zelkova, an automated reasoning engine, to validate and warn you about policies that may grant broad access to your secrets across AWS accounts. This control fails if kms:Decrypt or kms:ReEncryptFrom actions are allowed on all KMS keys in an inline policy. ID: aws_kms_key_decryption_restricted_in_iam_inline_policy -Title: "KMS key decryption should be restricted in IAM inline policy" -Description: "Checks whether the inline policies that are embedded in your IAM identities (role, user, or group) allow the AWS KMS decryption actions on all KMS keys. This control uses Zelkova, an automated reasoning engine, to validate and warn you about policies that may grant broad access to your secrets across AWS accounts. This control fails if kms:Decrypt or kms:ReEncryptFrom actions are allowed on all KMS keys in an inline policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_iam_group + - aws_iam_role + - aws_iam_user + Parameters: [] + PrimaryTable: "" QueryToExecute: | - with user_with_decrypt_grant as ( - select - distinct arn - from + WITH user_with_decrypt_grant AS ( + SELECT + DISTINCT arn + FROM aws_iam_user, - jsonb_array_elements(inline_policies_std) as inline_policy, - jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') as statement - where + jsonb_array_elements(inline_policies_std) AS inline_policy, + jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') AS statement + WHERE statement ->> 'Effect' = 'Allow' - and statement -> 'Resource' ?| array['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] - and statement -> 'Action' ?| array['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom'] + AND statement -> 'Resource' ?| ARRAY['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] + AND statement -> 'Action' ?| ARRAY['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom'] ), - role_with_decrypt_grant as ( - select - distinct arn - from + role_with_decrypt_grant AS ( + SELECT + DISTINCT arn + FROM aws_iam_role, - jsonb_array_elements(inline_policies_std) as inline_policy, - jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') as statement - where + jsonb_array_elements(inline_policies_std) AS inline_policy, + jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') AS statement + WHERE statement ->> 'Effect' = 'Allow' - and statement -> 'Resource' ?| array['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] - and statement -> 'Action' ?| array['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom'] + AND statement -> 'Resource' ?| ARRAY['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] + AND statement -> 'Action' ?| ARRAY['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom'] ), - group_with_decrypt_grant as ( - select - distinct arn - from + group_with_decrypt_grant AS ( + SELECT + DISTINCT arn + FROM aws_iam_group, - jsonb_array_elements(inline_policies_std) as inline_policy, - jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') as statement - where + jsonb_array_elements(inline_policies_std) AS inline_policy, + jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') AS statement + WHERE statement ->> 'Effect' = 'Allow' - and statement -> 'Resource' ?| array['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] - and statement -> 'Action' ?| array['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom'] + AND statement -> 'Resource' ?| ARRAY['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] + AND statement -> 'Action' ?| ARRAY['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom'] ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - 'aws_iam_user' as og_table_name, - case - when d.arn is null then 'ok' - else 'alarm' - end as status, - case - when d.arn is null then 'User ' || i.title || ' not allowed to perform decryption actions on all keys.' - else 'User ' || i.title || ' allowed to perform decryption actions on all keys.' - end as reason - - , i.account_id - from + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + 'aws_iam_user' AS og_table_name, + CASE + WHEN d.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.arn IS NULL THEN 'User ' || i.title || ' not allowed to perform decryption actions on all keys.' + ELSE 'User ' || i.title || ' allowed to perform decryption actions on all keys.' + END AS reason, + i.account_id + FROM aws_iam_user i - left join user_with_decrypt_grant d on i.arn = d.arn - union - select - r.arn as resource, - r.og_account_id as og_account_id, - r.og_resource_id as og_resource_id, - 'aws_iam_role' as og_table_name, - case - when d.arn is null then 'ok' - else 'alarm' - end as status, - case - when d.arn is null then 'Role ' || r.title || ' not allowed to perform decryption actions on all keys.' - else 'Role ' || r.title || ' allowed to perform decryption actions on all keys.' - end as reason - - , r.account_id - from + LEFT JOIN user_with_decrypt_grant d ON i.arn = d.arn + UNION + SELECT + r.arn AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + 'aws_iam_role' AS og_table_name, + CASE + WHEN d.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.arn IS NULL THEN 'Role ' || r.title || ' not allowed to perform decryption actions on all keys.' + ELSE 'Role ' || r.title || ' allowed to perform decryption actions on all keys.' + END AS reason, + r.account_id + FROM aws_iam_role r - left join role_with_decrypt_grant d on r.arn = d.arn - where - r.arn not like '%service-role/%' - union - select - g.arn as resource, - g.og_account_id as og_account_id, - g.og_resource_id as og_resource_id, - 'aws_iam_group' as og_table_name, - case - when d.arn is null then 'ok' - else 'alarm' - end as status, - case - when d.arn is null then 'Role ' || g.title || ' not allowed to perform decryption actions on all keys.' - else 'Group ' || g.title || ' allowed to perform decryption actions on all keys.' - end as reason - , g.account_id - from + LEFT JOIN role_with_decrypt_grant d ON r.arn = d.arn + WHERE + r.arn NOT LIKE '%service-role/%' + UNION + SELECT + g.arn AS resource, + g.og_account_id AS og_account_id, + g.og_resource_id AS og_resource_id, + 'aws_iam_group' AS og_table_name, + CASE + WHEN d.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.arn IS NULL THEN 'Group ' || g.title || ' not allowed to perform decryption actions on all keys.' + ELSE 'Group ' || g.title || ' allowed to perform decryption actions on all keys.' + END AS reason, + g.account_id + FROM aws_iam_group g - left join group_with_decrypt_grant d on g.arn = d.arn; - PrimaryTable: "" - ListOfTables: - - aws_iam_group - - aws_iam_role - - aws_iam_user - Parameters: [] + LEFT JOIN group_with_decrypt_grant d ON g.arn = d.arn; Severity: medium Tags: aws_foundational_security: @@ -117,5 +116,4 @@ Tags: - aws service: - AWS/KMS -IntegrationType: - - aws_cloud_account +Title: KMS key decryption should be restricted in IAM inline policy \ No newline at end of file diff --git a/compliance/controls/aws/aws_kms_key_not_pending_deletion.yaml b/compliance/controls/aws/aws_kms_key_not_pending_deletion.yaml old mode 100755 new mode 100644 index 0776c2582..4317ae342 --- a/compliance/controls/aws/aws_kms_key_not_pending_deletion.yaml +++ b/compliance/controls/aws/aws_kms_key_not_pending_deletion.yaml @@ -1,13 +1,32 @@ +Description: To help protect data at rest, ensure necessary customer master keys (CMKs) are not scheduled for deletion in AWS Key Management Service (AWS KMS). ID: aws_kms_key_not_pending_deletion -Title: "KMS keys should not be pending deletion" -Description: "To help protect data at rest, ensure necessary customer master keys (CMKs) are not scheduled for deletion in AWS Key Management Service (AWS KMS)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when key_state = 'PendingDeletion' then 'alarm'\n else 'ok'\n end as status,\n case\n when key_state = 'PendingDeletion' then title || ' scheduled for deletion and will be deleted in ' || extract(day from deletion_date - current_timestamp) || ' day(s).'\n else title || ' not scheduled for deletion.'\n end as reason\n \n , region, account_id\nfrom\n aws_kms_key\nwhere\n key_manager = 'CUSTOMER';\n" - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: [] + PrimaryTable: aws_kms_key + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN key_state = 'PendingDeletion' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN key_state = 'PendingDeletion' THEN title || ' scheduled for deletion and will be deleted in ' || EXTRACT(day FROM deletion_date - current_timestamp) || ' day(s).' + ELSE title || ' not scheduled for deletion.' + END AS reason, + region, + account_id + FROM + aws_kms_key + WHERE + key_manager = 'CUSTOMER'; Severity: high Tags: category: @@ -24,12 +43,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -40,5 +59,4 @@ Tags: - AWS/KMS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: KMS keys should not be pending deletion \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_cloudtrail_logging_enabled.yaml b/compliance/controls/aws/aws_lambda_function_cloudtrail_logging_enabled.yaml old mode 100755 new mode 100644 index 868c3c466..aaa72fadd --- a/compliance/controls/aws/aws_lambda_function_cloudtrail_logging_enabled.yaml +++ b/compliance/controls/aws/aws_lambda_function_cloudtrail_logging_enabled.yaml @@ -1,78 +1,77 @@ +Description: Lambda functions logging is essential because once lambdas are triggered, all of the underlying compute resources are automatically managed for you. This control is compliant if CloudTrail logging is enabled. ID: aws_lambda_function_cloudtrail_logging_enabled -Title: "Lambda functions CloudTrail logging should be enabled" -Description: "Lambda functions logging is essential because once lambdas are triggered, all of the underlying compute resources are automatically managed for you. This control is compliant if CloudTrail logging is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with function_logging_cloudtrails as ( - select - distinct replace(replace(v::text,'"',''),'/','') as lambda_arn, - d ->> 'Type' as type - from + ListOfTables: + - aws_cloudtrail_trail + - aws_lambda_function + Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + WITH function_logging_cloudtrails AS ( + SELECT + DISTINCT replace(replace(v::text, '"', ''), '/', '') AS lambda_arn, + d ->> 'Type' AS type + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) e, + jsonb_array_elements(e -> 'DataResources') AS d, + jsonb_array_elements(d -> 'Values') v + WHERE + d ->> 'Type' = 'AWS::Lambda::Function' + AND replace(replace(v::text, '"', ''), '/', '') <> 'arn:aws:lambda' + ), function_logging_region AS ( + SELECT + region AS cloudtrail_region, + replace(replace(v::text, '"', ''), '/', '') AS lambda_arn + FROM aws_cloudtrail_trail, jsonb_array_elements(event_selectors) e, - jsonb_array_elements(e -> 'DataResources') as d, + jsonb_array_elements(e -> 'DataResources') AS d, jsonb_array_elements(d -> 'Values') v - where + WHERE d ->> 'Type' = 'AWS::Lambda::Function' - and replace(replace(v::text,'"',''),'/','') <> 'arn:aws:lambda' - ), function_logging_region as ( - select - region as cloudtrail_region, - replace(replace(v::text,'"',''),'/','') as lambda_arn - from - aws_cloudtrail_trail, - jsonb_array_elements(event_selectors) e, - jsonb_array_elements(e -> 'DataResources') as d, - jsonb_array_elements(d -> 'Values') v - where - d ->> 'Type' = 'AWS::Lambda::Function' - and replace(replace(v::text,'"',''),'/', '') = 'arn:aws:lambda' - group by - region, - lambda_arn - ), - function_logging_region_advance_es as ( - select - region as cloudtrail_region - from + AND replace(replace(v::text, '"', ''), '/', '') = 'arn:aws:lambda' + GROUP BY + region, + lambda_arn + ), function_logging_region_advance_es AS ( + SELECT + region AS cloudtrail_region + FROM aws_cloudtrail_trail, jsonb_array_elements(advanced_event_selectors) a, - jsonb_array_elements(a -> 'FieldSelectors') as f, + jsonb_array_elements(a -> 'FieldSelectors') AS f, jsonb_array_elements_text(f -> 'Equals') e - where + WHERE e = 'AWS::Lambda::Function' - and f ->> 'Field' != 'eventCategory' - group by + AND f ->> 'Field' != 'eventCategory' + GROUP BY region ) - select - distinct l.arn as resource, - l.og_account_id as og_account_id, - l.og_resource_id as og_resource_id, - case - when (l.arn = c.lambda_arn) - or (r.lambda_arn = 'arn:aws:lambda' and r.cloudtrail_region = l.region ) - or a.cloudtrail_region = l.region then 'ok' - else 'alarm' - end as status, - case - when (l.arn = c.lambda_arn) - or (r.lambda_arn = 'arn:aws:s3' and r.cloudtrail_region = l.region ) - or a.cloudtrail_region = l.region then l.name || ' logging enabled.' - else l.name || ' logging not enabled.' - end as reason - from - aws_lambda_function as l - left join function_logging_cloudtrails as c on l.arn = c.lambda_arn - left join function_logging_region as r on r.cloudtrail_region = l.region - left join function_logging_region_advance_es as a on a.cloudtrail_region = l.region; - PrimaryTable: aws_lambda_function - ListOfTables: - - aws_cloudtrail_trail - - aws_lambda_function - Parameters: [] + SELECT + DISTINCT l.arn AS resource, + l.og_account_id AS og_account_id, + l.og_resource_id AS og_resource_id, + CASE + WHEN (l.arn = c.lambda_arn) + OR (r.lambda_arn = 'arn:aws:lambda' AND r.cloudtrail_region = l.region) + OR a.cloudtrail_region = l.region THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (l.arn = c.lambda_arn) + OR (r.lambda_arn = 'arn:aws:s3' AND r.cloudtrail_region = l.region) + OR a.cloudtrail_region = l.region THEN l.name || ' logging enabled.' + ELSE l.name || ' logging not enabled.' + END AS reason + FROM + aws_lambda_function AS l + LEFT JOIN function_logging_cloudtrails AS c ON l.arn = c.lambda_arn + LEFT JOIN function_logging_region AS r ON r.cloudtrail_region = l.region + LEFT JOIN function_logging_region_advance_es AS a ON a.cloudtrail_region = l.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Lambda functions CloudTrail logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_cloudwatch_insights_enabled.yaml b/compliance/controls/aws/aws_lambda_function_cloudwatch_insights_enabled.yaml old mode 100755 new mode 100644 index d9dda8e26..c9c43450c --- a/compliance/controls/aws/aws_lambda_function_cloudwatch_insights_enabled.yaml +++ b/compliance/controls/aws/aws_lambda_function_cloudwatch_insights_enabled.yaml @@ -1,14 +1,36 @@ +Description: Ensure that Amazon CloudWatch Lambda Insights is enabled for your Amazon Lambda functions for enhanced monitoring. ID: aws_lambda_function_cloudwatch_insights_enabled -Title: "Ensure Cloudwatch Lambda insights is enabled" -Description: "Ensure that Amazon CloudWatch Lambda Insights is enabled for your Amazon Lambda functions for enhanced monitoring." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when exists (\n select 1\n from jsonb_array_elements(layers) as l\n where l ->> 'Arn' like '%:layer:LambdaInsightsExtension:%'\n ) then 'ok'\n else 'alarm'\n end as status,\n case\n when exists (\n select 1\n from jsonb_array_elements(layers) as l\n where l ->> 'Arn' like '%:layer:LambdaInsightsExtension:%'\n ) then title || ' CloudWatch Insights enabled.'\n else title || ' CloudWatch Insights disabled.'\n end as reason\n \n \nfrom\n aws_lambda_function;" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(layers) AS l + WHERE l ->> 'Arn' LIKE '%:layer:LambdaInsightsExtension:%' + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(layers) AS l + WHERE l ->> 'Arn' LIKE '%:layer:LambdaInsightsExtension:%' + ) THEN title || ' CloudWatch Insights enabled.' + ELSE title || ' CloudWatch Insights disabled.' + END AS reason + FROM + aws_lambda_function; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure Cloudwatch Lambda insights is enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_concurrent_execution_limit_configured.yaml b/compliance/controls/aws/aws_lambda_function_concurrent_execution_limit_configured.yaml old mode 100755 new mode 100644 index e93380411..dae225d52 --- a/compliance/controls/aws/aws_lambda_function_concurrent_execution_limit_configured.yaml +++ b/compliance/controls/aws/aws_lambda_function_concurrent_execution_limit_configured.yaml @@ -1,13 +1,30 @@ +Description: Checks whether the AWS Lambda function is configured with function-level concurrent execution limit. The control is non-compliant if the Lambda function is not configured with function-level concurrent execution limit. ID: aws_lambda_function_concurrent_execution_limit_configured -Title: "Lambda functions concurrent execution limit configured" -Description: "Checks whether the AWS Lambda function is configured with function-level concurrent execution limit. The control is non-compliant if the Lambda function is not configured with function-level concurrent execution limit." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when reserved_concurrent_executions is null then 'alarm'\n else 'ok'\n end as status,\n case\n when reserved_concurrent_executions is null then title || ' function-level concurrent execution limit not configured.'\n else title || ' function-level concurrent execution limit configured.'\n end as reason\n \n , region, account_id\nfrom\n aws_lambda_function;\n" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN reserved_concurrent_executions IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN reserved_concurrent_executions IS NULL THEN title || ' function-level concurrent execution limit not configured.' + ELSE title || ' function-level concurrent execution limit configured.' + END AS reason, + region, + account_id + FROM + aws_lambda_function; Severity: medium Tags: category: @@ -20,10 +37,10 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -32,5 +49,4 @@ Tags: - AWS/Lambda soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Lambda functions concurrent execution limit configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_cors_configuration.yaml b/compliance/controls/aws/aws_lambda_function_cors_configuration.yaml old mode 100755 new mode 100644 index 36bccde9d..3124b9b2e --- a/compliance/controls/aws/aws_lambda_function_cors_configuration.yaml +++ b/compliance/controls/aws/aws_lambda_function_cors_configuration.yaml @@ -1,14 +1,30 @@ +Description: Enable this rule to ensure that the CORS configuration for your Lambda functions does not allow all origins. ID: aws_lambda_function_cors_configuration -Title: "Lambda functions CORS configuration should not allow all origins" -Description: "Enable this rule to ensure that the CORS configuration for your Lambda functions does not allow all origins." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when url_config is null then 'info'\n when url_config -> 'Cors' ->> 'AllowOrigins' = '[\"*\"]' then 'alarm'\n else 'ok'\n end as status,\n case\n when url_config is null then title || ' does not has a URL config.'\n when url_config -> 'Cors' ->> 'AllowOrigins' = '[\"*\"]' then title || ' CORS configuration allows all origins.'\n else title || ' CORS configuration does not allow all origins.'\n end as reason\n \n \nfrom\n aws_lambda_function;" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN url_config IS NULL THEN 'info' + WHEN url_config -> 'Cors' ->> 'AllowOrigins' = '[\"*\"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN url_config IS NULL THEN title || ' does not have a URL config.' + WHEN url_config -> 'Cors' ->> 'AllowOrigins' = '[\"*\"]' THEN title || ' CORS configuration allows all origins.' + ELSE title || ' CORS configuration does not allow all origins.' + END AS reason + FROM + aws_lambda_function; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Lambda functions CORS configuration should not allow all origins \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_dead_letter_queue_configured.yaml b/compliance/controls/aws/aws_lambda_function_dead_letter_queue_configured.yaml old mode 100755 new mode 100644 index 241473c3c..26e74b6ee --- a/compliance/controls/aws/aws_lambda_function_dead_letter_queue_configured.yaml +++ b/compliance/controls/aws/aws_lambda_function_dead_letter_queue_configured.yaml @@ -1,13 +1,30 @@ +Description: Enable this rule to help notify the appropriate personnel through AWS Simple Queue Service (AWS SQS) or AWS Simple Notification Service (AWS SNS) when a function has failed. ID: aws_lambda_function_dead_letter_queue_configured -Title: "Lambda functions should be configured with a dead-letter queue" -Description: "Enable this rule to help notify the appropriate personnel through AWS Simple Queue Service (AWS SQS) or AWS Simple Notification Service (AWS SNS) when a function has failed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when dead_letter_config_target_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when dead_letter_config_target_arn is null then title || ' configured with dead-letter queue.'\n else title || ' not configured with dead-letter queue.'\n end as reason\n \n , region, account_id\nfrom\n aws_lambda_function;\n" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN dead_letter_config_target_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN dead_letter_config_target_arn IS NULL THEN title || ' configured with dead-letter queue.' + ELSE title || ' not configured with dead-letter queue.' + END AS reason, + region, + account_id + FROM + aws_lambda_function; Severity: medium Tags: category: @@ -22,10 +39,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -34,5 +51,4 @@ Tags: - AWS/Lambda soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Lambda functions should be configured with a dead-letter queue \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_encryption_enabled.yaml b/compliance/controls/aws/aws_lambda_function_encryption_enabled.yaml old mode 100755 new mode 100644 index e89da06a5..e398c06db --- a/compliance/controls/aws/aws_lambda_function_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_lambda_function_encryption_enabled.yaml @@ -1,28 +1,28 @@ +Description: As you can set your own environmental variables for Lambda it is important to also encrypt them for in transit protection. ID: aws_lambda_function_encryption_enabled -Title: "Ensure encryption in transit is enabled for Lambda environment variables" -Description: "As you can set your own environmental variables for Lambda it is important to also encrypt them for in transit protection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when kms_key_arn is null then 'alarm' - else 'ok' - end as status, - case - when kms_key_arn is null then title || ' encryption is disabled.' - else title || ' encryption is enabled.' - end as reason - from - aws_lambda_function; - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_arn IS NULL THEN title || ' encryption is disabled.' + ELSE title || ' encryption is enabled.' + END AS reason + FROM + aws_lambda_function; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure encryption in transit is enabled for Lambda environment variables \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_in_vpc.yaml b/compliance/controls/aws/aws_lambda_function_in_vpc.yaml old mode 100755 new mode 100644 index d338c02c0..3e8d198e9 --- a/compliance/controls/aws/aws_lambda_function_in_vpc.yaml +++ b/compliance/controls/aws/aws_lambda_function_in_vpc.yaml @@ -1,13 +1,30 @@ +Description: Deploy AWS Lambda functions within an AWS Virtual Private Cloud (AWS VPC) for a secure communication between a function and other services within the AWS VPC. ID: aws_lambda_function_in_vpc -Title: "Lambda functions should be in a VPC" -Description: "Deploy AWS Lambda functions within an AWS Virtual Private Cloud (AWS VPC) for a secure communication between a function and other services within the AWS VPC." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when vpc_id is null or vpc_id = '' then 'alarm'\n else 'ok'\n end status,\n case\n when vpc_id is null or vpc_id = '' then title || ' is not in VPC.'\n else title || ' is in VPC ' || vpc_id || '.'\n end reason\n \n , region, account_id\nfrom\n aws_lambda_function;\n" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_id IS NULL OR vpc_id = '' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vpc_id IS NULL OR vpc_id = '' THEN title || ' is not in VPC.' + ELSE title || ' is in VPC ' || vpc_id || '.' + END AS reason, + region, + account_id + FROM + aws_lambda_function; Severity: medium Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/Lambda soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Lambda functions should be in a VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_multiple_az_configured.yaml b/compliance/controls/aws/aws_lambda_function_multiple_az_configured.yaml old mode 100755 new mode 100644 index f6252d09a..8ccf22981 --- a/compliance/controls/aws/aws_lambda_function_multiple_az_configured.yaml +++ b/compliance/controls/aws/aws_lambda_function_multiple_az_configured.yaml @@ -1,14 +1,42 @@ +Description: This control checks if Lambda has more than one availability zone associated. The rule fails if only one availability zone is associated with Lambda. ID: aws_lambda_function_multiple_az_configured -Title: "Lambda functions should operate in more than one availability zone" -Description: "This control checks if Lambda has more than one availability zone associated. The rule fails if only one availability zone is associated with Lambda." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when vpc_id is null or vpc_id = '' then 'skip'\n else case\n when\n (\n select\n count(distinct availability_zone_id)\n from\n aws_vpc_subnet\n where\n subnet_id in (select jsonb_array_elements_text(vpc_subnet_ids) )\n ) >= 2\n then 'ok'\n else 'alarm'\n end\n end as status,\n case\n when vpc_id is null or vpc_id = '' then title || ' is not in VPC.'\n else title || ' has ' || jsonb_array_length(vpc_subnet_ids) || ' availability zone(s).'\n end as reason\n \n , region, account_id\nfrom\n aws_lambda_function;\n" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function - aws_vpc_subnet Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_id IS NULL OR vpc_id = '' THEN 'skip' + ELSE CASE + WHEN ( + SELECT + COUNT(DISTINCT availability_zone_id) + FROM + aws_vpc_subnet + WHERE + subnet_id IN (SELECT jsonb_array_elements_text(vpc_subnet_ids)) + ) >= 2 + THEN 'ok' + ELSE 'alarm' + END + END AS status, + CASE + WHEN vpc_id IS NULL OR vpc_id = '' THEN title || ' is not in VPC.' + ELSE title || ' has ' || jsonb_array_length(vpc_subnet_ids) || ' availability zone(s).' + END AS reason, + region, + account_id + FROM + aws_lambda_function; Severity: medium Tags: aws_foundational_security: @@ -23,5 +51,4 @@ Tags: - aws service: - AWS/Lambda -IntegrationType: - - aws_cloud_account +Title: Lambda functions should operate in more than one availability zone \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_restrict_public_access.yaml b/compliance/controls/aws/aws_lambda_function_restrict_public_access.yaml old mode 100755 new mode 100644 index 0e10c58c7..0759f3c5e --- a/compliance/controls/aws/aws_lambda_function_restrict_public_access.yaml +++ b/compliance/controls/aws/aws_lambda_function_restrict_public_access.yaml @@ -1,13 +1,54 @@ +Description: Manage access to resources in the AWS Cloud by ensuring AWS Lambda functions cannot be publicly accessed. ID: aws_lambda_function_restrict_public_access -Title: "Lambda functions should restrict public access" -Description: "Manage access to resources in the AWS Cloud by ensuring AWS Lambda functions cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with wildcard_action_policies as (\n select\n arn,\n count(*) as statements_num\n from\n aws_lambda_function,\n jsonb_array_elements(\n case jsonb_typeof(policy_std -> 'Statement') \n when 'array' \n then policy_std -> 'Statement' \n else '[]' \n end\n ) as s\n where\n s ->> 'Effect' = 'Allow'\n and (\n ( s -> 'Principal' -> 'AWS') = '[\"*\"]'\n or s ->> 'Principal' = '*'\n )\n group by\n arn\n)\nselect\n f.arn as resource,\n f.og_account_id as og_account_id,\n f.og_resource_id as og_resource_id,\n case\n when p.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when p.arn is null then title || ' does not allow public access.'\n else title || ' contains ' || coalesce(p.statements_num,0) ||\n ' statements that allows public access.'\n end as reason\n \n , f.region, f.account_id\nfrom\n aws_lambda_function as f\n left join wildcard_action_policies as p on p.arn = f.arn;\n" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT + arn, + COUNT(*) AS statements_num + FROM + aws_lambda_function, + jsonb_array_elements( + CASE jsonb_typeof(policy_std -> 'Statement') + WHEN 'array' + THEN policy_std -> 'Statement' + ELSE '[]' + END + ) AS s + WHERE + s ->> 'Effect' = 'Allow' + AND ( + (s -> 'Principal' -> 'AWS') = '[\"*\"]' + OR s ->> 'Principal' = '*' + ) + GROUP BY + arn + ) + SELECT + f.arn AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' does not allow public access.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || ' statements that allows public access.' + END AS reason, + f.region, + f.account_id + FROM + aws_lambda_function AS f + LEFT JOIN wildcard_action_policies AS p + ON p.arn = f.arn Severity: high Tags: category: @@ -28,12 +69,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +87,4 @@ Tags: - AWS/Lambda soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Lambda functions should restrict public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_restrict_public_url.yaml b/compliance/controls/aws/aws_lambda_function_restrict_public_url.yaml old mode 100755 new mode 100644 index a774c22e9..8f1f6c530 --- a/compliance/controls/aws/aws_lambda_function_restrict_public_url.yaml +++ b/compliance/controls/aws/aws_lambda_function_restrict_public_url.yaml @@ -1,14 +1,30 @@ +Description: This control verifies that the Lambda function does not have a publicly accessible URL. Exposing services publicly could potentially make sensitive data accessible to malicious actors. ID: aws_lambda_function_restrict_public_url -Title: "Lambda functions should restrict public URL" -Description: "This control verifies that the Lambda function does not have a publicly accessible URL. Exposing services publicly could potentially make sensitive data accessible to malicious actors." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when url_config is null then 'info'\n when url_config ->> 'AuthType' = 'AWS_IAM' then 'ok'\n else 'alarm'\n end as status,\n case\n when url_config is null then title || ' having no URL config.'\n when url_config ->> 'AuthType' = 'AWS_IAM' then title || ' restricts public function URL.'\n else title || ' public function URL configured.'\n end as reason\n \n \nfrom\n aws_lambda_function;" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN url_config IS NULL THEN 'info' + WHEN url_config ->> 'AuthType' = 'AWS_IAM' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN url_config IS NULL THEN title || ' having no URL config.' + WHEN url_config ->> 'AuthType' = 'AWS_IAM' THEN title || ' restricts public function URL.' + ELSE title || ' public function URL configured.' + END AS reason + FROM + aws_lambda_function; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Lambda functions should restrict public URL \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_tracing_enabled.yaml b/compliance/controls/aws/aws_lambda_function_tracing_enabled.yaml old mode 100755 new mode 100644 index c1e83958c..28cd0b4d4 --- a/compliance/controls/aws/aws_lambda_function_tracing_enabled.yaml +++ b/compliance/controls/aws/aws_lambda_function_tracing_enabled.yaml @@ -1,28 +1,28 @@ +Description: AWS X-Ray can be used to visualize the components of application, identify performance bottlenecks, and troubleshoot requests that resulted in an error. Lambda functions send trace data to X-Ray, and X-Ray processes the data to generate a service map and searchable trace summaries. ID: aws_lambda_function_tracing_enabled -Title: "Lambda functions tracing should be enabled" -Description: "AWS X-Ray can be used to visualize the components of application, identify performance bottlenecks, and troubleshoot requests that resulted in an error. Lambda functions send trace data to X-Ray, and X-Ray processes the data to generate a service map and searchable trace summaries." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when tracing_config ->> 'Mode' = 'PassThrough' then 'alarm' - else 'ok' - end as status, - case - when tracing_config ->> 'Mode' = 'PassThrough' then title || ' has tracing disabled.' - else title || ' has tracing enabled.' - end as reason - from - aws_lambda_function; - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN tracing_config ->> 'Mode' = 'PassThrough' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN tracing_config ->> 'Mode' = 'PassThrough' THEN title || ' has tracing disabled.' + ELSE title || ' has tracing enabled.' + END AS reason + FROM + aws_lambda_function; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Lambda functions tracing should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_use_latest_runtime.yaml b/compliance/controls/aws/aws_lambda_function_use_latest_runtime.yaml old mode 100755 new mode 100644 index 3ff8fb04c..8fcea6d28 --- a/compliance/controls/aws/aws_lambda_function_use_latest_runtime.yaml +++ b/compliance/controls/aws/aws_lambda_function_use_latest_runtime.yaml @@ -1,13 +1,32 @@ +Description: 'This control checks that the Lambda function settings for runtimes match the expected values set for the latest runtimes for each supported language. This control checks for the following runtimes: nodejs20.x, nodejs18.x, nodejs16.x, python3.12, python3.11, python3.10, python3.9, python3.8, ruby3.3, ruby3.2, java21, java17, java11, java8.al2, dotnet8, dotnet6' ID: aws_lambda_function_use_latest_runtime -Title: "Lambda functions should use latest runtimes" -Description: "This control checks that the Lambda function settings for runtimes match the expected values set for the latest runtimes for each supported language. This control checks for the following runtimes: nodejs20.x, nodejs18.x, nodejs16.x, python3.12, python3.11, python3.10, python3.9, python3.8, ruby3.3, ruby3.2, java21, java17, java11, java8.al2, dotnet8, dotnet6" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when package_type <> 'Zip' then 'skip'\n when runtime in ('nodejs16.x', 'nodejs14.x', 'nodejs12.x', 'nodejs10.x', 'python3.9', 'python3.8', 'python3.7', 'python3.6', 'ruby2.5', 'ruby2.7', 'java11', 'java8', 'java8.al2', 'go1.x', 'dotnetcore2.1', 'dotnetcore3.1', 'dotnet6') then 'ok'\n else 'alarm'\n end as status,\n case\n when package_type <> 'Zip' then title || ' package type is ' || package_type || '.'\n when runtime in ('nodejs16.x', 'nodejs14.x', 'nodejs12.x', 'nodejs10.x', 'python3.9', 'python3.8', 'python3.7', 'python3.6', 'ruby2.5', 'ruby2.7', 'java11', 'java8', 'java8.al2', 'go1.x', 'dotnetcore2.1', 'dotnetcore3.1', 'dotnet6') then title || ' uses latest runtime - ' || runtime || '.'\n else title || ' uses ' || runtime || ' which is not the latest version.'\n end as reason\n \n , region, account_id\nfrom\n aws_lambda_function;\n" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN package_type <> 'Zip' THEN 'skip' + WHEN runtime IN ('nodejs16.x', 'nodejs14.x', 'nodejs12.x', 'nodejs10.x', 'python3.9', 'python3.8', 'python3.7', 'python3.6', 'ruby2.5', 'ruby2.7', 'java11', 'java8', 'java8.al2', 'go1.x', 'dotnetcore2.1', 'dotnetcore3.1', 'dotnet6') THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN package_type <> 'Zip' THEN title || ' package type is ' || package_type || '.' + WHEN runtime IN ('nodejs16.x', 'nodejs14.x', 'nodejs12.x', 'nodejs10.x', 'python3.9', 'python3.8', 'python3.7', 'python3.6', 'ruby2.5', 'ruby2.7', 'java11', 'java8', 'java8.al2', 'go1.x', 'dotnetcore2.1', 'dotnetcore3.1', 'dotnet6') THEN title || ' uses latest runtime - ' || runtime || '.' + ELSE title || ' uses ' || runtime || ' which is not the latest version.' + END AS reason, + region, + account_id + FROM + aws_lambda_function; Severity: medium Tags: aws_foundational_security: @@ -22,5 +41,4 @@ Tags: - aws service: - AWS/Lambda -IntegrationType: - - aws_cloud_account +Title: Lambda functions should use latest runtimes \ No newline at end of file diff --git a/compliance/controls/aws/aws_lambda_function_variables_no_sensitive_data.yaml b/compliance/controls/aws/aws_lambda_function_variables_no_sensitive_data.yaml old mode 100755 new mode 100644 index 23d34bec1..41f78ac3b --- a/compliance/controls/aws/aws_lambda_function_variables_no_sensitive_data.yaml +++ b/compliance/controls/aws/aws_lambda_function_variables_no_sensitive_data.yaml @@ -1,14 +1,42 @@ +Description: Ensure functions environment variables is not having any sensitive data. Leveraging Secrets Manager enables secure provisioning of database credentials to Lambda functions while also ensuring the security of databases. This approach eliminates the need to hardcode secrets in code or pass them through environmental variables. Additionally, Secrets Manager facilitates the secure retrieval of credentials for establishing connections to databases and performing queries, enhancing overall security measures. ID: aws_lambda_function_variables_no_sensitive_data -Title: "Lambda functions variable should not have any sensitive data" -Description: "Ensure functions environment variables is not having any sensitive data. Leveraging Secrets Manager enables secure provisioning of database credentials to Lambda functions while also ensuring the security of databases. This approach eliminates the need to hardcode secrets in code or pass them through environmental variables. Additionally, Secrets Manager facilitates the secure retrieval of credentials for establishing connections to databases and performing queries, enhancing overall security measures." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with function_vaiable_with_sensitive_data as (\nselect\n distinct arn,\n name\nfrom\n aws_lambda_function\n join jsonb_each_text(environment_variables) d on true\nwhere\n d.key ilike any (array['%pass%', '%secret%', '%token%', '%key%'])\n or d.key ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]'\n or d.value ilike any (array['%pass%', '%secret%', '%token%', '%key%'])\n or d.value ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]'\n)\nselect\n f.arn as resource,\n f.og_account_id as og_account_id,\n f.og_resource_id as og_resource_id,\n case\n when b.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is null then f.title || ' has no sensitive data.'\n else f.title || ' has potential sensitive data.'\n end as reason\n \n \nfrom\n aws_lambda_function as f\n left join function_vaiable_with_sensitive_data b on f.arn = b.arn;" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: [] + PrimaryTable: aws_lambda_function + QueryToExecute: | + WITH function_vaiable_with_sensitive_data AS ( + SELECT DISTINCT + arn, + name + FROM + aws_lambda_function + JOIN jsonb_each_text(environment_variables) d ON true + WHERE + d.key ILIKE ANY (ARRAY['%pass%', '%secret%', '%token%', '%key%']) + OR d.key ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' + OR d.value ILIKE ANY (ARRAY['%pass%', '%secret%', '%token%', '%key%']) + OR d.value ~ '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]' + ) + SELECT + f.arn AS resource, + f.og_account_id AS og_account_id, + f.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NULL THEN f.title || ' has no sensitive data.' + ELSE f.title || ' has potential sensitive data.' + END AS reason + FROM + aws_lambda_function AS f + LEFT JOIN function_vaiable_with_sensitive_data b ON f.arn = b.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Lambda functions variable should not have any sensitive data \ No newline at end of file diff --git a/compliance/controls/aws/aws_lightsail_instance_ipv6_networking_disabled.yaml b/compliance/controls/aws/aws_lightsail_instance_ipv6_networking_disabled.yaml old mode 100755 new mode 100644 index 24ca4218a..281b01942 --- a/compliance/controls/aws/aws_lightsail_instance_ipv6_networking_disabled.yaml +++ b/compliance/controls/aws/aws_lightsail_instance_ipv6_networking_disabled.yaml @@ -1,14 +1,28 @@ +Description: Any protocols enable within Lightsail by default that aren't being used should be disabled. ID: aws_lightsail_instance_ipv6_networking_disabled -Title: "Disable IPv6 Networking if not in use within your organization" -Description: "Any protocols enable within Lightsail by default that aren't being used should be disabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when ip_v6_addresses is null then 'ok'\n else 'alarm'\n end as status,\n case\n when ip_v6_addresses is null then name || ' has IPv6 networking disabled.'\n else name || ' has IPv6 networking enabled.'\n end as reason\n \nfrom\n aws_lightsail_instance;" - PrimaryTable: aws_lightsail_instance ListOfTables: - aws_lightsail_instance Parameters: [] + PrimaryTable: aws_lightsail_instance + QueryToExecute: | + SELECT + name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ip_v6_addresses IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ip_v6_addresses IS NULL THEN name || ' has IPv6 networking disabled.' + ELSE name || ' has IPv6 networking enabled.' + END AS reason + FROM + aws_lightsail_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Disable IPv6 Networking if not in use within your organization \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_group_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_log_group_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 60544acc8..69c8350e1 --- a/compliance/controls/aws/aws_log_group_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_log_group_encryption_at_rest_enabled.yaml @@ -1,13 +1,30 @@ +Description: To help protect sensitive data at rest, ensure encryption is enabled for your AWS CloudWatch Log Group. ID: aws_log_group_encryption_at_rest_enabled -Title: "Log group encryption at rest should be enabled" -Description: "To help protect sensitive data at rest, ensure encryption is enabled for your AWS CloudWatch Log Group." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kms_key_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_key_id is null then title || ' not encrypted at rest.'\n else title || ' encrypted at rest.'\n end as reason\n \n , region, account_id\nfrom\n aws_cloudwatch_log_group;\n" - PrimaryTable: aws_cloudwatch_log_group ListOfTables: - aws_cloudwatch_log_group Parameters: [] + PrimaryTable: aws_cloudwatch_log_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' not encrypted at rest.' + ELSE title || ' encrypted at rest.' + END AS reason, + region, + account_id + FROM + aws_cloudwatch_log_group; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/CloudWatch soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Log group encryption at rest should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_bucket_policy.yaml b/compliance/controls/aws/aws_log_metric_filter_bucket_policy.yaml old mode 100755 new mode 100644 index b5081d685..1ec020e03 --- a/compliance/controls/aws/aws_log_metric_filter_bucket_policy.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_bucket_policy.yaml @@ -1,55 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for changes to S3 bucket policies. Monitoring these changes might reduce time to detect and correct permissive policies on sensitive S3 buckets. ID: aws_log_metric_filter_bucket_policy -Title: "Ensure a log metric filter and alarm exist for S3 bucket policy changes" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for changes to S3 bucket policies. Monitoring these changes might reduce time to detect and correct permissive policies on sensitive S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging as is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern, - filter.metric_transformation_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*s3.amazonaws.com.+\$\.eventName\s*=\s*PutBucketAcl.+\$\.eventName\s*=\s*PutBucketPolicy.+\$\.eventName\s*=\s*PutBucketCors.+\$\.eventName\s*=\s*PutBucketLifecycle.+\$\.eventName\s*=\s*PutBucketReplication.+\$\.eventName\s*=\s*DeleteBucketPolicy.+\$\.eventName\s*=\s*DeleteBucketCors.+\$\.eventName\s*=\s*DeleteBucketLifecycle.+\$\.eventName\s*=\s*DeleteBucketReplication' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for S3 bucket policy changes.' - else filter_name || ' forwards events for S3 bucket policy changes.' - end as reason - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -57,6 +11,53 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging AS is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern, + filter.metric_transformation_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + JSONB_ARRAY_ELEMENTS_TEXT(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = SPLIT_PART(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*s3.amazonaws.com.+\$.eventName\s*=\s*PutBucketAcl.+\$.eventName\s*=\s*PutBucketPolicy.+\$.eventName\s*=\s*PutBucketCors.+\$.eventName\s*=\s*PutBucketLifecycle.+\$.eventName\s*=\s*PutBucketReplication.+\$.eventName\s*=\s*DeleteBucketPolicy.+\$.eventName\s*=\s*DeleteBucketCors.+\$.eventName\s*=\s*DeleteBucketLifecycle.+\$.eventName\s*=\s*DeleteBucketReplication' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for S3 bucket policy changes.' + ELSE filter_name || ' forwards events for S3 bucket policy changes.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -77,5 +78,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for S3 bucket policy changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_cloudtrail_configuration.yaml b/compliance/controls/aws/aws_log_metric_filter_cloudtrail_configuration.yaml old mode 100755 new mode 100644 index d1fa112b8..5fc70ea84 --- a/compliance/controls/aws/aws_log_metric_filter_cloudtrail_configuration.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_cloudtrail_configuration.yaml @@ -1,54 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for changes to CloudTrail configuration settings. Monitoring these changes helps ensure sustained visibility to activities in the account. ID: aws_log_metric_filter_cloudtrail_configuration -Title: "Ensure a log metric filter and alarm exist for CloudTrail configuration changes" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for changes to CloudTrail configuration settings. Monitoring these changes helps ensure sustained visibility to activities in the account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateTrail.+\$\.eventName\s*=\s*UpdateTrail.+\$\.eventName\s*=\s*DeleteTrail.+\$\.eventName\s*=\s*StartLogging.+\$\.eventName\s*=\s*StopLogging' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for CloudTrail configuration changes.' - else filter_name || ' forwards events for CloudTrail configuration changes.' - end as reason - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -56,6 +11,52 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = split_part(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateTrail.+\$\.eventName\s*=\s*UpdateTrail.+\$\.eventName\s*=\s*DeleteTrail.+\$\.eventName\s*=\s*StartLogging.+\$\.eventName\s*=\s*StopLogging' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for CloudTrail configuration changes.' + ELSE filter_name || ' forwards events for CloudTrail configuration changes.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -76,5 +77,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for CloudTrail configuration changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_config_configuration.yaml b/compliance/controls/aws/aws_log_metric_filter_config_configuration.yaml old mode 100755 new mode 100644 index acae08001..ffdd4d017 --- a/compliance/controls/aws/aws_log_metric_filter_config_configuration.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_config_configuration.yaml @@ -1,54 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for changes to AWS Config configuration settings. Monitoring these changes helps ensure sustained visibility of configuration items in the account ID: aws_log_metric_filter_config_configuration -Title: "Ensure a log metric filter and alarm exist for AWS Config configuration changes" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for changes to AWS Config configuration settings. Monitoring these changes helps ensure sustained visibility of configuration items in the account" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*config.amazonaws.com.+\$\.eventName\s*=\s*StopConfigurationRecorder.+\$\.eventName\s*=\s*DeleteDeliveryChannel.+\$\.eventName\s*=\s*PutDeliveryChannel.+\$\.eventName\s*=\s*PutConfigurationRecorder' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for AWS Config configuration changes.' - else filter_name || ' forwards events for AWS Config configuration changes.' - end as reason - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -56,6 +11,52 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = SPLIT_PART(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*config.amazonaws.com.+\$\.eventName\s*=\s*StopConfigurationRecorder.+\$\.eventName\s*=\s*DeleteDeliveryChannel.+\$\.eventName\s*=\s*PutDeliveryChannel.+\$\.eventName\s*=\s*PutConfigurationRecorder' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for AWS Config configuration changes.' + ELSE filter_name || ' forwards events for AWS Config configuration changes.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -76,5 +77,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for AWS Config configuration changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_console_authentication_failure.yaml b/compliance/controls/aws/aws_log_metric_filter_console_authentication_failure.yaml old mode 100755 new mode 100644 index 5b2a6d51d..9bd9e7bac --- a/compliance/controls/aws/aws_log_metric_filter_console_authentication_failure.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_console_authentication_failure.yaml @@ -1,54 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for failed console authentication attempts. ID: aws_log_metric_filter_console_authentication_failure -Title: "Ensure a log metric filter and alarm exist for AWS Management Console authentication failures" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for failed console authentication attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*ConsoleLogin.+\$\.errorMessage\s*=\s*"Failed authentication"' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for console authentication failures.' - else filter_name || ' forwards events for console authentication failures.' - end as reason - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -56,6 +11,52 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = split_part(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*ConsoleLogin.+\$\.errorMessage\s*=\s*"Failed authentication"' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console authentication failures.' + ELSE filter_name || ' forwards events for console authentication failures.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -76,5 +77,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for AWS Management Console authentication failures \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_console_login_mfa.yaml b/compliance/controls/aws/aws_log_metric_filter_console_login_mfa.yaml old mode 100755 new mode 100644 index c69401a6f..a66e377ff --- a/compliance/controls/aws/aws_log_metric_filter_console_login_mfa.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_console_login_mfa.yaml @@ -1,55 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm console logins that aren't protected by MFA. ID: aws_log_metric_filter_console_login_mfa -Title: "Ensure a log metric filter and alarm exist for AWS Management Console sign-in without MFA" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm console logins that aren't protected by MFA." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\(\s*\$\.eventName\s*=\s*"ConsoleLogin"\)\s+&&\s+\(\s*\$.additionalEventData\.MFAUsed\s*!=\s*"Yes"\)' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for console sign-in without MFA.' - else filter_name || ' forwards events for console sign-in without MFA.' - end as reason - - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -57,6 +11,52 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = SPLIT_PART(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\(\s*\$\.eventName\s*=\s*"ConsoleLogin"\)\s+&&\s+\(\s*\$.additionalEventData\.MFAUsed\s*!=\s*"Yes"\)' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console sign-in without MFA.' + ELSE filter_name || ' forwards events for console sign-in without MFA.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -77,5 +77,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for AWS Management Console sign-in without MFA \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_disable_or_delete_cmk.yaml b/compliance/controls/aws/aws_log_metric_filter_disable_or_delete_cmk.yaml old mode 100755 new mode 100644 index 3bed490d6..96cce84d5 --- a/compliance/controls/aws/aws_log_metric_filter_disable_or_delete_cmk.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_disable_or_delete_cmk.yaml @@ -1,54 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for customer managed keys that have changed state to disabled or scheduled deletion. Data encrypted with disabled or deleted keys is no longer accessible. ID: aws_log_metric_filter_disable_or_delete_cmk -Title: "Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer managed keys" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for customer managed keys that have changed state to disabled or scheduled deletion. Data encrypted with disabled or deleted keys is no longer accessible." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*kms.amazonaws.com.+\$\.eventName\s*=\s*DisableKey.+\$\.eventName\s*=\s*ScheduleKeyDeletion' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for disabling/deletion of CMKs.' - else filter_name || ' forwards events for disabling/deletion of CMKs.' - end as reason - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -56,6 +11,52 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = SPLIT_PART(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*kms.amazonaws.com.+\$\.eventName\s*=\s*DisableKey.+\$\.eventName\s*=\s*ScheduleKeyDeletion' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for disabling/deletion of CMKs.' + ELSE filter_name || ' forwards events for disabling/deletion of CMKs.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -76,5 +77,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer managed keys \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_iam_policy.yaml b/compliance/controls/aws/aws_log_metric_filter_iam_policy.yaml old mode 100755 new mode 100644 index 4e8269754..81bc1226d --- a/compliance/controls/aws/aws_log_metric_filter_iam_policy.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_iam_policy.yaml @@ -1,56 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for changes made to IAM policies. Monitoring these changes helps ensure that authentication and authorization controls remain intact. ID: aws_log_metric_filter_iam_policy -Title: "Ensure a log metric filter and alarm exist for IAM policy changes" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for changes made to IAM policies. Monitoring these changes helps ensure that authentication and authorization controls remain intact." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging as is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern, - filter.metric_transformation_name - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*DeleteGroupPolicy.+\$\.eventName\s*=\s*DeleteRolePolicy.+\$\.eventName\s*=\s*DeleteUserPolicy.+\$\.eventName\s*=\s*PutGroupPolicy.+\$\.eventName\s*=\s*PutRolePolicy.+\$\.eventName\s*=\s*PutUserPolicy.+\$\.eventName\s*=\s*CreatePolicy.+\$\.eventName\s*=\s*DeletePolicy.+\$\.eventName\s*=\s*CreatePolicyVersion.+\$\.eventName\s*=\s*DeletePolicyVersion.+\$\.eventName\s*=\s*AttachRolePolicy.+\$\.eventName\s*=\s*DetachRolePolicy.+\$\.eventName\s*=\s*AttachUserPolicy.+\$\.eventName\s*=\s*DetachUserPolicy.+\$\.eventName\s*=\s*AttachGroupPolicy.+\$\.eventName\s*=\s*DetachGroupPolicy' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for IAM policy changes.' - else filter_name || ' forwards events for IAM policy changes.' - end as reason - - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -58,6 +11,53 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging AS is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern, + filter.metric_transformation_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = SPLIT_PART(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*DeleteGroupPolicy.+\$\.eventName\s*=\s*DeleteRolePolicy.+\$\.eventName\s*=\s*DeleteUserPolicy.+\$\.eventName\s*=\s*PutGroupPolicy.+\$\.eventName\s*=\s*PutRolePolicy.+\$\.eventName\s*=\s*PutUserPolicy.+\$\.eventName\s*=\s*CreatePolicy.+\$\.eventName\s*=\s*DeletePolicy.+\$\.eventName\s*=\s*CreatePolicyVersion.+\$\.eventName\s*=\s*DeletePolicyVersion.+\$\.eventName\s*=\s*AttachRolePolicy.+\$\.eventName\s*=\s*DetachRolePolicy.+\$\.eventName\s*=\s*AttachUserPolicy.+\$\.eventName\s*=\s*DetachUserPolicy.+\$\.eventName\s*=\s*AttachGroupPolicy.+\$\.eventName\s*=\s*DetachGroupPolicy' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for IAM policy changes.' + ELSE filter_name || ' forwards events for IAM policy changes.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -78,5 +78,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for IAM policy changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_network_acl.yaml b/compliance/controls/aws/aws_log_metric_filter_network_acl.yaml old mode 100755 new mode 100644 index b94b6de12..f341211f4 --- a/compliance/controls/aws/aws_log_metric_filter_network_acl.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_network_acl.yaml @@ -1,54 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets in a VPC. Security Hub recommends that you create a metric filter and alarm for changes to NACLs. Monitoring these changes helps ensure that AWS resources and services aren't unintentionally exposed. ID: aws_log_metric_filter_network_acl -Title: "Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL)" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets in a VPC. Security Hub recommends that you create a metric filter and alarm for changes to NACLs. Monitoring these changes helps ensure that AWS resources and services aren't unintentionally exposed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateNetworkAcl.+\$\.eventName\s*=\s*CreateNetworkAclEntry.+\$\.eventName\s*=\s*DeleteNetworkAcl.+\$\.eventName\s*=\s*DeleteNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclAssociation' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for changes to NACLs.' - else filter_name || ' forwards events for changes to NACLs.' - end as reason - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -56,6 +11,52 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = split_part(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateNetworkAcl.+\\$\\.eventName\\s*=\\s*CreateNetworkAclEntry.+\\$\\.eventName\\s*=\\s*DeleteNetworkAcl.+\\$\\.eventName\\s*=\\s*DeleteNetworkAclEntry.+\\$\\.eventName\\s*=\\s*ReplaceNetworkAclEntry.+\\$\\.eventName\\s*=\\s*ReplaceNetworkAclAssociation' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to NACLs.' + ELSE filter_name || ' forwards events for changes to NACLs.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: medium Tags: category: @@ -76,5 +77,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_network_gateway.yaml b/compliance/controls/aws/aws_log_metric_filter_network_gateway.yaml old mode 100755 new mode 100644 index 567ef8aec..c60be22d8 --- a/compliance/controls/aws/aws_log_metric_filter_network_gateway.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_network_gateway.yaml @@ -1,55 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send and receive traffic to a destination outside a VPC. Security Hub recommends that you create a metric filter and alarm for changes to network gateways. ID: aws_log_metric_filter_network_gateway -Title: "Ensure a log metric filter and alarm exist for changes to network gateways" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send and receive traffic to a destination outside a VPC. Security Hub recommends that you create a metric filter and alarm for changes to network gateways." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - alarm.name as alarm_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateCustomerGateway.+\$\.eventName\s*=\s*DeleteCustomerGateway.+\$\.eventName\s*=\s*AttachInternetGateway.+\$\.eventName\s*=\s*CreateInternetGateway.+\$\.eventName\s*=\s*DeleteInternetGateway.+\$\.eventName\s*=\s*DetachInternetGateway' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for changes to network gateways.' - else filter_name || ' forwards events for changes to network gateways.' - end as reason - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -57,6 +11,53 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + alarm.name AS alarm_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = split_part(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateCustomerGateway.+\$\.eventName\s*=\s*DeleteCustomerGateway.+\$\.eventName\s*=\s*AttachInternetGateway.+\$\.eventName\s*=\s*CreateInternetGateway.+\$\.eventName\s*=\s*DeleteInternetGateway.+\$\.eventName\s*=\s*DetachInternetGateway' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to network gateways.' + ELSE filter_name || ' forwards events for changes to network gateways.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -77,5 +78,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for changes to network gateways \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_organization.yaml b/compliance/controls/aws/aws_log_metric_filter_organization.yaml old mode 100755 new mode 100644 index b5d4b7db3..07e483b67 --- a/compliance/controls/aws/aws_log_metric_filter_organization.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_organization.yaml @@ -1,55 +1,9 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account. ID: aws_log_metric_filter_organization -Title: "Ensure AWS Organizations changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - alarm.name as alarm_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*organizations.amazonaws.com.+\$\.eventName\s*=\s*"?AcceptHandshake"?.+\$\.eventName\s*=\s*"?AttachPolicy"?.+\$\.eventName\s*=\s*"?CreateAccount"?.+\$\.eventName\s*=\s*"?CreateOrganizationalUnit"?.+\$\.eventName\s*=\s*"?CreatePolicy"?.+\$\.eventName\s*=\s*"?DeclineHandshake"?.+\$\.eventName\s*=\s*"?DeleteOrganization"?.+\$\.eventName\s*=\s*"?DeleteOrganizationalUnit"?.+\$\.eventName\s*=\s*"?DeletePolicy"?.+\$\.eventName\s*=\s*"?DetachPolicy"?.+\$\.eventName\s*=\s*"?DisablePolicyType"?.+\$\.eventName\s*=\s*"?EnablePolicyType"?.+\$\.eventName\s*=\s*"?InviteAccountToOrganization"?.+\$\.eventName\s*=\s*"?LeaveOrganization"?.+\$\.eventName\s*=\s*"?MoveAccount"?.+\$\.eventName\s*=\s*"?RemoveAccountFromOrganization"?.+\$\.eventName\s*=\s*"?UpdatePolicy"?.+\$\.eventName\s*=\s*"?UpdateOrganizationalUnit"?' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exists for AWS Organizations changes.' - else filter_name || ' forwards relevant events for AWS Organizations changes.' - end as reason - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -57,6 +11,53 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + alarm.name AS alarm_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + JSONB_ARRAY_ELEMENTS_TEXT(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = SPLIT_PART(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*organizations.amazonaws.com.+\$\.eventName\s*=\s*"?AcceptHandshake"?.+\$\.eventName\s*=\s*"?AttachPolicy"?.+\$\.eventName\s*=\s*"?CreateAccount"?.+\$\.eventName\s*=\s*"?CreateOrganizationalUnit"?.+\$\.eventName\s*=\s*"?CreatePolicy"?.+\$\.eventName\s*=\s*"?DeclineHandshake"?.+\$\.eventName\s*=\s*"?DeleteOrganization"?.+\$\.eventName\s*=\s*"?DeleteOrganizationalUnit"?.+\$\.eventName\s*=\s*"?DeletePolicy"?.+\$\.eventName\s*=\s*"?DetachPolicy"?.+\$\.eventName\s*=\s*"?DisablePolicyType"?.+\$\.eventName\s*=\s*"?EnablePolicyType"?.+\$\.eventName\s*=\s*"?InviteAccountToOrganization"?.+\$\.eventName\s*=\s*"?LeaveOrganization"?.+\$\.eventName\s*=\s*"?MoveAccount"?.+\$\.eventName\s*=\s*"?RemoveAccountFromOrganization"?.+\$\.eventName\s*=\s*"?UpdatePolicy"?.+\$\.eventName\s*=\s*"?UpdateOrganizationalUnit"?' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exists for AWS Organizations changes.' + ELSE filter_name || ' forwards relevant events for AWS Organizations changes.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -77,5 +78,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure AWS Organizations changes are monitored \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_root_login.yaml b/compliance/controls/aws/aws_log_metric_filter_root_login.yaml old mode 100755 new mode 100644 index d0fe33c7b..b4beb879f --- a/compliance/controls/aws/aws_log_metric_filter_root_login.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_root_login.yaml @@ -1,55 +1,9 @@ +Description: You can do real-time monitoring of API calls directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Hub recommends that you create a metric filter and alarm for root login attempts. Monitoring for root account logins provides visibility into the use of a fully privileged account and an opportunity to reduce the use of it. ID: aws_log_metric_filter_root_login -Title: "Ensure a log metric filter and alarm exist for usage of 'root' account" -Description: "You can do real-time monitoring of API calls directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms.Security Hub recommends that you create a metric filter and alarm for root login attempts. Monitoring for root account logins provides visibility into the use of a fully privileged account and an opportunity to reduce the use of it." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.userIdentity\.type\s*=\s*"Root".+\$\.userIdentity\.invokedBy NOT EXISTS.+\$\.eventType\s*!=\s*"AwsServiceEvent"' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for usage of "root" account.' - else filter_name || ' forwards events for usage of "root" account.' - end as reason - - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -57,6 +11,52 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = SPLIT_PART(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.userIdentity\.type\s*=\s*"Root".+\$\.userIdentity\.invokedBy NOT EXISTS.+\$\.eventType\s*!=\s*"AwsServiceEvent"' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for usage of "root" account.' + ELSE filter_name || ' forwards events for usage of "root" account.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -77,5 +77,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for usage of 'root' account \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_route_table.yaml b/compliance/controls/aws/aws_log_metric_filter_route_table.yaml old mode 100755 new mode 100644 index 743e21250..753f389b8 --- a/compliance/controls/aws/aws_log_metric_filter_route_table.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_route_table.yaml @@ -1,55 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables route network traffic between subnets and to network gateways. Security Hub recommends that you create a metric filter and alarm for changes to route tables. Monitoring these changes helps ensure that all VPC traffic flows through an expected path. ID: aws_log_metric_filter_route_table -Title: "Ensure a log metric filter and alarm exist for route table changes" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables route network traffic between subnets and to network gateways. Security Hub recommends that you create a metric filter and alarm for changes to route tables. Monitoring these changes helps ensure that all VPC traffic flows through an expected path." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - alarm.name as alarm_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*ReplaceRoute.+\$\.eventName\s*=\s*ReplaceRouteTableAssociation.+\$\.eventName\s*=\s*DeleteRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for route table changes.' - else filter_name || ' forwards events for route table changes.' - end as reason - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -57,6 +11,53 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + alarm.name AS alarm_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = split_part(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*ReplaceRoute.+\$\.eventName\s*=\s*ReplaceRouteTableAssociation.+\$\.eventName\s*=\s*DeleteRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for route table changes.' + ELSE filter_name || ' forwards events for route table changes.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -77,5 +78,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for route table changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_security_group.yaml b/compliance/controls/aws/aws_log_metric_filter_security_group.yaml old mode 100755 new mode 100644 index 9d4a09ef9..8456f6af9 --- a/compliance/controls/aws/aws_log_metric_filter_security_group.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_security_group.yaml @@ -1,54 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security groups are a stateful packet filter that controls ingress and egress traffic in a VPC. Security Hub recommends that you create a metric filter and alarm for changes to security groups. Monitoring these changes helps ensure that resources and services aren't unintentionally exposed. ID: aws_log_metric_filter_security_group -Title: "Ensure a log metric filter and alarm exist for security group changes" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security groups are a stateful packet filter that controls ingress and egress traffic in a VPC. Security Hub recommends that you create a metric filter and alarm for changes to security groups. Monitoring these changes helps ensure that resources and services aren't unintentionally exposed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*RevokeSecurityGroupIngress.+\$\.eventName\s*=\s*RevokeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for security group changes.' - else filter_name || ' forwards events for security group changes.' - end as reason - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -56,6 +11,52 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + JSONB_ARRAY_ELEMENTS_TEXT(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = SPLIT_PART(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*RevokeSecurityGroupIngress.+\$\.eventName\s*=\s*RevokeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for security group changes.' + ELSE filter_name || ' forwards events for security group changes.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -76,5 +77,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for security group changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_unauthorized_api.yaml b/compliance/controls/aws/aws_log_metric_filter_unauthorized_api.yaml old mode 100755 new mode 100644 index e4a1bd5ee..323550c69 --- a/compliance/controls/aws/aws_log_metric_filter_unauthorized_api.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_unauthorized_api.yaml @@ -1,55 +1,9 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls. ID: aws_log_metric_filter_unauthorized_api -Title: "Ensure a log metric filter and alarm exist for unauthorized API calls" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\$\.errorCode\s*=\s*"\*UnauthorizedOperation".+\$\.errorCode\s*=\s*"AccessDenied\*".+\$\.sourceIPAddress\s*!=\s*"delivery.logs.amazonaws.com".+\$\.eventName\s*!=\s*"HeadBucket"' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for unauthorized API calls.' - else filter_name || ' forwards events for unauthorized API calls.' - end as reason - - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -57,6 +11,52 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = SPLIT_PART(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\$\.errorCode\s*=\s*"\*UnauthorizedOperation".+\$\.errorCode\s*=\s*"AccessDenied\*".+\$\.sourceIPAddress\s*!=\s*"delivery.logs.amazonaws.com".+\$\.eventName\s*!=\s*"HeadBucket"' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for unauthorized API calls.' + ELSE filter_name || ' forwards events for unauthorized API calls.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -77,5 +77,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for unauthorized API calls \ No newline at end of file diff --git a/compliance/controls/aws/aws_log_metric_filter_vpc.yaml b/compliance/controls/aws/aws_log_metric_filter_vpc.yaml old mode 100755 new mode 100644 index 9688b638f..28aaa0be9 --- a/compliance/controls/aws/aws_log_metric_filter_vpc.yaml +++ b/compliance/controls/aws/aws_log_metric_filter_vpc.yaml @@ -1,56 +1,9 @@ +Description: You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. You can have more than one VPC in an account, and you can create a peer connection between two VPCs, enabling network traffic to route between VPCs. Security Hub recommends that you create a metric filter and alarm for changes to VPCs. ID: aws_log_metric_filter_vpc -Title: "Ensure a log metric filter and alarm exist for VPC changes" -Description: "You can do real-time monitoring of API calls by directing CloudTrail logs to CloudWatch Logs and establishing corresponding metric filters and alarms. You can have more than one VPC in an account, and you can create a peer connection between two VPCs, enabling network traffic to route between VPCs. Security Hub recommends that you create a metric filter and alarm for changes to VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with filter_data as ( - select - trail.account_id, - trail.name as trail_name, - trail.is_logging, - split_part(trail.log_group_arn, ':', 7) as log_group_name, - filter.name as filter_name, - action_arn as topic_arn, - alarm.metric_name, - alarm.name as alarm_name, - subscription.subscription_arn, - filter.filter_pattern - from - aws_cloudtrail_trail as trail, - jsonb_array_elements(trail.event_selectors) as se, - aws_cloudwatch_log_metric_filter as filter, - aws_cloudwatch_alarm as alarm, - jsonb_array_elements_text(alarm.alarm_actions) as action_arn, - aws_sns_topic_subscription as subscription - where - trail.is_multi_region_trail is true - and trail.is_logging - and se ->> 'ReadWriteType' = 'All' - and trail.log_group_arn is not null - and filter.log_group_name = split_part(trail.log_group_arn, ':', 7) - and filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateVpc.+\$\.eventName\s*=\s*DeleteVpc.+\$\.eventName\s*=\s*ModifyVpcAttribute.+\$\.eventName\s*=\s*AcceptVpcPeeringConnection.+\$\.eventName\s*=\s*CreateVpcPeeringConnection.+\$\.eventName\s*=\s*DeleteVpcPeeringConnection.+\$\.eventName\s*=\s*RejectVpcPeeringConnection.+\$\.eventName\s*=\s*AttachClassicLinkVpc.+\$\.eventName\s*=\s*DetachClassicLinkVpc.+\$\.eventName\s*=\s*DisableVpcClassicLink.+\$\.eventName\s*=\s*EnableVpcClassicLink' - and alarm.metric_name LIKE filter.metric_transformation_name - and subscription.topic_arn = action_arn - ) - select - distinct 'arn:' || a.partition || ':::' || a.account_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when f.trail_name is null then 'alarm' - else 'ok' - end as status, - case - when f.trail_name is null then 'No log metric filter and alarm exist for VPC changes.' - else filter_name || ' forwards events for VPC changes.' - end as reason - - , a.account_id - from - aws_account as a - left join filter_data as f on a.account_id = f.account_id; - PrimaryTable: aws_account ListOfTables: - aws_account - aws_cloudtrail_trail @@ -58,6 +11,53 @@ Query: - aws_cloudwatch_log_metric_filter - aws_sns_topic_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH filter_data AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name, + filter.name AS filter_name, + action_arn AS topic_arn, + alarm.metric_name, + alarm.name AS alarm_name, + subscription.subscription_arn, + filter.filter_pattern + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se, + aws_cloudwatch_log_metric_filter AS filter, + aws_cloudwatch_alarm AS alarm, + jsonb_array_elements_text(alarm.alarm_actions) AS action_arn, + aws_sns_topic_subscription AS subscription + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + AND filter.log_group_name = SPLIT_PART(trail.log_group_arn, ':', 7) + AND filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateVpc.+\$\.eventName\s*=\s*DeleteVpc.+\$\.eventName\s*=\s*ModifyVpcAttribute.+\$\.eventName\s*=\s*AcceptVpcPeeringConnection.+\$\.eventName\s*=\s*CreateVpcPeeringConnection.+\$\.eventName\s*=\s*DeleteVpcPeeringConnection.+\$\.eventName\s*=\s*RejectVpcPeeringConnection.+\$\.eventName\s*=\s*AttachClassicLinkVpc.+\$\.eventName\s*=\s*DetachClassicLinkVpc.+\$\.eventName\s*=\s*DisableVpcClassicLink.+\$\.eventName\s*=\s*EnableVpcClassicLink' + AND alarm.metric_name LIKE filter.metric_transformation_name + AND subscription.topic_arn = action_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for VPC changes.' + ELSE filter_name || ' forwards events for VPC changes.' + END AS reason, + a.account_id + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: high Tags: category: @@ -78,5 +78,4 @@ Tags: - aws service: - AWS/CloudWatch -IntegrationType: - - aws_cloud_account +Title: Ensure a log metric filter and alarm exist for VPC changes \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_accessanalyzer_analyzer_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_accessanalyzer_analyzer_mandatory.yaml old mode 100755 new mode 100644 index ce7c2795c..b1e1ce658 --- a/compliance/controls/aws/aws_mandatory_sql_accessanalyzer_analyzer_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_accessanalyzer_analyzer_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Access Analyzer analyzers have mandatory tags. ID: aws_mandatory_sql_accessanalyzer_analyzer_mandatory -Title: "Access Analyzer analyzers should have mandatory tags" -Description: "Check if Access Analyzer analyzers have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_accessanalyzer_analyzer\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_accessanalyzer_analyzer ListOfTables: - aws_accessanalyzer_analyzer Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_accessanalyzer_analyzer + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_accessanalyzer_analyzer + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Access Analyzer analyzers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_api_gateway_stage_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_api_gateway_stage_mandatory.yaml old mode 100755 new mode 100644 index f0b09ce85..60f7f436f --- a/compliance/controls/aws/aws_mandatory_sql_api_gateway_stage_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_api_gateway_stage_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if API Gateway stages have mandatory tags. ID: aws_mandatory_sql_api_gateway_stage_mandatory -Title: "API Gateway stages should have mandatory tags" -Description: "Check if API Gateway stages have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_api_gateway_stage\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_api_gateway_stage ListOfTables: - aws_api_gateway_stage Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_api_gateway_stage + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_api_gateway_stage + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: API Gateway stages should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_cloudfront_distribution_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_cloudfront_distribution_mandatory.yaml old mode 100755 new mode 100644 index 37119389a..acf4b7536 --- a/compliance/controls/aws/aws_mandatory_sql_cloudfront_distribution_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_cloudfront_distribution_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if CloudFront distributions have mandatory tags. ID: aws_mandatory_sql_cloudfront_distribution_mandatory -Title: "CloudFront distributions should have mandatory tags" -Description: "Check if CloudFront distributions have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_cloudfront_distribution\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_cloudfront_distribution ListOfTables: - aws_cloudfront_distribution Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_cloudfront_distribution + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_cloudfront_distribution + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_cloudtrail_trail_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_cloudtrail_trail_mandatory.yaml old mode 100755 new mode 100644 index 4aa51e103..4912f7848 --- a/compliance/controls/aws/aws_mandatory_sql_cloudtrail_trail_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_cloudtrail_trail_mandatory.yaml @@ -1,16 +1,53 @@ +Description: Check if CloudTrail trails have mandatory tags. ID: aws_mandatory_sql_cloudtrail_trail_mandatory -Title: "CloudTrail trails should have mandatory tags" -Description: "Check if CloudTrail trails have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_cloudtrail_trail\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_cloudtrail_trail ListOfTables: - aws_cloudtrail_trail Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_cloudtrail_trail + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - array( + SELECT jsonb_object_keys(tags) + ) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_cloudtrail_trail + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN has_mandatory_tags THEN + title || ' has all mandatory tags.' + ELSE + title || ' is missing tags: ' || array_to_string(array( + SELECT jsonb_array_elements_text(missing_tags) + ), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudTrail trails should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_cloudwatch_alarm_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_cloudwatch_alarm_mandatory.yaml old mode 100755 new mode 100644 index 529193bf9..6537e85b8 --- a/compliance/controls/aws/aws_mandatory_sql_cloudwatch_alarm_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_cloudwatch_alarm_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if CloudWatch alarms have mandatory tags. ID: aws_mandatory_sql_cloudwatch_alarm_mandatory -Title: "CloudWatch alarms should have mandatory tags" -Description: "Check if CloudWatch alarms have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_cloudwatch_alarm\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_cloudwatch_alarm ListOfTables: - aws_cloudwatch_alarm Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_cloudwatch_alarm + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_cloudwatch_alarm + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudWatch alarms should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_cloudwatch_log_group_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_cloudwatch_log_group_mandatory.yaml old mode 100755 new mode 100644 index c9f45ec0c..f7a087284 --- a/compliance/controls/aws/aws_mandatory_sql_cloudwatch_log_group_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_cloudwatch_log_group_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if CloudWatch log groups have mandatory tags. ID: aws_mandatory_sql_cloudwatch_log_group_mandatory -Title: "CloudWatch log groups should have mandatory tags" -Description: "Check if CloudWatch log groups have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_cloudwatch_log_group\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_cloudwatch_log_group ListOfTables: - aws_cloudwatch_log_group Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_cloudwatch_log_group + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_cloudwatch_log_group + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudWatch log groups should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_codebuild_project_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_codebuild_project_mandatory.yaml old mode 100755 new mode 100644 index 3227bb80e..745090d45 --- a/compliance/controls/aws/aws_mandatory_sql_codebuild_project_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_codebuild_project_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if CodeBuild projects have mandatory tags. ID: aws_mandatory_sql_codebuild_project_mandatory -Title: "CodeBuild projects should have mandatory tags" -Description: "Check if CodeBuild projects have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_codebuild_project\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_codebuild_project ListOfTables: - aws_codebuild_project Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_codebuild_project + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_codebuild_project + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: CodeBuild projects should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_codecommit_repository_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_codecommit_repository_mandatory.yaml old mode 100755 new mode 100644 index 966f2d613..6a564e2f8 --- a/compliance/controls/aws/aws_mandatory_sql_codecommit_repository_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_codecommit_repository_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if CodeCommit repositories have mandatory tags. ID: aws_mandatory_sql_codecommit_repository_mandatory -Title: "CodeCommit repositories should have mandatory tags" -Description: "Check if CodeCommit repositories have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_codecommit_repository\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_codecommit_repository ListOfTables: - aws_codecommit_repository Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_codecommit_repository + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_codecommit_repository + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: CodeCommit repositories should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_codepipeline_pipeline_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_codepipeline_pipeline_mandatory.yaml old mode 100755 new mode 100644 index 7bbbb2cbb..fe852b53f --- a/compliance/controls/aws/aws_mandatory_sql_codepipeline_pipeline_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_codepipeline_pipeline_mandatory.yaml @@ -1,16 +1,49 @@ +Description: Check if CodePipeline pipelines have mandatory tags. ID: aws_mandatory_sql_codepipeline_pipeline_mandatory -Title: "CodePipeline pipelines should have mandatory tags" -Description: "Check if CodePipeline pipelines have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_codepipeline_pipeline\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_codepipeline_pipeline ListOfTables: - aws_codepipeline_pipeline Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_codepipeline_pipeline + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_codepipeline_pipeline + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags + THEN title || ' has all mandatory tags.' + ELSE + title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: CodePipeline pipelines should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_config_rule_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_config_rule_mandatory.yaml old mode 100755 new mode 100644 index dc2df0485..a29a7ca8e --- a/compliance/controls/aws/aws_mandatory_sql_config_rule_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_config_rule_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Config rules have mandatory tags. ID: aws_mandatory_sql_config_rule_mandatory -Title: "Config rules should have mandatory tags" -Description: "Check if Config rules have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_config_rule\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_config_rule ListOfTables: - aws_config_rule Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_config_rule + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_config_rule + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Config rules should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_dax_cluster_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_dax_cluster_mandatory.yaml old mode 100755 new mode 100644 index 390a3e5a4..de0a372ae --- a/compliance/controls/aws/aws_mandatory_sql_dax_cluster_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_dax_cluster_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if DAX clusters have mandatory tags. ID: aws_mandatory_sql_dax_cluster_mandatory -Title: "DAX clusters should have mandatory tags" -Description: "Check if DAX clusters have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_dax_cluster\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_dax_cluster ListOfTables: - aws_dax_cluster Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_dax_cluster + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_dax_cluster + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: DAX clusters should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_directory_service_directory_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_directory_service_directory_mandatory.yaml old mode 100755 new mode 100644 index 89faf6b69..56849b0cb --- a/compliance/controls/aws/aws_mandatory_sql_directory_service_directory_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_directory_service_directory_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Directory Service directories have mandatory tags. ID: aws_mandatory_sql_directory_service_directory_mandatory -Title: "Directory Service directories should have mandatory tags" -Description: "Check if Directory Service directories have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_directory_service_directory\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_directory_service_directory ListOfTables: - aws_directory_service_directory Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_directory_service_directory + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_directory_service_directory + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Directory Service directories should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_dms_replication_instance_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_dms_replication_instance_mandatory.yaml old mode 100755 new mode 100644 index e1f858d2c..055a95af7 --- a/compliance/controls/aws/aws_mandatory_sql_dms_replication_instance_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_dms_replication_instance_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Dms replication instances have mandatory tags. ID: aws_mandatory_sql_dms_replication_instance_mandatory -Title: "DMS replication instances should have mandatory tags" -Description: "Check if Dms replication instances have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_dms_replication_instance\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_dms_replication_instance ListOfTables: - aws_dms_replication_instance Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_dms_replication_instance + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_dms_replication_instance + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: DMS replication instances should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_dynamodb_table_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_dynamodb_table_mandatory.yaml old mode 100755 new mode 100644 index 37fc0f5f9..309adddd1 --- a/compliance/controls/aws/aws_mandatory_sql_dynamodb_table_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_dynamodb_table_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if DynamoDB tables have mandatory tags. ID: aws_mandatory_sql_dynamodb_table_mandatory -Title: "DynamoDB tables should have mandatory tags" -Description: "Check if DynamoDB tables have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_dynamodb_table\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_dynamodb_table Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_dynamodb_table + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: DynamoDB tables should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ebs_snapshot_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ebs_snapshot_mandatory.yaml old mode 100755 new mode 100644 index a46d4cfab..6b2389023 --- a/compliance/controls/aws/aws_mandatory_sql_ebs_snapshot_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ebs_snapshot_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EBS snapshots have mandatory tags. ID: aws_mandatory_sql_ebs_snapshot_mandatory -Title: "EBS snapshots should have mandatory tags" -Description: "Check if EBS snapshots have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ebs_snapshot\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ebs_snapshot ListOfTables: - aws_ebs_snapshot Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ebs_snapshot + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ebs_snapshot + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EBS snapshots should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ebs_volume_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ebs_volume_mandatory.yaml old mode 100755 new mode 100644 index d92d86994..a3307440d --- a/compliance/controls/aws/aws_mandatory_sql_ebs_volume_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ebs_volume_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EBS volumes have mandatory tags. ID: aws_mandatory_sql_ebs_volume_mandatory -Title: "EBS volumes should have mandatory tags" -Description: "Check if EBS volumes have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ebs_volume\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ebs_volume + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ebs_volume + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EBS volumes should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ec2_application_load_balancer_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ec2_application_load_balancer_mandatory.yaml old mode 100755 new mode 100644 index bd2aad3fb..e8a83ec06 --- a/compliance/controls/aws/aws_mandatory_sql_ec2_application_load_balancer_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ec2_application_load_balancer_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EC2 application load balancers have mandatory tags. ID: aws_mandatory_sql_ec2_application_load_balancer_mandatory -Title: "EC2 application load balancers should have mandatory tags" -Description: "Check if EC2 application load balancers have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ec2_application_load_balancer\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ec2_application_load_balancer + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(array(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 application load balancers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ec2_classic_load_balancer_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ec2_classic_load_balancer_mandatory.yaml old mode 100755 new mode 100644 index b89fa05c1..b29306d5c --- a/compliance/controls/aws/aws_mandatory_sql_ec2_classic_load_balancer_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ec2_classic_load_balancer_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EC2 classic load balancers have mandatory tags. ID: aws_mandatory_sql_ec2_classic_load_balancer_mandatory -Title: "EC2 classic load balancers should have mandatory tags" -Description: "Check if EC2 classic load balancers have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ec2_classic_load_balancer\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ec2_classic_load_balancer ListOfTables: - aws_ec2_classic_load_balancer Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ec2_classic_load_balancer + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ec2_classic_load_balancer + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 classic load balancers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ec2_gateway_load_balancer_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ec2_gateway_load_balancer_mandatory.yaml old mode 100755 new mode 100644 index 7a087afbd..8091966d2 --- a/compliance/controls/aws/aws_mandatory_sql_ec2_gateway_load_balancer_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ec2_gateway_load_balancer_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EC2 gateway load balancers have mandatory tags. ID: aws_mandatory_sql_ec2_gateway_load_balancer_mandatory -Title: "EC2 gateway load balancers should have mandatory tags" -Description: "Check if EC2 gateway load balancers have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ec2_gateway_load_balancer\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ec2_gateway_load_balancer ListOfTables: - aws_ec2_gateway_load_balancer Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ec2_gateway_load_balancer + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ec2_gateway_load_balancer + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 gateway load balancers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ec2_instance_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ec2_instance_mandatory.yaml old mode 100755 new mode 100644 index ddfc1d327..cbecdec12 --- a/compliance/controls/aws/aws_mandatory_sql_ec2_instance_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ec2_instance_mandatory.yaml @@ -1,16 +1,48 @@ +Description: Check if EC2 instances have mandatory tags. ID: aws_mandatory_sql_ec2_instance_mandatory -Title: "EC2 instances should have mandatory tags" -Description: "Check if EC2 instances have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ec2_instance\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ec2_instance + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags + THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instances should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ec2_network_load_balancer_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ec2_network_load_balancer_mandatory.yaml old mode 100755 new mode 100644 index dfb650bdf..5f59802be --- a/compliance/controls/aws/aws_mandatory_sql_ec2_network_load_balancer_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ec2_network_load_balancer_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EC2 network load balancers have mandatory tags. ID: aws_mandatory_sql_ec2_network_load_balancer_mandatory -Title: "EC2 network load balancers should have mandatory tags" -Description: "Check if EC2 network load balancers have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ec2_network_load_balancer\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ec2_network_load_balancer ListOfTables: - aws_ec2_network_load_balancer Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ec2_network_load_balancer + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ec2_network_load_balancer + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 network load balancers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ec2_reserved_instance_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ec2_reserved_instance_mandatory.yaml old mode 100755 new mode 100644 index c746594cb..a487a5117 --- a/compliance/controls/aws/aws_mandatory_sql_ec2_reserved_instance_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ec2_reserved_instance_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EC2 reserved instances have mandatory tags. ID: aws_mandatory_sql_ec2_reserved_instance_mandatory -Title: "EC2 reserved instances should have mandatory tags" -Description: "Check if EC2 reserved instances have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ec2_reserved_instance\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ec2_reserved_instance ListOfTables: - aws_ec2_reserved_instance Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ec2_reserved_instance + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ec2_reserved_instance + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 reserved instances should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ecr_repository_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ecr_repository_mandatory.yaml old mode 100755 new mode 100644 index b8cea7d64..006f6518c --- a/compliance/controls/aws/aws_mandatory_sql_ecr_repository_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ecr_repository_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if ECR repositories have mandatory tags. ID: aws_mandatory_sql_ecr_repository_mandatory -Title: "ECR repositories should have mandatory tags" -Description: "Check if ECR repositories have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ecr_repository\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ecr_repository ListOfTables: - aws_ecr_repository Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ecr_repository + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ecr_repository + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECR repositories should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ecs_container_instance_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ecs_container_instance_mandatory.yaml old mode 100755 new mode 100644 index 4045acc7a..1e9505fc9 --- a/compliance/controls/aws/aws_mandatory_sql_ecs_container_instance_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ecs_container_instance_mandatory.yaml @@ -1,16 +1,53 @@ +Description: Check if ECS container instances have mandatory tags. ID: aws_mandatory_sql_ecs_container_instance_mandatory -Title: "ECS container instances should have mandatory tags" -Description: "Check if ECS container instances have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ecs_container_instance\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ecs_container_instance ListOfTables: - aws_ecs_container_instance Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ecs_container_instance + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY( + SELECT jsonb_object_keys(tags) + ) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ecs_container_instance + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING( + ARRAY( + SELECT jsonb_array_elements_text(missing_tags) + ), ', ' + ) || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECS container instances should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ecs_service_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ecs_service_mandatory.yaml old mode 100755 new mode 100644 index 3eeb29e8f..0d1c888e8 --- a/compliance/controls/aws/aws_mandatory_sql_ecs_service_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ecs_service_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if ECS services have mandatory tags. ID: aws_mandatory_sql_ecs_service_mandatory -Title: "ECS services should have mandatory tags" -Description: "Check if ECS services have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ecs_service\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ecs_service ListOfTables: - aws_ecs_service Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ecs_service + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::TEXT[]) - ARRAY(SELECT JSONB_OBJECT_KEYS(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ecs_service + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT JSONB_ARRAY_ELEMENTS_TEXT(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECS services should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_efs_file_system_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_efs_file_system_mandatory.yaml old mode 100755 new mode 100644 index c65fea349..41c4a9c1b --- a/compliance/controls/aws/aws_mandatory_sql_efs_file_system_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_efs_file_system_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EFS file systems have mandatory tags. ID: aws_mandatory_sql_efs_file_system_mandatory -Title: "EFS file systems should have mandatory tags" -Description: "Check if EFS file systems have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_efs_file_system\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_efs_file_system ListOfTables: - aws_efs_file_system Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_efs_file_system + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_efs_file_system + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EFS file systems should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_eks_addon_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_eks_addon_mandatory.yaml old mode 100755 new mode 100644 index a2186a68f..8947e6e4c --- a/compliance/controls/aws/aws_mandatory_sql_eks_addon_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_eks_addon_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EKS addons have mandatory tags. ID: aws_mandatory_sql_eks_addon_mandatory -Title: "EKS addons should have mandatory tags" -Description: "Check if EKS addons have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_eks_addon\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_eks_addon ListOfTables: - aws_eks_addon Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_eks_addon + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_eks_addon + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EKS addons should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_eks_cluster_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_eks_cluster_mandatory.yaml old mode 100755 new mode 100644 index 213ba84f8..4e85b60a0 --- a/compliance/controls/aws/aws_mandatory_sql_eks_cluster_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_eks_cluster_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EKS clusters have mandatory tags. ID: aws_mandatory_sql_eks_cluster_mandatory -Title: "EKS clusters should have mandatory tags" -Description: "Check if EKS clusters have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_eks_cluster\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_eks_cluster + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_eks_cluster + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(array(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EKS clusters should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_elastic_beanstalk_application_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_elastic_beanstalk_application_mandatory.yaml old mode 100755 new mode 100644 index c8a8d3486..b1a084675 --- a/compliance/controls/aws/aws_mandatory_sql_elastic_beanstalk_application_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_elastic_beanstalk_application_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Elastic beanstalk applications have mandatory tags. ID: aws_mandatory_sql_elastic_beanstalk_application_mandatory -Title: "Elastic beanstalk applications should have mandatory tags" -Description: "Check if Elastic beanstalk applications have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_elastic_beanstalk_application\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_elastic_beanstalk_application ListOfTables: - aws_elastic_beanstalk_application Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_elastic_beanstalk_application + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_elastic_beanstalk_application + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Elastic beanstalk applications should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_elastic_beanstalk_environment_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_elastic_beanstalk_environment_mandatory.yaml old mode 100755 new mode 100644 index f8e09488b..5dba01a7a --- a/compliance/controls/aws/aws_mandatory_sql_elastic_beanstalk_environment_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_elastic_beanstalk_environment_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Elastic beanstalk environments have mandatory tags. ID: aws_mandatory_sql_elastic_beanstalk_environment_mandatory -Title: "Elastic beanstalk environments should have mandatory tags" -Description: "Check if Elastic beanstalk environments have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_elastic_beanstalk_environment\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_elastic_beanstalk_environment ListOfTables: - aws_elastic_beanstalk_environment Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_elastic_beanstalk_environment + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_elastic_beanstalk_environment + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Elastic beanstalk environments should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_elasticache_cluster_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_elasticache_cluster_mandatory.yaml old mode 100755 new mode 100644 index d7d4f942e..564e54cf6 --- a/compliance/controls/aws/aws_mandatory_sql_elasticache_cluster_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_elasticache_cluster_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if ElastiCache clusters have mandatory tags. ID: aws_mandatory_sql_elasticache_cluster_mandatory -Title: "ElastiCache clusters should have mandatory tags" -Description: "Check if ElastiCache clusters have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_elasticache_cluster\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_elasticache_cluster ListOfTables: - aws_elasticache_cluster Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_elasticache_cluster + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_elasticache_cluster + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(array(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: ElastiCache clusters should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_elasticsearch_domain_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_elasticsearch_domain_mandatory.yaml old mode 100755 new mode 100644 index cbbc90938..b1c207eab --- a/compliance/controls/aws/aws_mandatory_sql_elasticsearch_domain_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_elasticsearch_domain_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if ElasticSearch domains have mandatory tags. ID: aws_mandatory_sql_elasticsearch_domain_mandatory -Title: "ElasticSearch domains should have mandatory tags" -Description: "Check if ElasticSearch domains have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_elasticsearch_domain\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_elasticsearch_domain ListOfTables: - aws_elasticsearch_domain Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_elasticsearch_domain + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_elasticsearch_domain + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: ElasticSearch domains should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_eventbridge_rule_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_eventbridge_rule_mandatory.yaml old mode 100755 new mode 100644 index d6c66fcfb..b08616761 --- a/compliance/controls/aws/aws_mandatory_sql_eventbridge_rule_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_eventbridge_rule_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if EventBridge rules have mandatory tags. ID: aws_mandatory_sql_eventbridge_rule_mandatory -Title: "EventBridge rules should have mandatory tags" -Description: "Check if EventBridge rules have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_eventbridge_rule\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_eventbridge_rule ListOfTables: - aws_eventbridge_rule Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_eventbridge_rule + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_eventbridge_rule + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: EventBridge rules should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_guardduty_detector_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_guardduty_detector_mandatory.yaml old mode 100755 new mode 100644 index d9506a6cf..3a1ef3a65 --- a/compliance/controls/aws/aws_mandatory_sql_guardduty_detector_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_guardduty_detector_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if GuardDuty detectors have mandatory tags. ID: aws_mandatory_sql_guardduty_detector_mandatory -Title: "GuardDuty detectors should have mandatory tags" -Description: "Check if GuardDuty detectors have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_guardduty_detector\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_guardduty_detector ListOfTables: - aws_guardduty_detector Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_guardduty_detector + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_guardduty_detector + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: GuardDuty detectors should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_iam_role_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_iam_role_mandatory.yaml old mode 100755 new mode 100644 index d649e683e..feb8fcd2b --- a/compliance/controls/aws/aws_mandatory_sql_iam_role_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_iam_role_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if IAM roles have mandatory tags. ID: aws_mandatory_sql_iam_role_mandatory -Title: "IAM roles should have mandatory tags" -Description: "Check if IAM roles have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_iam_role\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_iam_role ListOfTables: - aws_iam_role Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_iam_role + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM roles should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_iam_server_certificate_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_iam_server_certificate_mandatory.yaml old mode 100755 new mode 100644 index c00a330e9..3fd0319af --- a/compliance/controls/aws/aws_mandatory_sql_iam_server_certificate_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_iam_server_certificate_mandatory.yaml @@ -1,16 +1,53 @@ +Description: Check if IAM server certificates have mandatory tags. ID: aws_mandatory_sql_iam_server_certificate_mandatory -Title: "IAM server certificates should have mandatory tags" -Description: "Check if IAM server certificates have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_iam_server_certificate\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY( + SELECT jsonb_object_keys(tags) + ) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_iam_server_certificate + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string( + ARRAY( + SELECT jsonb_array_elements_text(missing_tags) + ), ', ' + ) || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM server certificates should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_iam_user_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_iam_user_mandatory.yaml old mode 100755 new mode 100644 index 121cccd28..e2bfe4e5b --- a/compliance/controls/aws/aws_mandatory_sql_iam_user_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_iam_user_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if IAM users have mandatory tags. ID: aws_mandatory_sql_iam_user_mandatory -Title: "IAM users should have mandatory tags" -Description: "Check if IAM users have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_iam_user\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_iam_user + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_iam_user + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM users should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_inspector_assessment_template_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_inspector_assessment_template_mandatory.yaml old mode 100755 new mode 100644 index f9d108635..ec9023b85 --- a/compliance/controls/aws/aws_mandatory_sql_inspector_assessment_template_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_inspector_assessment_template_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Inspector assessment templates have mandatory tags. ID: aws_mandatory_sql_inspector_assessment_template_mandatory -Title: "Inspector assessment templates should have mandatory tags" -Description: "Check if Inspector assessment templates have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_inspector_assessment_template\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_inspector_assessment_template ListOfTables: - aws_inspector_assessment_template Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_inspector_assessment_template + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_inspector_assessment_template + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Inspector assessment templates should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_kinesis_firehose_delivery_stream_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_kinesis_firehose_delivery_stream_mandatory.yaml old mode 100755 new mode 100644 index 49b7593b0..5d3d8dfb8 --- a/compliance/controls/aws/aws_mandatory_sql_kinesis_firehose_delivery_stream_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_kinesis_firehose_delivery_stream_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Kinesis firehose delivery streams have mandatory tags. ID: aws_mandatory_sql_kinesis_firehose_delivery_stream_mandatory -Title: "Kinesis firehose delivery streams should have mandatory tags" -Description: "Check if Kinesis firehose delivery streams have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_kinesis_firehose_delivery_stream\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_kinesis_firehose_delivery_stream ListOfTables: - aws_kinesis_firehose_delivery_stream Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_kinesis_firehose_delivery_stream + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_kinesis_firehose_delivery_stream + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Kinesis firehose delivery streams should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_kms_key_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_kms_key_mandatory.yaml old mode 100755 new mode 100644 index 38e932819..59dd1a167 --- a/compliance/controls/aws/aws_mandatory_sql_kms_key_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_kms_key_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if KMS keys have mandatory tags. ID: aws_mandatory_sql_kms_key_mandatory -Title: "KMS keys should have mandatory tags" -Description: "Check if KMS keys have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_kms_key\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_kms_key ListOfTables: - aws_kms_key Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_kms_key + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_kms_key + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: KMS keys should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_lambda_function_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_lambda_function_mandatory.yaml old mode 100755 new mode 100644 index 8ecf8c295..fc7812c38 --- a/compliance/controls/aws/aws_mandatory_sql_lambda_function_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_lambda_function_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Lambda functions have mandatory tags. ID: aws_mandatory_sql_lambda_function_mandatory -Title: "Lambda functions should have mandatory tags" -Description: "Check if Lambda functions have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_lambda_function\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_lambda_function ListOfTables: - aws_lambda_function Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_lambda_function + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_lambda_function + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Lambda functions should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_mandatory.yaml old mode 100755 new mode 100644 index 67f5c5f35..fe53d0220 --- a/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if RDS DB clusters have mandatory tags. ID: aws_mandatory_sql_rds_db_cluster_mandatory -Title: "RDS DB clusters should have mandatory tags" -Description: "Check if RDS DB clusters have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_rds_db_cluster\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_rds_db_cluster + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB clusters should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_parameter_group_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_parameter_group_mandatory.yaml old mode 100755 new mode 100644 index 1beb6c83a..4db12e96f --- a/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_parameter_group_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_parameter_group_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if RDS DB cluster parameter groups have mandatory tags. ID: aws_mandatory_sql_rds_db_cluster_parameter_group_mandatory -Title: "RDS DB cluster parameter groups should have mandatory tags" -Description: "Check if RDS DB cluster parameter groups have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_rds_db_cluster_parameter_group\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_rds_db_cluster_parameter_group ListOfTables: - aws_rds_db_cluster_parameter_group Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_rds_db_cluster_parameter_group + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_rds_db_cluster_parameter_group + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB cluster parameter groups should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_snapshot_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_snapshot_mandatory.yaml old mode 100755 new mode 100644 index 5e7f34fc2..5b1635319 --- a/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_snapshot_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_rds_db_cluster_snapshot_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if RDS DB cluster snapshots have mandatory tags. ID: aws_mandatory_sql_rds_db_cluster_snapshot_mandatory -Title: "RDS DB cluster snapshots should have mandatory tags" -Description: "Check if RDS DB cluster snapshots have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_rds_db_cluster_snapshot\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_rds_db_cluster_snapshot ListOfTables: - aws_rds_db_cluster_snapshot Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_rds_db_cluster_snapshot + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_rds_db_cluster_snapshot + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB cluster snapshots should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_rds_db_instance_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_rds_db_instance_mandatory.yaml old mode 100755 new mode 100644 index 55af7cf81..a8453e990 --- a/compliance/controls/aws/aws_mandatory_sql_rds_db_instance_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_rds_db_instance_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if RDS DB instances have mandatory tags. ID: aws_mandatory_sql_rds_db_instance_mandatory -Title: "RDS DB instances should have mandatory tags" -Description: "Check if RDS DB instances have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_rds_db_instance\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_rds_db_instance + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB instances should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_rds_db_option_group_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_rds_db_option_group_mandatory.yaml old mode 100755 new mode 100644 index 6777e8573..f4acc97bb --- a/compliance/controls/aws/aws_mandatory_sql_rds_db_option_group_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_rds_db_option_group_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if RDS DB option groups have mandatory tags. ID: aws_mandatory_sql_rds_db_option_group_mandatory -Title: "RDS DB option groups should have mandatory tags" -Description: "Check if RDS DB option groups have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_rds_db_option_group\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_rds_db_option_group ListOfTables: - aws_rds_db_option_group Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_rds_db_option_group + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_rds_db_option_group + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB option groups should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_rds_db_parameter_group_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_rds_db_parameter_group_mandatory.yaml old mode 100755 new mode 100644 index f71e1acb9..94381ef8d --- a/compliance/controls/aws/aws_mandatory_sql_rds_db_parameter_group_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_rds_db_parameter_group_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if RDS DB parameter groups have mandatory tags. ID: aws_mandatory_sql_rds_db_parameter_group_mandatory -Title: "RDS DB parameter groups should have mandatory tags" -Description: "Check if RDS DB parameter groups have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_rds_db_parameter_group\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_rds_db_parameter_group ListOfTables: - aws_rds_db_parameter_group Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_rds_db_parameter_group + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_rds_db_parameter_group + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB parameter groups should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_rds_db_snapshot_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_rds_db_snapshot_mandatory.yaml old mode 100755 new mode 100644 index 71dee4d85..0a1cf1272 --- a/compliance/controls/aws/aws_mandatory_sql_rds_db_snapshot_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_rds_db_snapshot_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if RDS DB snapshots have mandatory tags. ID: aws_mandatory_sql_rds_db_snapshot_mandatory -Title: "RDS DB snapshots should have mandatory tags" -Description: "Check if RDS DB snapshots have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_rds_db_snapshot\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_rds_db_snapshot ListOfTables: - aws_rds_db_snapshot Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_rds_db_snapshot + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT JSONB_OBJECT_KEYS(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_rds_db_snapshot + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT JSONB_ARRAY_ELEMENTS_TEXT(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB snapshots should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_rds_db_subnet_group_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_rds_db_subnet_group_mandatory.yaml old mode 100755 new mode 100644 index da3c40b8e..0eeb660a2 --- a/compliance/controls/aws/aws_mandatory_sql_rds_db_subnet_group_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_rds_db_subnet_group_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if RDS DB subnet groups have mandatory tags. ID: aws_mandatory_sql_rds_db_subnet_group_mandatory -Title: "RDS DB subnet groups should have mandatory tags" -Description: "Check if RDS DB subnet groups have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_rds_db_subnet_group\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_rds_db_subnet_group ListOfTables: - aws_rds_db_subnet_group Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_rds_db_subnet_group + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_rds_db_subnet_group + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB subnet groups should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_redshift_cluster_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_redshift_cluster_mandatory.yaml old mode 100755 new mode 100644 index c135795f7..734c149b6 --- a/compliance/controls/aws/aws_mandatory_sql_redshift_cluster_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_redshift_cluster_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Redshift clusters have mandatory tags. ID: aws_mandatory_sql_redshift_cluster_mandatory -Title: "Redshift clusters should have mandatory tags" -Description: "Check if Redshift clusters have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_redshift_cluster\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_redshift_cluster + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Redshift clusters should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_route53_domain_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_route53_domain_mandatory.yaml old mode 100755 new mode 100644 index ad6974953..cf386b72a --- a/compliance/controls/aws/aws_mandatory_sql_route53_domain_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_route53_domain_mandatory.yaml @@ -1,16 +1,51 @@ +Description: Check if Route53 domains have mandatory tags. ID: aws_mandatory_sql_route53_domain_mandatory -Title: "Route53 domains should have mandatory tags" -Description: "Check if Route53 domains have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_route53_domain\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_route53_domain ListOfTables: - aws_route53_domain Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_route53_domain + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY( + SELECT jsonb_object_keys(tags) + ) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_route53_domain + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING( + ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ' + ) || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Route53 domains should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_route53_resolver_endpoint_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_route53_resolver_endpoint_mandatory.yaml old mode 100755 new mode 100644 index ba9b57ae3..96826e689 --- a/compliance/controls/aws/aws_mandatory_sql_route53_resolver_endpoint_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_route53_resolver_endpoint_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Route 53 Resolver endpoints have mandatory tags. ID: aws_mandatory_sql_route53_resolver_endpoint_mandatory -Title: "Route 53 Resolver endpoints should have mandatory tags" -Description: "Check if Route 53 Resolver endpoints have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_route53_resolver_endpoint\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_route53_resolver_endpoint ListOfTables: - aws_route53_resolver_endpoint Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_route53_resolver_endpoint + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_route53_resolver_endpoint + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Route 53 Resolver endpoints should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_s3_bucket_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_s3_bucket_mandatory.yaml old mode 100755 new mode 100644 index 257e9bc4f..ffe99e285 --- a/compliance/controls/aws/aws_mandatory_sql_s3_bucket_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_s3_bucket_mandatory.yaml @@ -1,16 +1,48 @@ +Description: Check if S3 buckets have mandatory tags. ID: aws_mandatory_sql_s3_bucket_mandatory -Title: "S3 buckets should have mandatory tags" -Description: "Check if S3 buckets have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_s3_bucket\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_s3_bucket + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string( + ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: S3 buckets should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_sagemaker_endpoint_configuration_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_sagemaker_endpoint_configuration_mandatory.yaml old mode 100755 new mode 100644 index 068572f59..9257fb9a1 --- a/compliance/controls/aws/aws_mandatory_sql_sagemaker_endpoint_configuration_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_sagemaker_endpoint_configuration_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if SageMaker endpoint configurations have mandatory tags. ID: aws_mandatory_sql_sagemaker_endpoint_configuration_mandatory -Title: "SageMaker endpoint configurations should have mandatory tags" -Description: "Check if SageMaker endpoint configurations have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_sagemaker_endpoint_configuration\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_sagemaker_endpoint_configuration ListOfTables: - aws_sagemaker_endpoint_configuration Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_sagemaker_endpoint_configuration + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_sagemaker_endpoint_configuration + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker endpoint configurations should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_sagemaker_model_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_sagemaker_model_mandatory.yaml old mode 100755 new mode 100644 index bbbbe1c6c..34631d69c --- a/compliance/controls/aws/aws_mandatory_sql_sagemaker_model_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_sagemaker_model_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if SageMaker models have mandatory tags. ID: aws_mandatory_sql_sagemaker_model_mandatory -Title: "SageMaker models should have mandatory tags" -Description: "Check if SageMaker models have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_sagemaker_model\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_sagemaker_model ListOfTables: - aws_sagemaker_model Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_sagemaker_model + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_sagemaker_model + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker models should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_sagemaker_notebook_instance_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_sagemaker_notebook_instance_mandatory.yaml old mode 100755 new mode 100644 index 39d67cf98..aca7e82f5 --- a/compliance/controls/aws/aws_mandatory_sql_sagemaker_notebook_instance_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_sagemaker_notebook_instance_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if SageMaker notebook instances have mandatory tags. ID: aws_mandatory_sql_sagemaker_notebook_instance_mandatory -Title: "SageMaker notebook instances should have mandatory tags" -Description: "Check if SageMaker notebook instances have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_sagemaker_notebook_instance\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_sagemaker_notebook_instance ListOfTables: - aws_sagemaker_notebook_instance Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_sagemaker_notebook_instance + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_sagemaker_notebook_instance + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker notebook instances should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_sagemaker_training_job_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_sagemaker_training_job_mandatory.yaml old mode 100755 new mode 100644 index 693b71734..438bf218f --- a/compliance/controls/aws/aws_mandatory_sql_sagemaker_training_job_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_sagemaker_training_job_mandatory.yaml @@ -1,16 +1,52 @@ +Description: Check if SageMaker training jobs have mandatory tags. ID: aws_mandatory_sql_sagemaker_training_job_mandatory -Title: "SageMaker training jobs should have mandatory tags" -Description: "Check if SageMaker training jobs have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_sagemaker_training_job\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_sagemaker_training_job ListOfTables: - aws_sagemaker_training_job Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_sagemaker_training_job + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY( + SELECT jsonb_object_keys(tags) + ) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_sagemaker_training_job + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING( + ARRAY( + SELECT jsonb_array_elements_text(missing_tags) + ), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker training jobs should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_secretsmanager_secret_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_secretsmanager_secret_mandatory.yaml old mode 100755 new mode 100644 index 86334ca0a..5e834f237 --- a/compliance/controls/aws/aws_mandatory_sql_secretsmanager_secret_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_secretsmanager_secret_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if Secrets Manager secrets have mandatory tags. ID: aws_mandatory_sql_secretsmanager_secret_mandatory -Title: "Secrets Manager secrets should have mandatory tags" -Description: "Check if Secrets Manager secrets have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_secretsmanager_secret\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_secretsmanager_secret + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(array(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: Secrets Manager secrets should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_ssm_parameter_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_ssm_parameter_mandatory.yaml old mode 100755 new mode 100644 index 39c46bcd8..9a7d43f01 --- a/compliance/controls/aws/aws_mandatory_sql_ssm_parameter_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_ssm_parameter_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if SSM parameters have mandatory tags. ID: aws_mandatory_sql_ssm_parameter_mandatory -Title: "SSM parameters should have mandatory tags" -Description: "Check if SSM parameters have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_ssm_parameter\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_ssm_parameter ListOfTables: - aws_ssm_parameter Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_ssm_parameter + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_ssm_parameter + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: SSM parameters should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_vpc_eip_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_vpc_eip_mandatory.yaml old mode 100755 new mode 100644 index cda153327..56dca009e --- a/compliance/controls/aws/aws_mandatory_sql_vpc_eip_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_vpc_eip_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if VPC elastic IP addresses have mandatory tags. ID: aws_mandatory_sql_vpc_eip_mandatory -Title: "VPC elastic IP addresses should have mandatory tags" -Description: "Check if VPC elastic IP addresses have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_vpc_eip\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_vpc_eip ListOfTables: - aws_vpc_eip Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_vpc_eip + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_vpc_eip + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC elastic IP addresses should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_vpc_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_vpc_mandatory.yaml old mode 100755 new mode 100644 index 5b76ac120..1bf351b83 --- a/compliance/controls/aws/aws_mandatory_sql_vpc_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_vpc_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if VPCs have mandatory tags. ID: aws_mandatory_sql_vpc_mandatory -Title: "VPCs should have mandatory tags" -Description: "Check if VPCs have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_vpc\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_vpc ListOfTables: - aws_vpc Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_vpc + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_vpc + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPCs should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_vpc_nat_gateway_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_vpc_nat_gateway_mandatory.yaml old mode 100755 new mode 100644 index f04224972..ea22d3d90 --- a/compliance/controls/aws/aws_mandatory_sql_vpc_nat_gateway_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_vpc_nat_gateway_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if VPC NAT gateways have mandatory tags. ID: aws_mandatory_sql_vpc_nat_gateway_mandatory -Title: "VPC NAT gateways should have mandatory tags" -Description: "Check if VPC NAT gateways have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_vpc_nat_gateway\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_vpc_nat_gateway ListOfTables: - aws_vpc_nat_gateway Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_vpc_nat_gateway + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_vpc_nat_gateway + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC NAT gateways should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_vpc_network_acl_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_vpc_network_acl_mandatory.yaml old mode 100755 new mode 100644 index 71a91342b..a3d0cb2f8 --- a/compliance/controls/aws/aws_mandatory_sql_vpc_network_acl_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_vpc_network_acl_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if VPC network ACLs have mandatory tags. ID: aws_mandatory_sql_vpc_network_acl_mandatory -Title: "VPC network ACLs should have mandatory tags" -Description: "Check if VPC network ACLs have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_vpc_network_acl\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_vpc_network_acl ListOfTables: - aws_vpc_network_acl Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_vpc_network_acl + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_vpc_network_acl + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC network ACLs should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_vpc_security_group_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_vpc_security_group_mandatory.yaml old mode 100755 new mode 100644 index c1b914898..5ca5a2308 --- a/compliance/controls/aws/aws_mandatory_sql_vpc_security_group_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_vpc_security_group_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if VPC security groups have mandatory tags. ID: aws_mandatory_sql_vpc_security_group_mandatory -Title: "VPC security groups should have mandatory tags" -Description: "Check if VPC security groups have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_vpc_security_group\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_vpc_security_group + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC security groups should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_vpc_vpn_connection_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_vpc_vpn_connection_mandatory.yaml old mode 100755 new mode 100644 index dec4e632c..30f32ac40 --- a/compliance/controls/aws/aws_mandatory_sql_vpc_vpn_connection_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_vpc_vpn_connection_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if VPC VPN connections have mandatory tags. ID: aws_mandatory_sql_vpc_vpn_connection_mandatory -Title: "VPC VPN connections should have mandatory tags" -Description: "Check if VPC VPN connections have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_vpc_vpn_connection\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_vpc_vpn_connection ListOfTables: - aws_vpc_vpn_connection Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_vpc_vpn_connection + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_vpc_vpn_connection + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC VPN connections should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_wafv2_ip_set_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_wafv2_ip_set_mandatory.yaml old mode 100755 new mode 100644 index 77a724331..0fc08e20d --- a/compliance/controls/aws/aws_mandatory_sql_wafv2_ip_set_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_wafv2_ip_set_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if WAFV2 ip sets have mandatory tags. ID: aws_mandatory_sql_wafv2_ip_set_mandatory -Title: "WAFV2 ip sets should have mandatory tags" -Description: "Check if WAFV2 ip sets have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_wafv2_ip_set\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_wafv2_ip_set ListOfTables: - aws_wafv2_ip_set Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_wafv2_ip_set + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.awsMandatoryTags}}'::TEXT[]) - ARRAY(SELECT JSONB_OBJECT_KEYS(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_wafv2_ip_set + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT JSONB_ARRAY_ELEMENTS_TEXT(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: WAFV2 ip sets should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_wafv2_regex_pattern_set_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_wafv2_regex_pattern_set_mandatory.yaml old mode 100755 new mode 100644 index 92f804bfb..c96cba4a1 --- a/compliance/controls/aws/aws_mandatory_sql_wafv2_regex_pattern_set_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_wafv2_regex_pattern_set_mandatory.yaml @@ -1,16 +1,48 @@ +Description: Check if WAFV2 regex pattern sets have mandatory tags. ID: aws_mandatory_sql_wafv2_regex_pattern_set_mandatory -Title: "WAFV2 regex pattern sets should have mandatory tags" -Description: "Check if WAFV2 regex pattern sets have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_wafv2_regex_pattern_set\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_wafv2_regex_pattern_set ListOfTables: - aws_wafv2_regex_pattern_set Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_wafv2_regex_pattern_set + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_wafv2_regex_pattern_set + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string( + ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: WAFV2 regex pattern sets should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_wafv2_rule_group_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_wafv2_rule_group_mandatory.yaml old mode 100755 new mode 100644 index 9a1926168..4d9e5f751 --- a/compliance/controls/aws/aws_mandatory_sql_wafv2_rule_group_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_wafv2_rule_group_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if WAFV2 rule groups have mandatory tags. ID: aws_mandatory_sql_wafv2_rule_group_mandatory -Title: "WAFV2 rule groups should have mandatory tags" -Description: "Check if WAFV2 rule groups have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_wafv2_rule_group\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_wafv2_rule_group ListOfTables: - aws_wafv2_rule_group Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_wafv2_rule_group + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_wafv2_rule_group + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: WAFV2 rule groups should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mandatory_sql_wafv2_web_acl_mandatory.yaml b/compliance/controls/aws/aws_mandatory_sql_wafv2_web_acl_mandatory.yaml old mode 100755 new mode 100644 index 332c39842..6c79e2c9a --- a/compliance/controls/aws/aws_mandatory_sql_wafv2_web_acl_mandatory.yaml +++ b/compliance/controls/aws/aws_mandatory_sql_wafv2_web_acl_mandatory.yaml @@ -1,16 +1,47 @@ +Description: Check if WAFV2 web acls have mandatory tags. ID: aws_mandatory_sql_wafv2_web_acl_mandatory -Title: "WAFV2 web acls should have mandatory tags" -Description: "Check if WAFV2 web acls have mandatory tags." +IntegrationType: + - aws_cloud_account Query: Engine: steampipe-v0.5 - QueryToExecute: "with analysis as (\n select\n og_account_id,\n og_resource_id,\n arn,\n title,\n tags ?& '{{.awsMandatoryTags}}'::text[] as has_mandatory_tags,\n to_jsonb('{{.awsMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags,\n region,\n account_id,\n tags,\n _ctx\n from\n aws_wafv2_web_acl\n)\nselect\n og_account_id,\n og_resource_id,\n arn as resource,\n case\n when has_mandatory_tags then 'ok'\n else 'alarm'\n end as status,\n case\n when has_mandatory_tags then title || ' has all mandatory tags.'\n else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.'\n end as reason\n \n , region, account_id\nfrom\n analysis;\n" - PrimaryTable: aws_wafv2_web_acl ListOfTables: - aws_wafv2_web_acl Parameters: - key: awsMandatoryTags required: true + PrimaryTable: aws_wafv2_web_acl + QueryToExecute: | + WITH analysis AS ( + SELECT + og_account_id, + og_resource_id, + arn, + title, + tags ?& '{{.awsMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.awsMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + region, + account_id, + tags, + _ctx + FROM + aws_wafv2_web_acl + ) + SELECT + og_account_id, + og_resource_id, + arn AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + region, + account_id + FROM + analysis; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: WAFV2 web acls should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/aws/aws_mq_broker_restrict_public_access.yaml b/compliance/controls/aws/aws_mq_broker_restrict_public_access.yaml old mode 100755 new mode 100644 index 32636179f..6f5342e81 --- a/compliance/controls/aws/aws_mq_broker_restrict_public_access.yaml +++ b/compliance/controls/aws/aws_mq_broker_restrict_public_access.yaml @@ -1,14 +1,28 @@ +Description: Ensure whether MQ broker is not publicly accessible. The rule is compliant if the MQ broker is publicly accessible. ID: aws_mq_broker_restrict_public_access -Title: "MQ brokers should restrict public access" -Description: "Ensure whether MQ broker is not publicly accessible. The rule is compliant if the MQ broker is publicly accessible." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when publicly_accessible then 'alarm'\n else 'ok'\n end as status,\n case\n when publicly_accessible then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end as reason\n \nfrom\n aws_mq_broker;" - PrimaryTable: aws_mq_broker ListOfTables: - aws_mq_broker Parameters: [] + PrimaryTable: aws_mq_broker + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason + FROM + aws_mq_broker; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: MQ brokers should restrict public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_msk_cluster_encryption_in_transit_with_tls_enabled.yaml b/compliance/controls/aws/aws_msk_cluster_encryption_in_transit_with_tls_enabled.yaml old mode 100755 new mode 100644 index 3165fcac6..ac718af2c --- a/compliance/controls/aws/aws_msk_cluster_encryption_in_transit_with_tls_enabled.yaml +++ b/compliance/controls/aws/aws_msk_cluster_encryption_in_transit_with_tls_enabled.yaml @@ -1,14 +1,28 @@ +Description: This controls checks if an Amazon MSK cluster is encrypted in transit with HTTPS (TLS) among the broker nodes of the cluster. The control fails if plain text communication is enabled for a cluster broker node connection. ID: aws_msk_cluster_encryption_in_transit_with_tls_enabled -Title: "MSK clusters should be encrypted in transit among broker nodes" -Description: "This controls checks if an Amazon MSK cluster is encrypted in transit with HTTPS (TLS) among the broker nodes of the cluster. The control fails if plain text communication is enabled for a cluster broker node connection." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when provisioned -> 'EncryptionInfo' -> 'EncryptionInTransit' ->> 'ClientBroker' = 'TLS' then 'ok'\n else 'alarm'\n end as status,\n case\n when provisioned -> 'EncryptionInfo' -> 'EncryptionInTransit' ->> 'ClientBroker' = 'TLS' then title || ' encryption in transit enabled with TLS.'\n else title || ' encryption in transit enabled with plaintext.'\n end as reason\n \n \nfrom\n aws_msk_cluster;" - PrimaryTable: aws_msk_cluster ListOfTables: - aws_msk_cluster Parameters: [] + PrimaryTable: aws_msk_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN provisioned -> 'EncryptionInfo' -> 'EncryptionInTransit' ->> 'ClientBroker' = 'TLS' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN provisioned -> 'EncryptionInfo' -> 'EncryptionInTransit' ->> 'ClientBroker' = 'TLS' THEN title || ' encryption in transit enabled with TLS.' + ELSE title || ' encryption in transit enabled with plaintext.' + END AS reason + FROM + aws_msk_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: MSK clusters should be encrypted in transit among broker nodes \ No newline at end of file diff --git a/compliance/controls/aws/aws_neptune_db_cluster_audit_logging_enabled.yaml b/compliance/controls/aws/aws_neptune_db_cluster_audit_logging_enabled.yaml old mode 100755 new mode 100644 index 6ac8e0f4a..74770701d --- a/compliance/controls/aws/aws_neptune_db_cluster_audit_logging_enabled.yaml +++ b/compliance/controls/aws/aws_neptune_db_cluster_audit_logging_enabled.yaml @@ -1,14 +1,29 @@ +Description: This control checks whether a Neptune DB cluster publishes audit logs to AWS CloudWatch Logs. The control fails if a Neptune DB cluster doesn't publish audit logs to CloudWatch Logs. EnableCloudWatchLogsExport should be set to Audit. ID: aws_neptune_db_cluster_audit_logging_enabled -Title: "Neptune DB clusters should publish audit logs to CloudWatch Logs" -Description: "This control checks whether a Neptune DB cluster publishes audit logs to AWS CloudWatch Logs. The control fails if a Neptune DB cluster doesn't publish audit logs to CloudWatch Logs. EnableCloudWatchLogsExport should be set to Audit." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n engine,\n case\n when enabled_cloudwatch_logs_exports @> '[\"audit\"]' then 'ok'\n else 'alarm'\n end as status,\n case\n when enabled_cloudwatch_logs_exports @> '[\"audit\"]' then title || ' audit logging enabled.'\n else title || ' audit logging disabled.'\n end as reason\n \n \nfrom\n aws_neptune_db_cluster;" - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + engine, + CASE + WHEN enabled_cloudwatch_logs_exports @> '["audit"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled_cloudwatch_logs_exports @> '["audit"]' THEN title || ' audit logging enabled.' + ELSE title || ' audit logging disabled.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Neptune DB clusters should publish audit logs to CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_neptune_db_cluster_automated_backup_enabled.yaml b/compliance/controls/aws/aws_neptune_db_cluster_automated_backup_enabled.yaml old mode 100755 new mode 100644 index 4d243f746..defbbfc87 --- a/compliance/controls/aws/aws_neptune_db_cluster_automated_backup_enabled.yaml +++ b/compliance/controls/aws/aws_neptune_db_cluster_automated_backup_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether a Neptune DB cluster has automated backups enabled, and a backup retention period greater than or equal to 7 days. The control fails if backups aren't enabled for the Neptune DB cluster, or if the retention period is less than 7 days. ID: aws_neptune_db_cluster_automated_backup_enabled -Title: "Neptune DB clusters should have automated backups enabled" -Description: "This control checks whether a Neptune DB cluster has automated backups enabled, and a backup retention period greater than or equal to 7 days. The control fails if backups aren't enabled for the Neptune DB cluster, or if the retention period is less than 7 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when backup_retention_period >= 7 then 'ok' - else 'alarm' - end as status, - case - when backup_retention_period >= 7 then title || ' automated backups enabled.' - else title || ' automated backups disabled.' - end as reason - from - aws_neptune_db_cluster; - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN backup_retention_period >= 7 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN backup_retention_period >= 7 THEN title || ' automated backups enabled.' + ELSE title || ' automated backups disabled.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Neptune DB clusters should have automated backups enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_neptune_db_cluster_copy_tags_to_snapshot_enabled.yaml b/compliance/controls/aws/aws_neptune_db_cluster_copy_tags_to_snapshot_enabled.yaml old mode 100755 new mode 100644 index 93fc250c0..4b1f67e51 --- a/compliance/controls/aws/aws_neptune_db_cluster_copy_tags_to_snapshot_enabled.yaml +++ b/compliance/controls/aws/aws_neptune_db_cluster_copy_tags_to_snapshot_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks if a Neptune DB cluster is configured to copy all tags to snapshots when the snapshots are created. The control fails if a Neptune DB cluster isn't configured to copy tags to snapshots. ID: aws_neptune_db_cluster_copy_tags_to_snapshot_enabled -Title: "Neptune DB clusters should be configured to copy tags to snapshots" -Description: "This control checks if a Neptune DB cluster is configured to copy all tags to snapshots when the snapshots are created. The control fails if a Neptune DB cluster isn't configured to copy tags to snapshots." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when copy_tags_to_snapshot then 'ok'\n else 'alarm'\n end as status,\n case\n when copy_tags_to_snapshot then title || ' copy tags to snapshot enabled.'\n else title || ' copy tags to snapshot disabled.'\n end as reason\n \n \nfrom\n aws_neptune_db_cluster;" - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN copy_tags_to_snapshot THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN copy_tags_to_snapshot THEN title || ' copy tags to snapshot enabled.' + ELSE title || ' copy tags to snapshot disabled.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Neptune DB clusters should be configured to copy tags to snapshots \ No newline at end of file diff --git a/compliance/controls/aws/aws_neptune_db_cluster_deletion_protection_enabled.yaml b/compliance/controls/aws/aws_neptune_db_cluster_deletion_protection_enabled.yaml old mode 100755 new mode 100644 index 60a02ce96..a1975d617 --- a/compliance/controls/aws/aws_neptune_db_cluster_deletion_protection_enabled.yaml +++ b/compliance/controls/aws/aws_neptune_db_cluster_deletion_protection_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control checks if a Neptune DB cluster has deletion protection enabled. The control fails if a Neptune DB cluster doesn't have deletion protection enabled. ID: aws_neptune_db_cluster_deletion_protection_enabled -Title: "Neptune DB clusters should have deletion protection enabled" -Description: "This control checks if a Neptune DB cluster has deletion protection enabled. The control fails if a Neptune DB cluster doesn't have deletion protection enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when deletion_protection then 'ok' - else 'alarm' - end as status, - case - when deletion_protection then title || ' deletion protection enabled.' - else title || ' deletion protection disabled.' - end as reason - from - aws_neptune_db_cluster; - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN deletion_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN deletion_protection THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection disabled.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Neptune DB clusters should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_neptune_db_cluster_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_neptune_db_cluster_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index b9ef9d7c9..6339593da --- a/compliance/controls/aws/aws_neptune_db_cluster_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_neptune_db_cluster_encryption_at_rest_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether a Neptune DB cluster is encrypted at rest. The control fails if a Neptune DB cluster isn't encrypted at rest. ID: aws_neptune_db_cluster_encryption_at_rest_enabled -Title: "Neptune DB clusters should be encrypted at rest" -Description: "This control checks whether a Neptune DB cluster is encrypted at rest. The control fails if a Neptune DB cluster isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \nfrom\n aws_neptune_db_cluster;" - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Neptune DB clusters should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_neptune_db_cluster_iam_authentication_enabled.yaml b/compliance/controls/aws/aws_neptune_db_cluster_iam_authentication_enabled.yaml old mode 100755 new mode 100644 index b23a527ea..39570ad08 --- a/compliance/controls/aws/aws_neptune_db_cluster_iam_authentication_enabled.yaml +++ b/compliance/controls/aws/aws_neptune_db_cluster_iam_authentication_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks if a Neptune DB cluster has IAM database authentication enabled. The control fails if IAM database authentication isn't enabled for a Neptune DB cluster. ID: aws_neptune_db_cluster_iam_authentication_enabled -Title: "Neptune DB clusters should have IAM database authentication enabled" -Description: "This control checks if a Neptune DB cluster has IAM database authentication enabled. The control fails if IAM database authentication isn't enabled for a Neptune DB cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when iam_database_authentication_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when iam_database_authentication_enabled then title || ' IAM authentication enabled.'\n else title || ' IAM authentication disabled.'\n end as reason\n \n \nfrom\n aws_neptune_db_cluster;" - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN iam_database_authentication_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN iam_database_authentication_enabled THEN title || ' IAM authentication enabled.' + ELSE title || ' IAM authentication disabled.' + END AS reason + FROM + aws_neptune_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Neptune DB clusters should have IAM database authentication enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_neptune_db_cluster_no_public_subnet.yaml b/compliance/controls/aws/aws_neptune_db_cluster_no_public_subnet.yaml old mode 100755 new mode 100644 index a2ec56941..82859df0e --- a/compliance/controls/aws/aws_neptune_db_cluster_no_public_subnet.yaml +++ b/compliance/controls/aws/aws_neptune_db_cluster_no_public_subnet.yaml @@ -1,94 +1,82 @@ +Description: This control checks if Neptune DB clusters are configured with public subnet as there is a risk of exposing sensitive data. ID: aws_neptune_db_cluster_no_public_subnet -Title: "Neptune DB clusters should not use public_subnet" -Description: "This control checks if Neptune DB clusters are configured with public subnet as there is a risk of exposing sensitive data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with subnets_with_explicit_route as ( - select - distinct ( a ->> 'SubnetId') as all_sub - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a - where - a ->> 'SubnetId' is not null - ), public_subnets_with_explicit_route as ( - select - distinct a ->> 'SubnetId' as SubnetId - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a, - jsonb_array_elements(routes) as r - where - r ->> 'DestinationCidrBlock' = '0.0.0.0/0' - and - ( - r ->> 'GatewayId' like 'igw-%' - or r ->> 'NatGatewayId' like 'nat-%' - ) - and a ->> 'SubnetId' is not null - ), public_subnets_with_implicit_route as ( - select - distinct route_table_id, - vpc_id, - region - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a, - jsonb_array_elements(routes) as r - where - a ->> 'Main' = 'true' - and r ->> 'DestinationCidrBlock' = '0.0.0.0/0' - and ( - r ->> 'GatewayId' like 'igw-%' - or r ->> 'NatGatewayId' like 'nat-%' - ) - ), subnet_accessibility as ( - select - subnet_id, - vpc_id, - case - when s.subnet_id in (select all_sub from subnets_with_explicit_route where all_sub not in (select SubnetId from public_subnets_with_explicit_route )) then 'private' - when p.SubnetId is not null or s.vpc_id in ( select vpc_id from public_subnets_with_implicit_route) then 'public' - else 'private' - end as access - from - aws_vpc_subnet as s - left join public_subnets_with_explicit_route as p on p.SubnetId = s.subnet_id - ), cluster_public_subnet as ( - select - distinct arn, - name as subnet_group_name - from - aws_rds_db_subnet_group, - jsonb_array_elements(subnets) as s - left join subnet_accessibility as a on a.subnet_id = s ->> 'SubnetIdentifier' - where - a.access = 'public' - ) - select - c.arn as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when s.subnet_group_name is not null then 'alarm' - else 'ok' - end as status, - case - when s.subnet_group_name is not null then c.title || ' has public subnet.' - else c.title || ' has private subnet.' - end as reason - from - aws_neptune_db_cluster as c - left join cluster_public_subnet as s on s.subnet_group_name = c.db_subnet_group; - PrimaryTable: aws_neptune_db_cluster ListOfTables: - aws_vpc_route_table - aws_vpc_subnet - aws_rds_db_subnet_group - aws_neptune_db_cluster Parameters: [] + PrimaryTable: aws_neptune_db_cluster + QueryToExecute: | + WITH subnets_with_explicit_route AS ( + SELECT DISTINCT (a ->> 'SubnetId') AS all_sub + FROM aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a + WHERE a ->> 'SubnetId' IS NOT NULL + ), + public_subnets_with_explicit_route AS ( + SELECT DISTINCT a ->> 'SubnetId' AS SubnetId + FROM aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND ( + r ->> 'GatewayId' LIKE 'igw-%' + OR r ->> 'NatGatewayId' LIKE 'nat-%' + ) + AND a ->> 'SubnetId' IS NOT NULL + ), + public_subnets_with_implicit_route AS ( + SELECT DISTINCT route_table_id, + vpc_id, + region + FROM aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE a ->> 'Main' = 'true' + AND r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND ( + r ->> 'GatewayId' LIKE 'igw-%' + OR r ->> 'NatGatewayId' LIKE 'nat-%' + ) + ), + subnet_accessibility AS ( + SELECT subnet_id, + vpc_id, + CASE + WHEN s.subnet_id IN (SELECT all_sub FROM subnets_with_explicit_route WHERE all_sub NOT IN (SELECT SubnetId FROM public_subnets_with_explicit_route)) THEN 'private' + WHEN p.SubnetId IS NOT NULL + OR s.vpc_id IN (SELECT vpc_id FROM public_subnets_with_implicit_route) THEN 'public' + ELSE 'private' + END AS access + FROM aws_vpc_subnet AS s + LEFT JOIN public_subnets_with_explicit_route AS p ON p.SubnetId = s.subnet_id + ), + cluster_public_subnet AS ( + SELECT DISTINCT arn, + name AS subnet_group_name + FROM aws_rds_db_subnet_group, + jsonb_array_elements(subnets) AS s + LEFT JOIN subnet_accessibility AS a ON a.subnet_id = s ->> 'SubnetIdentifier' + WHERE a.access = 'public' + ) + SELECT c.arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN s.subnet_group_name IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.subnet_group_name IS NOT NULL THEN c.title || ' has public subnet.' + ELSE c.title || ' has private subnet.' + END AS reason + FROM aws_neptune_db_cluster AS c + LEFT JOIN cluster_public_subnet AS s ON s.subnet_group_name = c.db_subnet_group; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Neptune DB clusters should not use public_subnet \ No newline at end of file diff --git a/compliance/controls/aws/aws_neptune_db_cluster_snapshot_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_neptune_db_cluster_snapshot_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 1bc890abf..1db5b738c --- a/compliance/controls/aws/aws_neptune_db_cluster_snapshot_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_neptune_db_cluster_snapshot_encryption_at_rest_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether a Neptune DB cluster snapshot is encrypted at rest. The control fails if a Neptune DB cluster isn't encrypted at rest. ID: aws_neptune_db_cluster_snapshot_encryption_at_rest_enabled -Title: "Neptune DB cluster snapshots should be encrypted at rest" -Description: "This control checks whether a Neptune DB cluster snapshot is encrypted at rest. The control fails if a Neptune DB cluster isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - db_cluster_snapshot_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when storage_encrypted then 'ok' - else 'alarm' - end as status, - case - when storage_encrypted then title || ' encrypted at rest.' - else title || ' not encrypted at rest.' - end as reason - from - aws_neptune_db_cluster_snapshot; - PrimaryTable: aws_neptune_db_cluster_snapshot ListOfTables: - aws_neptune_db_cluster_snapshot Parameters: [] + PrimaryTable: aws_neptune_db_cluster_snapshot + QueryToExecute: | + SELECT + db_cluster_snapshot_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_neptune_db_cluster_snapshot; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Neptune DB cluster snapshots should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_neptune_db_cluster_snapshot_prohibit_public_access.yaml b/compliance/controls/aws/aws_neptune_db_cluster_snapshot_prohibit_public_access.yaml old mode 100755 new mode 100644 index 8321adfa7..e4aa4de31 --- a/compliance/controls/aws/aws_neptune_db_cluster_snapshot_prohibit_public_access.yaml +++ b/compliance/controls/aws/aws_neptune_db_cluster_snapshot_prohibit_public_access.yaml @@ -1,14 +1,29 @@ +Description: This control checks whether a Neptune manual DB cluster snapshot is public. The control fails if a Neptune manual DB cluster snapshot is public. ID: aws_neptune_db_cluster_snapshot_prohibit_public_access -Title: "Neptune DB cluster snapshots should not be public" -Description: "This control checks whether a Neptune manual DB cluster snapshot is public. The control fails if a Neptune manual DB cluster snapshot is public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n db_cluster_snapshot_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end reason\n \nfrom\n aws_neptune_db_cluster_snapshot,\n jsonb_array_elements(db_cluster_snapshot_attributes) as cluster_snapshot;" - PrimaryTable: aws_neptune_db_cluster_snapshot ListOfTables: - aws_neptune_db_cluster_snapshot Parameters: [] + PrimaryTable: aws_neptune_db_cluster_snapshot + QueryToExecute: | + SELECT + db_cluster_snapshot_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cluster_snapshot -> 'AttributeValues' = '["all"]' THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN cluster_snapshot -> 'AttributeValues' = '["all"]' THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END reason + FROM + aws_neptune_db_cluster_snapshot, + jsonb_array_elements(db_cluster_snapshot_attributes) AS cluster_snapshot; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Neptune DB cluster snapshots should not be public \ No newline at end of file diff --git a/compliance/controls/aws/aws_networkfirewall_firewall_deletion_protection_enabled.yaml b/compliance/controls/aws/aws_networkfirewall_firewall_deletion_protection_enabled.yaml old mode 100755 new mode 100644 index ca191f675..ddbe90f66 --- a/compliance/controls/aws/aws_networkfirewall_firewall_deletion_protection_enabled.yaml +++ b/compliance/controls/aws/aws_networkfirewall_firewall_deletion_protection_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an AWS Network Firewall firewall has deletion protection enabled. The control fails if deletion protection isn't enabled for a firewall. ID: aws_networkfirewall_firewall_deletion_protection_enabled -Title: "Network Firewall firewalls should have deletion protection enabled" -Description: "This control checks whether an AWS Network Firewall firewall has deletion protection enabled. The control fails if deletion protection isn't enabled for a firewall." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when delete_protection then 'ok' - else 'alarm' - end status, - case - when delete_protection then title || ' delete protection enabled.' - else title || ' delete protection disabled.' - end reason - from - aws_networkfirewall_firewall; - PrimaryTable: aws_networkfirewall_firewall ListOfTables: - aws_networkfirewall_firewall Parameters: [] + PrimaryTable: aws_networkfirewall_firewall + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN delete_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN delete_protection THEN title || ' delete protection enabled.' + ELSE title || ' delete protection disabled.' + END AS reason + FROM + aws_networkfirewall_firewall; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Network Firewall firewalls should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_networkfirewall_firewall_in_vpc.yaml b/compliance/controls/aws/aws_networkfirewall_firewall_in_vpc.yaml old mode 100755 new mode 100644 index 70f3ac6db..7c6f86c3b --- a/compliance/controls/aws/aws_networkfirewall_firewall_in_vpc.yaml +++ b/compliance/controls/aws/aws_networkfirewall_firewall_in_vpc.yaml @@ -1,14 +1,28 @@ +Description: Deploy AWS Networkfirewall firewall within an AWS Virtual Private Cloud (AWS VPC) for a secure communication between a function and other services within the AWS VPC. ID: aws_networkfirewall_firewall_in_vpc -Title: "Networkfirewall firewall should be in a VPC" -Description: "Deploy AWS Networkfirewall firewall within an AWS Virtual Private Cloud (AWS VPC) for a secure communication between a function and other services within the AWS VPC." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when vpc_id is null or vpc_id = '' then 'alarm'\n else 'ok'\n end status,\n case\n when vpc_id is null or vpc_id = '' then title || ' is not in VPC.'\n else title || ' is in VPC ' || vpc_id || '.'\n end reason\n \n \nfrom\n aws_networkfirewall_firewall;" - PrimaryTable: aws_networkfirewall_firewall ListOfTables: - aws_networkfirewall_firewall Parameters: [] + PrimaryTable: aws_networkfirewall_firewall + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_id IS NULL OR vpc_id = '' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vpc_id IS NULL OR vpc_id = '' THEN title || ' is not in VPC.' + ELSE title || ' is in VPC ' || vpc_id || '.' + END AS reason + FROM + aws_networkfirewall_firewall; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Networkfirewall firewall should be in a VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_networkfirewall_firewall_logging_enabled.yaml b/compliance/controls/aws/aws_networkfirewall_firewall_logging_enabled.yaml old mode 100755 new mode 100644 index 220e62922..e552392d3 --- a/compliance/controls/aws/aws_networkfirewall_firewall_logging_enabled.yaml +++ b/compliance/controls/aws/aws_networkfirewall_firewall_logging_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether logging is enabled for an AWS Network Firewall firewall. The control fails if logging isn't enabled for at least one log type or if the logging destination doesn't exist. ID: aws_networkfirewall_firewall_logging_enabled -Title: "Network Firewall logging should be enabled" -Description: "This control checks whether logging is enabled for an AWS Network Firewall firewall. The control fails if logging isn't enabled for at least one log type or if the logging destination doesn't exist." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(logging_configuration) > 0 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(logging_configuration) > 0 then title || ' logging enabled.'\n else title || ' logging disabled.'\n end reason\n \n \nfrom\n aws_networkfirewall_firewall;" - PrimaryTable: aws_networkfirewall_firewall ListOfTables: - aws_networkfirewall_firewall Parameters: [] + PrimaryTable: aws_networkfirewall_firewall + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(logging_configuration) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(logging_configuration) > 0 THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason + FROM + aws_networkfirewall_firewall; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Network Firewall logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_fragmented_packets.yaml b/compliance/controls/aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_fragmented_packets.yaml old mode 100755 new mode 100644 index c55f4c0d1..3ed77bc47 --- a/compliance/controls/aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_fragmented_packets.yaml +++ b/compliance/controls/aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_fragmented_packets.yaml @@ -1,13 +1,32 @@ +Description: This control checks whether the default stateless action for fragmented packets for a Network Firewall policy is drop or forward. The control passes if Drop or Forward is selected, and fails if Pass is selected. ID: aws_networkfirewall_firewall_policy_default_stateless_action_check_fragmented_packets -Title: "The default stateless action for Network Firewall policies should be drop or forward for fragmented packets" -Description: "This control checks whether the default stateless action for fragmented packets for a Network Firewall policy is drop or forward. The control passes if Drop or Forward is selected, and fails if Pass is selected." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when (not (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:drop'\n and not (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:forward_to_sfe') then 'alarm'\n else 'ok'\n end as status,\n case\n when (not (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:drop'\n and not (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:forward_to_sfe') then title || ' stateless action is neither drop nor forward for fragmented packets.'\n else title || ' stateless action is either drop or forward for fragmented packets.'\n end as reason\n \n , region, account_id\nfrom\n aws_networkfirewall_firewall_policy;\n" - PrimaryTable: aws_networkfirewall_firewall_policy ListOfTables: - aws_networkfirewall_firewall_policy Parameters: [] + PrimaryTable: aws_networkfirewall_firewall_policy + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (NOT (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:drop' + AND NOT (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:forward_to_sfe') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (NOT (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:drop' + AND NOT (firewall_policy -> 'StatelessFragmentDefaultActions') ? 'aws:forward_to_sfe') THEN title || ' stateless action is neither drop nor forward for fragmented packets.' + ELSE title || ' stateless action is either drop or forward for fragmented packets.' + END AS reason, + region, + account_id + FROM + aws_networkfirewall_firewall_policy; Severity: medium Tags: aws_foundational_security: @@ -22,5 +41,4 @@ Tags: - aws service: - AWS/NetworkFirewall -IntegrationType: - - aws_cloud_account +Title: The default stateless action for Network Firewall policies should be drop or forward for fragmented packets \ No newline at end of file diff --git a/compliance/controls/aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_full_packets.yaml b/compliance/controls/aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_full_packets.yaml old mode 100755 new mode 100644 index 550330252..c7bf170dc --- a/compliance/controls/aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_full_packets.yaml +++ b/compliance/controls/aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_full_packets.yaml @@ -1,13 +1,34 @@ +Description: A firewall policy defines how your firewall monitors and handles traffic in AWS VPC. You configure stateless and stateful rule groups to filter packets and traffic flows. Defaulting to Pass can allow unintended traffic. ID: aws_networkfirewall_firewall_policy_default_stateless_action_check_full_packets -Title: "The default stateless action for Network Firewall policies should be drop or forward for full packets" -Description: "A firewall policy defines how your firewall monitors and handles traffic in AWS VPC. You configure stateless and stateful rule groups to filter packets and traffic flows. Defaulting to Pass can allow unintended traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when (not (firewall_policy -> 'StatelessDefaultActions') ? 'aws:drop'\n and not (firewall_policy -> 'StatelessDefaultActions') ? 'aws:forward_to_sfe') then 'alarm'\n else 'ok'\n end as status,\n case\n when (not (firewall_policy -> 'StatelessDefaultActions') ? 'aws:drop'\n and not (firewall_policy -> 'StatelessDefaultActions') ? 'aws:forward_to_sfe') then title || ' stateless action is neither drop nor forward for full packets.'\n else title || ' stateless action is either drop or forward for full packets.'\n end as reason\n \n , region, account_id\nfrom\n aws_networkfirewall_firewall_policy;\n" - PrimaryTable: aws_networkfirewall_firewall_policy ListOfTables: - aws_networkfirewall_firewall_policy Parameters: [] + PrimaryTable: aws_networkfirewall_firewall_policy + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (NOT (firewall_policy -> 'StatelessDefaultActions') ? 'aws:drop' + AND NOT (firewall_policy -> 'StatelessDefaultActions') ? 'aws:forward_to_sfe') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (NOT (firewall_policy -> 'StatelessDefaultActions') ? 'aws:drop' + AND NOT (firewall_policy -> 'StatelessDefaultActions') ? 'aws:forward_to_sfe') + THEN title || ' stateless action is neither drop nor forward for full packets.' + ELSE title || ' stateless action is either drop or forward for full packets.' + END AS reason, + region, + account_id + FROM + aws_networkfirewall_firewall_policy; Severity: medium Tags: aws_foundational_security: @@ -22,5 +43,4 @@ Tags: - aws service: - AWS/NetworkFirewall -IntegrationType: - - aws_cloud_account +Title: The default stateless action for Network Firewall policies should be drop or forward for full packets \ No newline at end of file diff --git a/compliance/controls/aws/aws_networkfirewall_firewall_policy_rule_group_not_empty.yaml b/compliance/controls/aws/aws_networkfirewall_firewall_policy_rule_group_not_empty.yaml old mode 100755 new mode 100644 index 748477363..ad9221de3 --- a/compliance/controls/aws/aws_networkfirewall_firewall_policy_rule_group_not_empty.yaml +++ b/compliance/controls/aws/aws_networkfirewall_firewall_policy_rule_group_not_empty.yaml @@ -1,13 +1,32 @@ +Description: This control checks whether a Network Firewall policy has any stateful or stateless rule groups associated. The control fails if stateless or stateful rule groups are not assigned. ID: aws_networkfirewall_firewall_policy_rule_group_not_empty -Title: "Network Firewall policies should have at least one rule group associated" -Description: "This control checks whether a Network Firewall policy has any stateful or stateless rule groups associated. The control fails if stateless or stateful rule groups are not assigned." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when (firewall_policy ->> 'StatefulRuleGroupReferences' is null or jsonb_array_length(firewall_policy -> 'StatefulRuleGroupReferences') = 0)\n and (firewall_policy ->> 'StatelessRuleGroupReferences' is null or jsonb_array_length(firewall_policy -> 'StatelessRuleGroupReferences') = 0) then 'alarm'\n else 'ok'\n end as status,\n case\n when (firewall_policy ->> 'StatefulRuleGroupReferences' is null or jsonb_array_length(firewall_policy -> 'StatefulRuleGroupReferences') = 0)\n and (firewall_policy ->> 'StatelessRuleGroupReferences' is null or jsonb_array_length(firewall_policy -> 'StatelessRuleGroupReferences') = 0) then title || ' has no associated rule groups.'\n else title || ' has associated rule groups.'\n end as reason\n \n , region, account_id\nfrom\n aws_networkfirewall_firewall_policy;\n" - PrimaryTable: aws_networkfirewall_firewall_policy ListOfTables: - aws_networkfirewall_firewall_policy Parameters: [] + PrimaryTable: aws_networkfirewall_firewall_policy + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (firewall_policy ->> 'StatefulRuleGroupReferences' IS NULL OR jsonb_array_length(firewall_policy -> 'StatefulRuleGroupReferences') = 0) + AND (firewall_policy ->> 'StatelessRuleGroupReferences' IS NULL OR jsonb_array_length(firewall_policy -> 'StatelessRuleGroupReferences') = 0) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (firewall_policy ->> 'StatefulRuleGroupReferences' IS NULL OR jsonb_array_length(firewall_policy -> 'StatefulRuleGroupReferences') = 0) + AND (firewall_policy ->> 'StatelessRuleGroupReferences' IS NULL OR jsonb_array_length(firewall_policy -> 'StatelessRuleGroupReferences') = 0) THEN title || ' has no associated rule groups.' + ELSE title || ' has associated rule groups.' + END AS reason, + region, + account_id + FROM + aws_networkfirewall_firewall_policy; Severity: medium Tags: aws_foundational_security: @@ -22,5 +41,4 @@ Tags: - aws service: - AWS/NetworkFirewall -IntegrationType: - - aws_cloud_account +Title: Network Firewall policies should have at least one rule group associated \ No newline at end of file diff --git a/compliance/controls/aws/aws_networkfirewall_stateless_rule_group_not_empty.yaml b/compliance/controls/aws/aws_networkfirewall_stateless_rule_group_not_empty.yaml old mode 100755 new mode 100644 index 87368146d..836a3f285 --- a/compliance/controls/aws/aws_networkfirewall_stateless_rule_group_not_empty.yaml +++ b/compliance/controls/aws/aws_networkfirewall_stateless_rule_group_not_empty.yaml @@ -1,13 +1,31 @@ +Description: A rule group contains rules that define how your firewall processes traffic in your VPC. An empty stateless rule group when present in a firewall policy might give the impression that the rule group will process traffic. However, when the stateless rule group is empty, it does not process traffic. ID: aws_networkfirewall_stateless_rule_group_not_empty -Title: "Stateless network firewall rule group should not be empty" -Description: "A rule group contains rules that define how your firewall processes traffic in your VPC. An empty stateless rule group when present in a firewall policy might give the impression that the rule group will process traffic. However, when the stateless rule group is empty, it does not process traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when type = 'STATEFUL' then 'skip'\n when jsonb_array_length(rules_source -> 'StatelessRulesAndCustomActions' -> 'StatelessRules') > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when type = 'STATEFUL' then title || ' is a stateful rule group.'\n else title || ' has ' || jsonb_array_length(rules_source -> 'StatelessRulesAndCustomActions' -> 'StatelessRules') || ' rule(s).'\n end as reason\n \n , region, account_id\nfrom\n aws_networkfirewall_rule_group;\n" - PrimaryTable: aws_networkfirewall_rule_group ListOfTables: - aws_networkfirewall_rule_group Parameters: [] + PrimaryTable: aws_networkfirewall_rule_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN type = 'STATEFUL' THEN 'skip' + WHEN jsonb_array_length(rules_source -> 'StatelessRulesAndCustomActions' -> 'StatelessRules') > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN type = 'STATEFUL' THEN title || ' is a stateful rule group.' + ELSE title || ' has ' || jsonb_array_length(rules_source -> 'StatelessRulesAndCustomActions' -> 'StatelessRules') || ' rule(s).' + END AS reason, + region, + account_id + FROM + aws_networkfirewall_rule_group; Severity: medium Tags: aws_foundational_security: @@ -22,5 +40,4 @@ Tags: - aws service: - AWS/NetworkFirewall -IntegrationType: - - aws_cloud_account +Title: Stateless network firewall rule group should not be empty \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_audit_logging_enabled.yaml b/compliance/controls/aws/aws_opensearch_domain_audit_logging_enabled.yaml old mode 100755 new mode 100644 index 8ad693f2e..ce491b180 --- a/compliance/controls/aws/aws_opensearch_domain_audit_logging_enabled.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_audit_logging_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether OpenSearch service domains have audit logging enabled. The rule is non-compliant if an OpenSearch service domain does not have audit logging enabled. ID: aws_opensearch_domain_audit_logging_enabled -Title: "OpenSearch domains should have audit logging enabled." -Description: "This control checks whether OpenSearch service domains have audit logging enabled. The rule is non-compliant if an OpenSearch service domain does not have audit logging enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_publishing_options -> 'AUDIT_LOGS' ->> 'Enabled' = 'true' then 'ok'\n else 'ok'\n end as status,\n case\n when log_publishing_options -> 'AUDIT_LOGS' ->> 'Enabled' = 'true' then title || ' audit logging enabled.'\n else title || ' audit logging disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_opensearch_domain;\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_publishing_options -> 'AUDIT_LOGS' ->> 'Enabled' = 'true' THEN 'ok' + ELSE 'ok' + END AS status, + CASE + WHEN log_publishing_options -> 'AUDIT_LOGS' ->> 'Enabled' = 'true' THEN title || ' audit logging enabled.' + ELSE title || ' audit logging disabled.' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/OpenSearch -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains should have audit logging enabled. \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_cognito_authentication_enabled_for_kibana.yaml b/compliance/controls/aws/aws_opensearch_domain_cognito_authentication_enabled_for_kibana.yaml old mode 100755 new mode 100644 index 78ace87c2..732e24e2b --- a/compliance/controls/aws/aws_opensearch_domain_cognito_authentication_enabled_for_kibana.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_cognito_authentication_enabled_for_kibana.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether AWS OpenSearch domain has AWS Cognito authentication for Kibana enabled. AWS Cognito lets you easily add user sign-up and authentication to your mobile and web apps. ID: aws_opensearch_domain_cognito_authentication_enabled_for_kibana -Title: "OpenSearch domains cognito authentication should be enabled for kibana" -Description: "This control checks whether AWS OpenSearch domain has AWS Cognito authentication for Kibana enabled. AWS Cognito lets you easily add user sign-up and authentication to your mobile and web apps." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when cognito_options ->> 'Enabled' = 'true' then 'ok'\n else 'alarm'\n end status,\n case\n when cognito_options ->> 'Enabled' = 'true' then title || ' cognito authentication enabled for kibana.'\n else title || ' cognito authentication disabled for kibana.'\n end reason\n \n \nfrom\n aws_opensearch_domain;" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cognito_options ->> 'Enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cognito_options ->> 'Enabled' = 'true' THEN title || ' cognito authentication enabled for kibana.' + ELSE title || ' cognito authentication disabled for kibana.' + END AS reason + FROM + aws_opensearch_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains cognito authentication should be enabled for kibana \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_data_node_fault_tolerance.yaml b/compliance/controls/aws/aws_opensearch_domain_data_node_fault_tolerance.yaml old mode 100755 new mode 100644 index 1c56cee8c..94246b824 --- a/compliance/controls/aws/aws_opensearch_domain_data_node_fault_tolerance.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_data_node_fault_tolerance.yaml @@ -1,13 +1,38 @@ +Description: This control checks whether OpenSearch domains are configured with at least three data nodes and zoneAwarenessEnabled is true. This control fails for an OpenSearch domain if instanceCount is less than 3 or zoneAwarenessEnabled is false. ID: aws_opensearch_domain_data_node_fault_tolerance -Title: "OpenSearch domains should have at least three data nodes" -Description: "This control checks whether OpenSearch domains are configured with at least three data nodes and zoneAwarenessEnabled is true. This control fails for an OpenSearch domain if instanceCount is less than 3 or zoneAwarenessEnabled is false." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when cluster_config ->> 'ZoneAwarenessEnabled' = 'true' and cluster_config ->> 'InstanceCount' > '2' then 'ok'\n else 'alarm'\n end as status,\n case\n when cluster_config ->> 'ZoneAwarenessEnabled' = 'true' and cluster_config ->> 'InstanceCount' > '2' then title || ' zone awareness is '\n || case when cluster_config ->> 'ZoneAwarenessEnabled' = 'true' then 'enabled' else 'disabled' end || ' with ' || (cluster_config ->> 'InstanceCount') || ' data node(s) configued.'\n else title || ' zone awareness is ' || case when cluster_config ->> 'ZoneAwarenessEnabled' = 'true' then 'enabled' else 'disabled' end || ' with ' || (cluster_config ->> 'InstanceCount') || ' data node(s) configued.'\n end as reason\n \n , region, account_id\nfrom\n aws_opensearch_domain;\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cluster_config ->> 'ZoneAwarenessEnabled' = 'true' AND cluster_config ->> 'InstanceCount' > '2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cluster_config ->> 'ZoneAwarenessEnabled' = 'true' AND cluster_config ->> 'InstanceCount' > '2' THEN title || ' zone awareness is ' || + CASE + WHEN cluster_config ->> 'ZoneAwarenessEnabled' = 'true' THEN 'enabled' + ELSE 'disabled' + END || ' with ' || (cluster_config ->> 'InstanceCount') || ' data node(s) configured.' + ELSE title || ' zone awareness is ' || + CASE + WHEN cluster_config ->> 'ZoneAwarenessEnabled' = 'true' THEN 'enabled' + ELSE 'disabled' + END || ' with ' || (cluster_config ->> 'InstanceCount') || ' data node(s) configured.' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +47,4 @@ Tags: - aws service: - AWS/OpenSearch -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains should have at least three data nodes \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_opensearch_domain_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 6bd0c7136..498997d3e --- a/compliance/controls/aws/aws_opensearch_domain_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_encryption_at_rest_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether AWS OpenSearch domains have encryption-at-rest configuration enabled. The check fails if encryption at rest is not enabled. ID: aws_opensearch_domain_encryption_at_rest_enabled -Title: "OpenSearch domains should have encryption at rest enabled" -Description: "This control checks whether AWS OpenSearch domains have encryption-at-rest configuration enabled. The check fails if encryption at rest is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encryption_at_rest_options ->> 'Enabled' = 'false' then 'alarm'\n else 'ok'\n end status,\n case\n when encryption_at_rest_options ->> 'Enabled' = 'false' then title || ' encryption at rest disabled.'\n else title || ' encryption at rest enabled.'\n end reason\n \n , region, account_id\nfrom\n aws_opensearch_domain;\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encryption_at_rest_options ->> 'Enabled' = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption_at_rest_options ->> 'Enabled' = 'false' THEN title || ' encryption at rest disabled.' + ELSE title || ' encryption at rest enabled.' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/OpenSearch -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains should have encryption at rest enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_fine_grained_access_enabled.yaml b/compliance/controls/aws/aws_opensearch_domain_fine_grained_access_enabled.yaml old mode 100755 new mode 100644 index 3943b5cff..9ac45def6 --- a/compliance/controls/aws/aws_opensearch_domain_fine_grained_access_enabled.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_fine_grained_access_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether OpenSearch domains have fine-grained access control enabled. The control fails if the fine-grained access control is not enabled. Fine-grained access control requires advanced-security-options in the OpenSearch parameter update-domain-config to be enabled. ID: aws_opensearch_domain_fine_grained_access_enabled -Title: "OpenSearch domains should have fine-grained access control enabled" -Description: "This control checks whether OpenSearch domains have fine-grained access control enabled. The control fails if the fine-grained access control is not enabled. Fine-grained access control requires advanced-security-optionsin the OpenSearch parameter update-domain-config to be enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when advanced_security_options is null or not (advanced_security_options -> 'Enabled')::boolean then 'alarm'\n else 'ok'\n end as status,\n case\n when advanced_security_options is null or not (advanced_security_options -> 'Enabled')::boolean then title || ' has fine-grained access control disabled.'\n else title || ' has fine-grained access control enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_opensearch_domain;\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN advanced_security_options IS NULL OR NOT (advanced_security_options -> 'Enabled')::boolean THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN advanced_security_options IS NULL OR NOT (advanced_security_options -> 'Enabled')::boolean THEN title || ' has fine-grained access control disabled.' + ELSE title || ' has fine-grained access control enabled.' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain; Severity: high Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/OpenSearch -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains should have fine-grained access control enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_https_required.yaml b/compliance/controls/aws/aws_opensearch_domain_https_required.yaml old mode 100755 new mode 100644 index 950a01a41..a1176081f --- a/compliance/controls/aws/aws_opensearch_domain_https_required.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_https_required.yaml @@ -1,13 +1,36 @@ +Description: This control checks whether connections to OpenSearch domains are using HTTPS. The rule is non-compliant if the OpenSearch domain 'EnforceHTTPS' is not 'true' or is 'true' and 'TLSSecurityPolicy' is not in 'tlsPolicies'. ID: aws_opensearch_domain_https_required -Title: "OpenSearch domains should use HTTPS" -Description: "This control checks whether connections to OpenSearch domains are using HTTPS. The rule is non-compliant if the OpenSearch domain 'EnforceHTTPS' is not 'true' or is 'true' and 'TLSSecurityPolicy' is not in 'tlsPolicies'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when (domain_endpoint_options ->> 'EnforceHTTPS' = 'false') or (domain_endpoint_options ->> 'EnforceHTTPS' = 'true' and domain_endpoint_options ->> 'TLSSecurityPolicy' not in ('tlsPolicies')) then 'alarm'\n else 'ok'\n end status,\n case\n when (domain_endpoint_options ->> 'EnforceHTTPS' = 'false') or (domain_endpoint_options ->> 'EnforceHTTPS' = 'true' and domain_endpoint_options ->> 'TLSSecurityPolicy' not in ('tlsPolicies')) then title || ' does not use HTTPS.'\n else title || ' uses HTTPS.'\n end as reason\n \n , region, account_id\nfrom\n aws_opensearch_domain;\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (domain_endpoint_options ->> 'EnforceHTTPS' = 'false') + OR (domain_endpoint_options ->> 'EnforceHTTPS' = 'true' + AND domain_endpoint_options ->> 'TLSSecurityPolicy' NOT IN ('tlsPolicies')) + THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN (domain_endpoint_options ->> 'EnforceHTTPS' = 'false') + OR (domain_endpoint_options ->> 'EnforceHTTPS' = 'true' + AND domain_endpoint_options ->> 'TLSSecurityPolicy' NOT IN ('tlsPolicies')) + THEN title || ' does not use HTTPS.' + ELSE title || ' uses HTTPS.' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +45,4 @@ Tags: - aws service: - AWS/OpenSearch -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains should use HTTPS \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_in_vpc.yaml b/compliance/controls/aws/aws_opensearch_domain_in_vpc.yaml old mode 100755 new mode 100644 index 86a23eb8a..f865f6a3c --- a/compliance/controls/aws/aws_opensearch_domain_in_vpc.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_in_vpc.yaml @@ -1,50 +1,44 @@ +Description: This control checks whether AWS OpenSearch domains are in a VPC. It does not evaluate the VPC subnet routing configuration to determine public access. ID: aws_opensearch_domain_in_vpc -Title: "OpenSearch domains should be in a VPC" -Description: "This control checks whether AWS OpenSearch domains are in a VPC. It does not evaluate the VPC subnet routing configuration to determine public access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with public_subnets as ( - select - distinct a -> 'SubnetId' as SubnetId - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a, - jsonb_array_elements(routes) as r - where - r ->> 'DestinationCidrBlock' = '0.0.0.0/0' - and r ->> 'GatewayId' like 'igw-%' - ), opensearch_domain_with_public_subnet as ( - select - arn - from - aws_opensearch_domain , - jsonb_array_elements(vpc_options -> 'SubnetIds') as s - where - s in (select SubnetId from public_subnets) - ) - select - d.arn as resource, - d.og_account_id as og_account_id, - d.og_resource_id as og_resource_id, - case - when d.vpc_options ->> 'VPCId' is null then 'alarm' - when d.vpc_options ->> 'VPCId' is not null and p.arn is not null then 'alarm' - else 'ok' - end status, - case - when vpc_options ->> 'VPCId' is null then title || ' not in VPC.' - when d.vpc_options ->> 'VPCId' is not null and p.arn is not null then title || ' attached to public subnet.' - else title || ' in VPC ' || (vpc_options ->> 'VPCId') || '.' - end reason, d.region, d.account_id - from - aws_opensearch_domain as d - left join opensearch_domain_with_public_subnet as p on d.arn = p.arn; - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain - aws_vpc_route_table Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + WITH public_subnets AS ( + SELECT DISTINCT a -> 'SubnetId' AS SubnetId + FROM aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND r ->> 'GatewayId' LIKE 'igw-%' + ), opensearch_domain_with_public_subnet AS ( + SELECT arn + FROM aws_opensearch_domain, + jsonb_array_elements(vpc_options -> 'SubnetIds') AS s + WHERE s IN (SELECT SubnetId FROM public_subnets) + ) + SELECT d.arn AS resource, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + CASE + WHEN d.vpc_options ->> 'VPCId' IS NULL THEN 'alarm' + WHEN d.vpc_options ->> 'VPCId' IS NOT NULL AND p.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN vpc_options ->> 'VPCId' IS NULL THEN title || ' not in VPC.' + WHEN d.vpc_options ->> 'VPCId' IS NOT NULL AND p.arn IS NOT NULL THEN title || ' attached to public subnet.' + ELSE title || ' in VPC ' || (vpc_options ->> 'VPCId') || '.' + END reason, + d.region, d.account_id + FROM aws_opensearch_domain AS d + LEFT JOIN opensearch_domain_with_public_subnet AS p ON d.arn = p.arn; Severity: critical Tags: aws_foundational_security: @@ -61,5 +55,4 @@ Tags: - Exposed Endpoints service: - AWS/OpenSearch -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains should be in a VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_internal_user_database_disabled.yaml b/compliance/controls/aws/aws_opensearch_domain_internal_user_database_disabled.yaml old mode 100755 new mode 100644 index 7844f5ffb..48cb65b5d --- a/compliance/controls/aws/aws_opensearch_domain_internal_user_database_disabled.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_internal_user_database_disabled.yaml @@ -1,14 +1,28 @@ +Description: Ensure that AWS OpenSearch domain has internal user database disabled. This control is non-compliant if the OpenSearch domain internal user database is enabled. ID: aws_opensearch_domain_internal_user_database_disabled -Title: "OpenSearch domains internal user database should be disabled" -Description: "Ensure that AWS OpenSearch domain has internal user database disabled. This control is non-compliant if the OpenSearch domain internal user database is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when advanced_security_options ->> 'InternalUserDatabaseEnabled' = 'true' then 'alarm'\n else 'ok'\n end status,\n case\n when advanced_security_options ->> 'InternalUserDatabaseEnabled' = 'true' then title || ' internal user database enabled.'\n else title || ' internal user database disabled.'\n end reason\n \n \nfrom\n aws_opensearch_domain;" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN advanced_security_options ->> 'InternalUserDatabaseEnabled' = 'true' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN advanced_security_options ->> 'InternalUserDatabaseEnabled' = 'true' THEN title || ' internal user database enabled.' + ELSE title || ' internal user database disabled.' + END AS reason + FROM + aws_opensearch_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains internal user database should be disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_logs_to_cloudwatch.yaml b/compliance/controls/aws/aws_opensearch_domain_logs_to_cloudwatch.yaml old mode 100755 new mode 100644 index c0237d1cb..cfa6ed9ff --- a/compliance/controls/aws/aws_opensearch_domain_logs_to_cloudwatch.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_logs_to_cloudwatch.yaml @@ -1,13 +1,77 @@ +Description: This control checks whether AWS OpenSearch Service domains are configured to send logs to CloudWatch logs. The rule is non-compliant if logging is not configured. ID: aws_opensearch_domain_logs_to_cloudwatch -Title: "OpenSearch domains logs to AWS CloudWatch Logs" -Description: "This control checks whether AWS OpenSearch Service domains are configured to send logs to CloudWatch logs. The rule is non-compliant if logging is not configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when log_publishing_options is null then 'alarm'\n when\n ( log_publishing_options -> 'AUDIT_LOGS' is null\n or log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'INDEX_SLOW_LOGS' is null\n or log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'SEARCH_SLOW_LOGS' is null\n or log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'ES_APPLICATION_LOGS' is null\n or log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n then 'ok'\n else 'alarm'\n end as status,\n case\n when log_publishing_options is null then title || ' logging not enabled.'\n when\n ( log_publishing_options -> 'AUDIT_LOGS' is null\n or log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'INDEX_SLOW_LOGS' is null\n or log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'SEARCH_SLOW_LOGS' is null\n or log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n )\n and\n ( log_publishing_options -> 'ES_APPLICATION_LOGS' is null\n or log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'false'\n or (log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' and log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' is not null)\n ) then title || ' send logs to Amazon CloudWatch.'\n else title || ' does not send logs to Amazon CloudWatch.'\n end as reason\n \n , region, account_id\nfrom\n aws_opensearch_domain;\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN log_publishing_options IS NULL THEN 'alarm' + WHEN + (log_publishing_options -> 'AUDIT_LOGS' IS NULL + OR log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'INDEX_SLOW_LOGS' IS NULL + OR log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'SEARCH_SLOW_LOGS' IS NULL + OR log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'ES_APPLICATION_LOGS' IS NULL + OR log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_publishing_options IS NULL THEN title || ' logging not enabled.' + WHEN + (log_publishing_options -> 'AUDIT_LOGS' IS NULL + OR log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'AUDIT_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'AUDIT_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'INDEX_SLOW_LOGS' IS NULL + OR log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'INDEX_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'SEARCH_SLOW_LOGS' IS NULL + OR log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'SEARCH_SLOW_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) + AND + (log_publishing_options -> 'ES_APPLICATION_LOGS' IS NULL + OR log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'false' + OR (log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'Enabled' = 'true' + AND log_publishing_options -> 'ES_APPLICATION_LOGS' -> 'CloudWatchLogsLogGroupArn' IS NOT NULL) + ) THEN title || ' send logs to Amazon CloudWatch.' + ELSE title || ' does not send logs to Amazon CloudWatch.' + END AS reason, + region, account_id + FROM + aws_opensearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +86,4 @@ Tags: - aws service: - AWS/OpenSearch -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains logs to AWS CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_node_to_node_encryption_enabled.yaml b/compliance/controls/aws/aws_opensearch_domain_node_to_node_encryption_enabled.yaml old mode 100755 new mode 100644 index 59a0c1c68..5de24e217 --- a/compliance/controls/aws/aws_opensearch_domain_node_to_node_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_node_to_node_encryption_enabled.yaml @@ -1,13 +1,35 @@ +Description: This control checks if AWS OpenSearch Service nodes are encrypted end to end. The rule is non-compliant if the node-to-node encryption is not enabled on the domain. ID: aws_opensearch_domain_node_to_node_encryption_enabled -Title: "OpenSearch domains node-to-node encryption should be enabled" -Description: "This control checks if AWS OpenSearch Service nodes are encrypted end to end. The rule is non-compliant if the node-to-node encryption is not enabled on the domain." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) then 'skip'\n when node_to_node_encryption_options_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) then title || ' node-to-node encryption not supported in ' || region || '.'\n when node_to_node_encryption_options_enabled then title || ' node-to-node encryption enabled.'\n else title || ' node-to-node encryption disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_opensearch_domain;\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) THEN 'skip' + WHEN node_to_node_encryption_options_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1']) THEN + title || ' node-to-node encryption not supported in ' || region || '.' + WHEN node_to_node_encryption_options_enabled THEN + title || ' node-to-node encryption enabled.' + ELSE + title || ' node-to-node encryption disabled.' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain; Severity: medium Tags: aws_foundational_security: @@ -22,5 +44,4 @@ Tags: - aws service: - AWS/OpenSearch -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains node-to-node encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_opensearch_domain_updated_with_latest_service_software_version.yaml b/compliance/controls/aws/aws_opensearch_domain_updated_with_latest_service_software_version.yaml old mode 100755 new mode 100644 index c97f398ac..d24d31bcc --- a/compliance/controls/aws/aws_opensearch_domain_updated_with_latest_service_software_version.yaml +++ b/compliance/controls/aws/aws_opensearch_domain_updated_with_latest_service_software_version.yaml @@ -1,14 +1,28 @@ +Description: This control checks whether AWS OpenSearch domain has any updates available. This control is non-compliant if the OpenSearch domain has any updates available. ID: aws_opensearch_domain_updated_with_latest_service_software_version -Title: "OpenSearch domains should be updated to the latest service software version" -Description: "This control checks whether AWS OpenSearch domain has any updates available. This control is non-compliant if the OpenSearch domain has any updates available." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when service_software_options ->> 'UpdateAvailable' = 'false' then 'ok'\n else 'alarm'\n end status,\n case\n when service_software_options ->> 'UpdateAvailable' = 'false' then title || ' updated with latest service software version.'\n else title || ' not updated with latest service software version.'\n end reason\n \n \nfrom\n aws_opensearch_domain;" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN service_software_options ->> 'UpdateAvailable' = 'false' THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN service_software_options ->> 'UpdateAvailable' = 'false' THEN title || ' updated with latest service software version.' + ELSE title || ' not updated with latest service software version.' + END reason + FROM + aws_opensearch_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: OpenSearch domains should be updated to the latest service software version \ No newline at end of file diff --git a/compliance/controls/aws/aws_organizational_tag_policies_enabled.yaml b/compliance/controls/aws/aws_organizational_tag_policies_enabled.yaml old mode 100755 new mode 100644 index 1f4b22f6b..0f2a91424 --- a/compliance/controls/aws/aws_organizational_tag_policies_enabled.yaml +++ b/compliance/controls/aws/aws_organizational_tag_policies_enabled.yaml @@ -1,46 +1,46 @@ +Description: Tag policies help you standardize tags on all tagged resources across your organization ID: aws_organizational_tag_policies_enabled -Title: "Ensure Tag Policies are enabled" -Description: "Tag policies help you standardize tags on all tagged resources across your organization" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with tag_policy_enabled as ( - select + ListOfTables: + - aws_organizations_policy + Parameters: [] + PrimaryTable: aws_organizations_policy + QueryToExecute: | + WITH tag_policy_enabled AS ( + SELECT _ctx, account_id, region, - count(*) as count, + COUNT(*) AS count, og_account_id, og_resource_id - from + FROM aws_organizations_policy - where + WHERE type = 'TAG_POLICY' - group by + GROUP BY _ctx, region, account_id, og_account_id, og_resource_id ) - select + SELECT og_account_id, og_resource_id, - case - when count > 0 then 'ok' - else 'alarm' - end as status, - case - when count > 0 then 'Organizational tag policies are enabled.' - else 'Organizational tag policies are disabled.' - end as reason - from + CASE + WHEN count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN count > 0 THEN 'Organizational tag policies are enabled.' + ELSE 'Organizational tag policies are disabled.' + END AS reason + FROM tag_policy_enabled; - PrimaryTable: aws_organizations_policy - ListOfTables: - - aws_organizations_policy - Parameters: [] Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure Tag Policies are enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_aurora_backtracking_enabled.yaml b/compliance/controls/aws/aws_rds_db_cluster_aurora_backtracking_enabled.yaml old mode 100755 new mode 100644 index 4dfd28ce8..06d3dee20 --- a/compliance/controls/aws/aws_rds_db_cluster_aurora_backtracking_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_aurora_backtracking_enabled.yaml @@ -1,13 +1,32 @@ +Description: This control checks whether AWS Aurora clusters have backtracking enabled. Backups help you to recover more quickly from a security incident. They also strengthen the resilience of your systems. Aurora backtracking reduces the time to recover a database to a point in time. It does not require a database restore to so. ID: aws_rds_db_cluster_aurora_backtracking_enabled -Title: "RDS Aurora clusters should have backtracking enabled" -Description: "This control checks whether AWS Aurora clusters have backtracking enabled. Backups help you to recover more quickly from a security incident. They also strengthen the resilience of your systems. Aurora backtracking reduces the time to recover a database to a point in time. It does not require a database restore to so." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when engine not ilike '%aurora-mysql%' then 'skip'\n when backtrack_window is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when engine not ilike '%aurora-mysql%' then title || ' not Aurora MySQL-compatible edition.'\n when backtrack_window is not null then title || ' backtracking enabled.'\n else title || ' backtracking not enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_cluster;\n" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine NOT ILIKE '%aurora-mysql%' THEN 'skip' + WHEN backtrack_window IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine NOT ILIKE '%aurora-mysql%' THEN title || ' not Aurora MySQL-compatible edition.' + WHEN backtrack_window IS NOT NULL THEN title || ' backtracking enabled.' + ELSE title || ' backtracking not enabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster; Severity: medium Tags: aws_foundational_security: @@ -22,5 +41,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS Aurora clusters should have backtracking enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_aurora_mysql_audit_logging_enabled.yaml b/compliance/controls/aws/aws_rds_db_cluster_aurora_mysql_audit_logging_enabled.yaml old mode 100755 new mode 100644 index 210ed3e20..0710d73ab --- a/compliance/controls/aws/aws_rds_db_cluster_aurora_mysql_audit_logging_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_aurora_mysql_audit_logging_enabled.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether an Amazon Aurora MySQL DB cluster is configured to publish audit logs to Amazon CloudWatch Logs. The control fails if the cluster isn't configured to publish audit logs to CloudWatch Logs. ID: aws_rds_db_cluster_aurora_mysql_audit_logging_enabled -Title: "Aurora MySQL DB clusters should publish audit logs to CloudWatch Logs" -Description: "This control checks whether an Amazon Aurora MySQL DB cluster is configured to publish audit logs to Amazon CloudWatch Logs. The control fails if the cluster isn't configured to publish audit logs to CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when engine not ilike '%aurora-mysql%' then 'skip'\n when enabled_cloudwatch_logs_exports @> '[\"audit\"]' then 'ok'\n else 'alarm'\n end as status,\n case\n when engine not ilike '%aurora-mysql%' then title || ' is not Aurora MySQL-compatible edition.'\n when enabled_cloudwatch_logs_exports @> '[\"audit\"]' then title || ' audit logging enabled.'\n else title || ' audit logging disabled.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster;" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine NOT ILIKE '%aurora-mysql%' THEN 'skip' + WHEN enabled_cloudwatch_logs_exports @> '["audit"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine NOT ILIKE '%aurora-mysql%' THEN title || ' is not Aurora MySQL-compatible edition.' + WHEN enabled_cloudwatch_logs_exports @> '["audit"]' THEN title || ' audit logging enabled.' + ELSE title || ' audit logging disabled.' + END AS reason + FROM + aws_rds_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Aurora MySQL DB clusters should publish audit logs to CloudWatch Logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_aurora_postgres_not_exposed_to_local_file_read_vulnerability.yaml b/compliance/controls/aws/aws_rds_db_cluster_aurora_postgres_not_exposed_to_local_file_read_vulnerability.yaml old mode 100755 new mode 100644 index bd16d3e18..6a350ea1b --- a/compliance/controls/aws/aws_rds_db_cluster_aurora_postgres_not_exposed_to_local_file_read_vulnerability.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_aurora_postgres_not_exposed_to_local_file_read_vulnerability.yaml @@ -1,14 +1,30 @@ +Description: This control checks whether AWS Aurora PostgreSQL clusters are exposed to local file read vulnerability by ensuring that AWS RDS PostgreSQL instances use a non-vulnerable version of the log_fdw. ID: aws_rds_db_cluster_aurora_postgres_not_exposed_to_local_file_read_vulnerability -Title: "RDS Aurora PostgreSQL clusters should not be exposed to local file read vulnerability" -Description: "This control checks whether AWS Aurora PostgreSQL clusters are exposed to local file read vulnerability by ensuring that AWS RDS PostgreSQL instances use a non-vulnerable version of the log_fdw." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when not engine ilike '%aurora-postgres%' then 'skip'\n when engine ilike '%aurora-postgres%' and engine_version like any (array ['10.11', '10.12', '10.13', '11.6', '11.7', '11.8']) then 'alarm'\n else 'ok'\n end as status,\n case\n when not engine ilike '%aurora-postgres%' then title || ' not Aurora PostgreSQL edition.'\n when engine ilike '%aurora-postgres%' and engine_version like any (array ['10.11', '10.12', '10.13', '11.6', '11.7', '11.8']) then title || ' exposed to local file read vulnerability.'\n else title || ' not exposed to local file read vulnerability.'\n end as reason\n \n \nfrom\n aws_rds_db_instance;" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT engine ILIKE '%aurora-postgres%' THEN 'skip' + WHEN engine ILIKE '%aurora-postgres%' AND engine_version LIKE ANY (ARRAY ['10.11', '10.12', '10.13', '11.6', '11.7', '11.8']) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT engine ILIKE '%aurora-postgres%' THEN title || ' not Aurora PostgreSQL edition.' + WHEN engine ILIKE '%aurora-postgres%' AND engine_version LIKE ANY (ARRAY ['10.11', '10.12', '10.13', '11.6', '11.7', '11.8']) THEN title || ' exposed to local file read vulnerability.' + ELSE title || ' not exposed to local file read vulnerability.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS Aurora PostgreSQL clusters should not be exposed to local file read vulnerability \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_aurora_protected_by_backup_plan.yaml b/compliance/controls/aws/aws_rds_db_cluster_aurora_protected_by_backup_plan.yaml old mode 100755 new mode 100644 index fa76e974a..9ec421b3c --- a/compliance/controls/aws/aws_rds_db_cluster_aurora_protected_by_backup_plan.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_aurora_protected_by_backup_plan.yaml @@ -1,14 +1,42 @@ +Description: Checks if AWS Aurora DB clusters are protected by a backup plan. The rule is non-compliant if the AWS Relational Database Service (AWS RDS) Database Cluster is not protected by a backup plan. ID: aws_rds_db_cluster_aurora_protected_by_backup_plan -Title: "RDS Aurora clusters should be protected by backup plan" -Description: "Checks if AWS Aurora DB clusters are protected by a backup plan. The rule is non-compliant if the AWS Relational Database Service (AWS RDS) Database Cluster is not protected by a backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with backup_protected_cluster as (\n select\n resource_arn as arn\n from\n aws_backup_protected_resource as b\n where\n resource_type = 'Aurora'\n)\nselect\n c.arn as resource,\n c.og_account_id as og_account_id,\n c.og_resource_id as og_resource_id,\n case\n when c.engine not like '%aurora%' then 'skip'\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when c.engine not like '%aurora%' then c.title || ' not Aurora resources.'\n when b.arn is not null then c.title || ' is protected by backup plan.'\n else c.title || ' is not protected by backup plan.'\n end as reason\n \n , c.region, c.account_id\nfrom\n aws_rds_db_cluster as c\n left join backup_protected_cluster as b on c.arn = b.arn;\n" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_backup_protected_resource - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + WITH backup_protected_cluster AS ( + SELECT + resource_arn AS arn + FROM + aws_backup_protected_resource AS b + WHERE + resource_type = 'Aurora' + ) + SELECT + c.arn AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.engine NOT LIKE '%aurora%' THEN 'skip' + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.engine NOT LIKE '%aurora%' THEN c.title || ' not Aurora resources.' + WHEN b.arn IS NOT NULL THEN c.title || ' is protected by backup plan.' + ELSE c.title || ' is not protected by backup plan.' + END AS reason, + c.region, + c.account_id + FROM + aws_rds_db_cluster AS c + LEFT JOIN backup_protected_cluster AS b ON c.arn = b.arn Severity: high Tags: category: @@ -41,5 +69,4 @@ Tags: - AWS/RDS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: RDS Aurora clusters should be protected by backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_automatic_minor_version_upgrade_enabled.yaml b/compliance/controls/aws/aws_rds_db_cluster_automatic_minor_version_upgrade_enabled.yaml old mode 100755 new mode 100644 index 74b323773..07f7db41e --- a/compliance/controls/aws/aws_rds_db_cluster_automatic_minor_version_upgrade_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_automatic_minor_version_upgrade_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks if automatic minor version upgrade is enabled for an Amazon RDS database cluster. The control fails if automatic minor version upgrade isn't enabled for an RDS cluster. ID: aws_rds_db_cluster_automatic_minor_version_upgrade_enabled -Title: "RDS DB clusters should have automatic minor version upgrade enabled" -Description: "This control checks if automatic minor version upgrade is enabled for an Amazon RDS database cluster. The control fails if automatic minor version upgrade isn't enabled for an RDS cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when auto_minor_version_upgrade then 'ok'\n else 'alarm'\n end as status,\n case\n when auto_minor_version_upgrade then title || ' automatic minor version upgrades enabled.'\n else title || ' automatic minor version upgrades disabled.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster;" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrades enabled.' + ELSE title || ' automatic minor version upgrades disabled.' + END AS reason + FROM + aws_rds_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB clusters should have automatic minor version upgrade enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_copy_tags_to_snapshot_enabled.yaml b/compliance/controls/aws/aws_rds_db_cluster_copy_tags_to_snapshot_enabled.yaml old mode 100755 new mode 100644 index 080db9cc5..7bf4cd211 --- a/compliance/controls/aws/aws_rds_db_cluster_copy_tags_to_snapshot_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_copy_tags_to_snapshot_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether RDS DB clusters are configured to copy all tags to snapshots when the snapshots are created. ID: aws_rds_db_cluster_copy_tags_to_snapshot_enabled -Title: "RDS DB clusters should be configured to copy tags to snapshots" -Description: "This control checks whether RDS DB clusters are configured to copy all tags to snapshots when the snapshots are created." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when copy_tags_to_snapshot then 'ok'\n else 'alarm'\n end as status,\n case\n when copy_tags_to_snapshot then title || ' copy tags to snapshot enabled.'\n else title || ' copy tags to snapshot disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_cluster;\n" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN copy_tags_to_snapshot THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN copy_tags_to_snapshot THEN title || ' copy tags to snapshot enabled.' + ELSE title || ' copy tags to snapshot disabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster; Severity: low Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS DB clusters should be configured to copy tags to snapshots \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_deletion_protection_enabled.yaml b/compliance/controls/aws/aws_rds_db_cluster_deletion_protection_enabled.yaml old mode 100755 new mode 100644 index 853fbfded..96f4cbf99 --- a/compliance/controls/aws/aws_rds_db_cluster_deletion_protection_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_deletion_protection_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether RDS clusters have deletion protection enabled. This control is intended for RDS DB instances. However, it can also generate findings for Aurora DB instances, Neptune DB instances, and AWS DocumentDB clusters. If these findings are not useful, then you can suppress them. ID: aws_rds_db_cluster_deletion_protection_enabled -Title: "RDS clusters should have deletion protection enabled" -Description: "This control checks whether RDS clusters have deletion protection enabled. This control is intended for RDS DB instances. However, it can also generate findings for Aurora DB instances, Neptune DB instances, and AWS DocumentDB clusters. If these findings are not useful,then you can suppress them." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n db_cluster_identifier as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when deletion_protection then 'ok'\n else 'alarm'\n end as status,\n case\n when deletion_protection then title || ' deletion protection enabled.'\n else title || ' deletion protection not enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_cluster;\n" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + db_cluster_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN deletion_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN deletion_protection THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection not enabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster; Severity: low Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS clusters should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_rds_db_cluster_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 34150bfec..88e019d40 --- a/compliance/controls/aws/aws_rds_db_cluster_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_encryption_at_rest_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control checks if an RDS DB cluster is encrypted at rest. The control fails if an RDS DB cluster isn't encrypted at rest. ID: aws_rds_db_cluster_encryption_at_rest_enabled -Title: "RDS DB clusters should be encrypted at rest" -Description: "This control checks if an RDS DB cluster is encrypted at rest. The control fails if an RDS DB cluster isn't encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster;" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_rds_db_cluster; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB clusters should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_events_subscription.yaml b/compliance/controls/aws/aws_rds_db_cluster_events_subscription.yaml old mode 100755 new mode 100644 index c5d182ad7..7f255cdce --- a/compliance/controls/aws/aws_rds_db_cluster_events_subscription.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_events_subscription.yaml @@ -1,30 +1,32 @@ +Description: This control checks whether an AWS RDS event subscription exists that has notifications enabled for the following source type, event category key-value pairs. ID: aws_rds_db_cluster_events_subscription -Title: "An RDS event notifications subscription should be configured for critical cluster events" -Description: "This control checks whether an AWS RDS event subscription exists that has notifications enabled for the following source type, event category key-value pairs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when source_type <> 'db-cluster' then 'skip' - when source_type = 'db-cluster' and enabled and event_categories_list @> '["failure", "maintenance"]' then 'ok' - else 'alarm' - end as status, - case - when source_type <> 'db-cluster' then cust_subscription_id || ' event subscription of ' || source_type || ' type.' - when source_type = 'db-cluster' and enabled and event_categories_list @> '["failure", "maintenance"]' then cust_subscription_id || ' event subscription enabled for critical db cluster events.' - else cust_subscription_id || ' event subscription missing critical db cluster events.' - end as reason - , region, account_id - from - aws_rds_db_event_subscription; - PrimaryTable: aws_rds_db_event_subscription ListOfTables: - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_rds_db_event_subscription + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN source_type <> 'db-cluster' THEN 'skip' + WHEN source_type = 'db-cluster' AND enabled AND event_categories_list @> '["failure", "maintenance"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN source_type <> 'db-cluster' THEN cust_subscription_id || ' event subscription of ' || source_type || ' type.' + WHEN source_type = 'db-cluster' AND enabled AND event_categories_list @> '["failure", "maintenance"]' THEN cust_subscription_id || ' event subscription enabled for critical db cluster events.' + ELSE cust_subscription_id || ' event subscription missing critical db cluster events.' + END AS reason, + region, + account_id + FROM + aws_rds_db_event_subscription; Severity: low Tags: aws_foundational_security: @@ -39,5 +41,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: An RDS event notifications subscription should be configured for critical cluster events \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_iam_authentication_enabled.yaml b/compliance/controls/aws/aws_rds_db_cluster_iam_authentication_enabled.yaml old mode 100755 new mode 100644 index 7085117e1..0681a689e --- a/compliance/controls/aws/aws_rds_db_cluster_iam_authentication_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_iam_authentication_enabled.yaml @@ -1,13 +1,30 @@ +Description: Checks if an AWS RDS Cluster has AWS Identity and Access Management (IAM) authentication enabled. The rule is non-compliant if an RDS Cluster does not have IAM authentication enabled. ID: aws_rds_db_cluster_iam_authentication_enabled -Title: "IAM authentication should be configured for RDS clusters" -Description: "Checks if an AWS RDS Cluster has AWS Identity and Access Management (IAM) authentication enabled. The rule is non-compliant if an RDS Cluster does not have IAM authentication enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when iam_database_authentication_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when iam_database_authentication_enabled then title || ' IAM authentication enabled.'\n else title || ' IAM authentication not enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_cluster;\n" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN iam_database_authentication_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN iam_database_authentication_enabled THEN title || ' IAM authentication enabled.' + ELSE title || ' IAM authentication not enabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: IAM authentication should be configured for RDS clusters \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_multiple_az_enabled.yaml b/compliance/controls/aws/aws_rds_db_cluster_multiple_az_enabled.yaml old mode 100755 new mode 100644 index 4f1dcc664..86c6a119c --- a/compliance/controls/aws/aws_rds_db_cluster_multiple_az_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_multiple_az_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether high availability is enabled for your RDS DB clusters. RDS DB clusters should be configured for multiple Availability Zones to ensure availability of the data that is stored. ID: aws_rds_db_cluster_multiple_az_enabled -Title: "RDS DB clusters should be configured for multiple Availability Zones" -Description: "This control checks whether high availability is enabled for your RDS DB clusters. RDS DB clusters should be configured for multiple Availability Zones to ensure availability of the data that is stored." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when multi_az then 'ok'\n else 'alarm'\n end as status,\n case\n when multi_az then title || ' Multi-AZ enabled.'\n else title || ' Multi-AZ disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_cluster;\n" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN multi_az THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN multi_az THEN title || ' Multi-AZ enabled.' + ELSE title || ' Multi-AZ disabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS DB clusters should be configured for multiple Availability Zones \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_cluster_no_default_admin_name.yaml b/compliance/controls/aws/aws_rds_db_cluster_no_default_admin_name.yaml old mode 100755 new mode 100644 index 915cfa925..d7b8a5836 --- a/compliance/controls/aws/aws_rds_db_cluster_no_default_admin_name.yaml +++ b/compliance/controls/aws/aws_rds_db_cluster_no_default_admin_name.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether an AWS RDS database cluster has changed the admin username from its default value. This rule will fail if the admin username is set to the default value. ID: aws_rds_db_cluster_no_default_admin_name -Title: "RDS database clusters should use a custom administrator username" -Description: "This control checks whether an AWS RDS database cluster has changed the admin username from its default value. This rule will fail if the admin username is set to the default value." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when master_user_name in ('admin', 'postgres') then 'alarm'\n else 'ok'\n end status,\n case\n when master_user_name in ('admin', 'postgres') then title || ' using default master user name.'\n else title || ' not using default master user name.'\n end reason\n \n , region, account_id\nfrom\n aws_rds_db_cluster;\n" - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN master_user_name IN ('admin', 'postgres') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN master_user_name IN ('admin', 'postgres') THEN title || ' using default master user name.' + ELSE title || ' not using default master user name.' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS database clusters should use a custom administrator username \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_and_cluster_enhanced_monitoring_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_and_cluster_enhanced_monitoring_enabled.yaml old mode 100755 new mode 100644 index 4cfb0006f..2b92de858 --- a/compliance/controls/aws/aws_rds_db_instance_and_cluster_enhanced_monitoring_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_and_cluster_enhanced_monitoring_enabled.yaml @@ -1,14 +1,56 @@ +Description: Enable AWS Relational Database Service (AWS RDS) to help monitor AWS RDS availability. This provides detailed visibility into the health of your AWS RDS database instances. ID: aws_rds_db_instance_and_cluster_enhanced_monitoring_enabled -Title: "RDS DB instance and cluster enhanced monitoring should be enabled" -Description: "Enable AWS Relational Database Service (AWS RDS) to help monitor AWS RDS availability. This provides detailed visibility into the health of your AWS RDS database instances." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_rds_db_cluster' as og_table_name,\n case\n when enabled_cloudwatch_logs_exports is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when enabled_cloudwatch_logs_exports is not null then title || ' enhanced monitoring enabled.'\n else title || ' enhanced monitoring not enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_cluster\n)\nunion\n(\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_rds_db_instance' as og_table_name,\n case\n when class = 'db.m1.small' then 'skip'\n when enhanced_monitoring_resource_arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when class = 'db.m1.small' then title || ' enhanced monitoring not supported.'\n when enhanced_monitoring_resource_arn is not null then title || ' enhanced monitoring enabled.'\n else title || ' enhanced monitoring not enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_instance\n);\n" - PrimaryTable: "" ListOfTables: - aws_rds_db_cluster - aws_rds_db_instance Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_rds_db_cluster' AS og_table_name, + CASE + WHEN enabled_cloudwatch_logs_exports IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled_cloudwatch_logs_exports IS NOT NULL THEN title || ' enhanced monitoring enabled.' + ELSE title || ' enhanced monitoring not enabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster + ) + UNION + ( + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_rds_db_instance' AS og_table_name, + CASE + WHEN class = 'db.m1.small' THEN 'skip' + WHEN enhanced_monitoring_resource_arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN class = 'db.m1.small' THEN title || ' enhanced monitoring not supported.' + WHEN enhanced_monitoring_resource_arn IS NOT NULL THEN title || ' enhanced monitoring enabled.' + ELSE title || ' enhanced monitoring not enabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance + ); Severity: low Tags: category: @@ -23,17 +65,16 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS DB instance and cluster enhanced monitoring should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_and_cluster_no_default_port.yaml b/compliance/controls/aws/aws_rds_db_instance_and_cluster_no_default_port.yaml old mode 100755 new mode 100644 index 589ada0d7..c937d04a8 --- a/compliance/controls/aws/aws_rds_db_instance_and_cluster_no_default_port.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_and_cluster_no_default_port.yaml @@ -1,14 +1,64 @@ +Description: This control checks whether the RDS cluster or instance uses a port other than the default port of the database engine. ID: aws_rds_db_instance_and_cluster_no_default_port -Title: "RDS databases and clusters should not use a database engine default port" -Description: "This control checks whether the RDS cluster or instance uses a port other than the default port of the database engine." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_rds_db_cluster' as og_table_name,\n case\n when engine similar to '%(aurora|mysql|mariadb)%' and port = '3306' then 'alarm'\n when engine like '%postgres%' and port = '5432' then 'alarm'\n when engine like 'oracle%' and port = '1521' then 'alarm'\n when engine like 'sqlserver%' and port = '1433' then 'alarm'\n else 'ok'\n end as status,\n case\n when engine similar to '%(aurora|mysql|mariadb)%' and port = '3306' then title || ' ' || engine || ' uses a default port.'\n when engine like '%postgres%' and port = '5432' then title || ' ' || engine || ' uses a default port.'\n when engine like 'oracle%' and port = '1521' then title || ' ' || engine || ' uses a default port.'\n when engine like 'sqlserver%' and port = '1433' then title || ' ' || engine || ' uses a default port.'\n else title || ' doesnt use a default port.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_cluster\n)\nunion\n(\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_rds_db_instance' as og_table_name,\n case\n when engine similar to '%(aurora|mysql|mariadb)%' and port = '3306' then 'alarm'\n when engine like '%postgres%' and port = '5432' then 'alarm'\n when engine like 'oracle%' and port = '1521' then 'alarm'\n when engine like 'sqlserver%' and port = '1433' then 'alarm'\n else 'ok'\n end as status,\n case\n when engine similar to '%(aurora|mysql|mariadb)%' and port = '3306' then title || ' ' || engine || ' uses a default port.'\n when engine like '%postgres%' and port = '5432' then title || ' ' || engine || ' uses a default port.'\n when engine like 'oracle%' and port = '1521' then title || ' ' || engine || ' uses a default port.'\n when engine like 'sqlserver%' and port = '1433' then title || ' ' || engine || ' uses a default port.'\n else title || ' doesnt use a default port.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_instance\n);\n" - PrimaryTable: "" ListOfTables: - aws_rds_db_cluster - aws_rds_db_instance Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_rds_db_cluster' AS og_table_name, + CASE + WHEN engine SIMILAR TO '%(aurora|mysql|mariadb)%' AND port = '3306' THEN 'alarm' + WHEN engine LIKE '%postgres%' AND port = '5432' THEN 'alarm' + WHEN engine LIKE 'oracle%' AND port = '1521' THEN 'alarm' + WHEN engine LIKE 'sqlserver%' AND port = '1433' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN engine SIMILAR TO '%(aurora|mysql|mariadb)%' AND port = '3306' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE '%postgres%' AND port = '5432' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE 'oracle%' AND port = '1521' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE 'sqlserver%' AND port = '1433' THEN title || ' ' || engine || ' uses a default port.' + ELSE title || ' doesnt use a default port.' + END AS reason, + region, account_id + FROM + aws_rds_db_cluster + ) + UNION + ( + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_rds_db_instance' AS og_table_name, + CASE + WHEN engine SIMILAR TO '%(aurora|mysql|mariadb)%' AND port = '3306' THEN 'alarm' + WHEN engine LIKE '%postgres%' AND port = '5432' THEN 'alarm' + WHEN engine LIKE 'oracle%' AND port = '1521' THEN 'alarm' + WHEN engine LIKE 'sqlserver%' AND port = '1433' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN engine SIMILAR TO '%(aurora|mysql|mariadb)%' AND port = '3306' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE '%postgres%' AND port = '5432' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE 'oracle%' AND port = '1521' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE 'sqlserver%' AND port = '1433' THEN title || ' ' || engine || ' uses a default port.' + ELSE title || ' doesnt use a default port.' + END AS reason, + region, account_id + FROM + aws_rds_db_instance + ); Severity: low Tags: aws_foundational_security: @@ -23,5 +73,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS databases and clusters should not use a database engine default port \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_automatic_minor_version_upgrade_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_automatic_minor_version_upgrade_enabled.yaml old mode 100755 new mode 100644 index 6d640416c..ccb35dd87 --- a/compliance/controls/aws/aws_rds_db_instance_automatic_minor_version_upgrade_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_automatic_minor_version_upgrade_enabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure that AWS Relational Database Service (RDS) database instances are configured for automatic minor version upgrades. The rule is non-compliant if the value of 'autoMinorVersionUpgrade' is false. ID: aws_rds_db_instance_automatic_minor_version_upgrade_enabled -Title: "RDS DB instance automatic minor version upgrade should be enabled" -Description: "Ensure that AWS Relational Database Service (RDS) database instances are configured for automatic minor version upgrades. The rule is non-compliant if the value of 'autoMinorVersionUpgrade' is false." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when auto_minor_version_upgrade then 'ok'\n else 'alarm'\n end as status,\n case\n when auto_minor_version_upgrade then title || ' automatic minor version upgrades enabled.'\n else title || ' automatic minor version upgrades not enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_minor_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_minor_version_upgrade THEN title || ' automatic minor version upgrades enabled.' + ELSE title || ' automatic minor version upgrades not enabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: high Tags: category: @@ -28,5 +45,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS DB instance automatic minor version upgrade should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_backup_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_backup_enabled.yaml old mode 100755 new mode 100644 index d6a92d6e6..e4a0575ed --- a/compliance/controls/aws/aws_rds_db_instance_backup_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_backup_enabled.yaml @@ -1,13 +1,30 @@ +Description: The backup feature of AWS RDS creates backups of your databases and transaction logs. ID: aws_rds_db_instance_backup_enabled -Title: "RDS DB instance backup should be enabled" -Description: "The backup feature of AWS RDS creates backups of your databases and transaction logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when backup_retention_period < 1 then 'alarm'\n else 'ok'\n end as status,\n case\n when backup_retention_period < 1 then title || ' backups not enabled.'\n else title || ' backups enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN backup_retention_period < 1 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN backup_retention_period < 1 THEN title || ' backups not enabled.' + ELSE title || ' backups enabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: low Tags: category: @@ -30,12 +47,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +65,4 @@ Tags: - AWS/RDS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: RDS DB instance backup should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_backup_retention_period_less_than_7.yaml b/compliance/controls/aws/aws_rds_db_instance_backup_retention_period_less_than_7.yaml old mode 100755 new mode 100644 index 55cca2a24..7a28aadc8 --- a/compliance/controls/aws/aws_rds_db_instance_backup_retention_period_less_than_7.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_backup_retention_period_less_than_7.yaml @@ -1,26 +1,25 @@ +Description: Ensure RDS DB instance backup retention period is greater than or equal to 7. ID: aws_rds_db_instance_backup_retention_period_less_than_7 -Title: "RDS DB instances backup retention period should be greater than or equal to 7" -Description: "Ensure RDS DB instance backup retention period is greater than or equal to 7." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when backup_retention_period < 7 then 'alarm' - else 'ok' - end as status, - title || ' backup retention period set to ' || backup_retention_period || '.' as reason - - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN backup_retention_period < 7 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' backup retention period set to ' || backup_retention_period || '.' AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB instances backup retention period should be greater than or equal to 7 \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_ca_certificate_expires_7_days.yaml b/compliance/controls/aws/aws_rds_db_instance_ca_certificate_expires_7_days.yaml old mode 100755 new mode 100644 index b11d2f8a1..added0c75 --- a/compliance/controls/aws/aws_rds_db_instance_ca_certificate_expires_7_days.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_ca_certificate_expires_7_days.yaml @@ -1,27 +1,28 @@ +Description: Ensure RDS DB instances CA certificates are not getting expired within the next 7 days. ID: aws_rds_db_instance_ca_certificate_expires_7_days -Title: "RDS DB instances CA certificates should not expire within next 7 days" -Description: "Ensure RDS DB instances CA certificates are not getting expired within the next 7 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when extract(day from (to_timestamp(certificate ->> 'ValidTill','YYYY-MM-DDTHH:MI:SS')) - current_timestamp) <= '7' then 'alarm' - else 'ok' - end as status, - title || ' expires ' || to_char(to_timestamp(certificate ->> 'ValidTill','YYYY-MM-DDTHH:MI:SS'), 'DD-Mon-YYYY') || - ' (' || extract(day from (to_timestamp(certificate ->> 'ValidTill','YYYY-MM-DDTHH:MI:SS')) - current_timestamp) || ' days).' - as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN EXTRACT(DAY FROM (TO_TIMESTAMP(certificate ->> 'ValidTill', 'YYYY-MM-DDTHH:MI:SS') - CURRENT_TIMESTAMP)) <= 7 + THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' expires ' || TO_CHAR(TO_TIMESTAMP(certificate ->> 'ValidTill', 'YYYY-MM-DDTHH:MI:SS'), 'DD-Mon-YYYY') || + ' (' || EXTRACT(DAY FROM (TO_TIMESTAMP(certificate ->> 'ValidTill', 'YYYY-MM-DDTHH:MI:SS') - CURRENT_TIMESTAMP)) || ' days).' + AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB instances CA certificates should not expire within next 7 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_cloudwatch_logs_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_cloudwatch_logs_enabled.yaml old mode 100755 new mode 100644 index c489f2ff6..41e502458 --- a/compliance/controls/aws/aws_rds_db_instance_cloudwatch_logs_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_cloudwatch_logs_enabled.yaml @@ -1,28 +1,28 @@ +Description: Use AWS CloudWatch to centrally collect and manage RDS DB instance activity. ID: aws_rds_db_instance_cloudwatch_logs_enabled -Title: "RDS DB instances should be integrated with CloudWatch logs" -Description: "Use AWS CloudWatch to centrally collect and manage RDS DB instance activity." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when enabled_cloudwatch_logs_exports is not null then 'ok' - else 'alarm' - end as status, - case - when enabled_cloudwatch_logs_exports is not null then title || ' integrated with CloudWatch logs.' - else title || ' not integrated with CloudWatch logs.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enabled_cloudwatch_logs_exports IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled_cloudwatch_logs_exports IS NOT NULL THEN title || ' integrated with CloudWatch logs.' + ELSE title || ' not integrated with CloudWatch logs.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB instances should be integrated with CloudWatch logs \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_connections_encryption_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_connections_encryption_enabled.yaml old mode 100755 new mode 100644 index 247d235c0..a58a2c532 --- a/compliance/controls/aws/aws_rds_db_instance_connections_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_connections_encryption_enabled.yaml @@ -1,12 +1,18 @@ +Description: This control checks if RDS DB instance connections are encrypted. Secure Sockets Layer (SSL) is used to encrypt between client applications and AWS RDS DB instances running Microsoft SQL Server or PostgreSQL. ID: aws_rds_db_instance_connections_encryption_enabled -Title: "RDS DB instances connections should be encrypted" -Description: "This control checks if RDS DB instance connections are encrypted. Secure Sockets Layer (SSL) is used to encrypt between client applications and AWS RDS DB instances running Microsoft SQL Server or PostgreSQL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with instance_pg as ( - select - g ->> 'DBParameterGroupName' as pg_name, + ListOfTables: + - aws_rds_db_instance + - aws_rds_db_parameter_group + Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + WITH instance_pg AS ( + SELECT + g ->> 'DBParameterGroupName' AS pg_name, i.engine, i.title, i.arn, @@ -14,49 +20,43 @@ Query: i.region, i.account_id, i._ctx, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id - from - aws_rds_db_instance as i, - jsonb_array_elements(db_parameter_groups) as g - ), pg_with_ssl_enabled as ( - select + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id + FROM + aws_rds_db_instance AS i, + jsonb_array_elements(db_parameter_groups) AS g + ), pg_with_ssl_enabled AS ( + SELECT g.name - from - instance_pg as i, - aws_rds_db_parameter_group as g, - jsonb_array_elements(parameters) as p - where + FROM + instance_pg AS i, + aws_rds_db_parameter_group AS g, + jsonb_array_elements(parameters) AS p + WHERE i.pg_name = g.name - and g.account_id = i.account_id - and g.region = i.region - and p ->> 'ParameterName' = 'rds.force_ssl' - and p ->> 'ParameterValue' = '1' + AND g.account_id = i.account_id + AND g.region = i.region + AND p ->> 'ParameterName' = 'rds.force_ssl' + AND p ->> 'ParameterValue' = '1' ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, i.engine, - case - when i.engine not in ('sqlserver', 'postgres') then 'skip' - when p.name is not null then 'ok' - else 'alarm' - end as status, - case - when i.engine not in ('sqlserver', 'postgres') then title || ' has ' || engine || ' engine type.' - when p.name is not null then title || ' connections are SSL encrypted.' - else title || ' connections are not SSL encrypted.' - end as reason - from - instance_pg as i - left join pg_with_ssl_enabled as p on p.name = i.pg_name - PrimaryTable: aws_rds_db_instance - ListOfTables: - - aws_rds_db_instance - - aws_rds_db_parameter_group - Parameters: [] + CASE + WHEN i.engine NOT IN ('sqlserver', 'postgres') THEN 'skip' + WHEN p.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN i.engine NOT IN ('sqlserver', 'postgres') THEN title || ' has ' || engine || ' engine type.' + WHEN p.name IS NOT NULL THEN title || ' connections are SSL encrypted.' + ELSE title || ' connections are not SSL encrypted.' + END AS reason + FROM + instance_pg AS i + LEFT JOIN pg_with_ssl_enabled AS p ON p.name = i.pg_name Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB instances connections should be encrypted \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_copy_tags_to_snapshot_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_copy_tags_to_snapshot_enabled.yaml old mode 100755 new mode 100644 index a1be9eb30..ee7972ca1 --- a/compliance/controls/aws/aws_rds_db_instance_copy_tags_to_snapshot_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_copy_tags_to_snapshot_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether RDS DB instances are configured to copy all tags to snapshots when the snapshots are created. ID: aws_rds_db_instance_copy_tags_to_snapshot_enabled -Title: "RDS DB instances should be configured to copy tags to snapshots" -Description: "This control checks whether RDS DB instances are configured to copy all tags to snapshots when the snapshots are created." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when copy_tags_to_snapshot then 'ok'\n else 'alarm'\n end as status,\n case\n when copy_tags_to_snapshot then title || ' copy tags to snapshot enabled.'\n else title || ' copy tags to snapshot disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN copy_tags_to_snapshot THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN copy_tags_to_snapshot THEN title || ' copy tags to snapshot enabled.' + ELSE title || ' copy tags to snapshot disabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: low Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS DB instances should be configured to copy tags to snapshots \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_deletion_protection_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_deletion_protection_enabled.yaml old mode 100755 new mode 100644 index c2aad8d52..7d7d2302a --- a/compliance/controls/aws/aws_rds_db_instance_deletion_protection_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_deletion_protection_enabled.yaml @@ -1,13 +1,35 @@ +Description: Ensure AWS Relational Database Service (AWS RDS) instances have deletion protection enabled. ID: aws_rds_db_instance_deletion_protection_enabled -Title: "RDS DB instances should have deletion protection enabled" -Description: "Ensure AWS Relational Database Service (AWS RDS) instances have deletion protection enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when engine like any(array['aurora%', 'docdb', 'neptune']) then 'skip'\n when deletion_protection then 'ok'\n else 'alarm'\n end status,\n case\n when engine like any(array['aurora%', 'docdb', 'neptune']) then title || ' has engine ' || engine || ' cluster, deletion protection is set at cluster level.'\n when deletion_protection then title || ' deletion protection enabled.'\n else title || ' deletion protection not enabled.'\n end reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine LIKE ANY(ARRAY['aurora%', 'docdb', 'neptune']) THEN 'skip' + WHEN deletion_protection THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN engine LIKE ANY(ARRAY['aurora%', 'docdb', 'neptune']) THEN + title || ' has engine ' || engine || ' cluster, deletion protection is set at cluster level.' + WHEN deletion_protection THEN + title || ' deletion protection enabled.' + ELSE + title || ' deletion protection not enabled.' + END reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: high Tags: category: @@ -24,12 +46,12 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -38,5 +60,4 @@ Tags: - AWS/RDS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: RDS DB instances should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 31ea165ef..2dc68849f --- a/compliance/controls/aws/aws_rds_db_instance_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_encryption_at_rest_enabled.yaml @@ -1,13 +1,30 @@ +Description: To help protect data at rest, ensure that encryption is enabled for your AWS Relational Database Service (AWS RDS) instances. ID: aws_rds_db_instance_encryption_at_rest_enabled -Title: "RDS DB instance encryption at rest should be enabled" -Description: "To help protect data at rest, ensure that encryption is enabled for your AWS Relational Database Service (AWS RDS) instances." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: high Tags: category: @@ -30,12 +47,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +65,4 @@ Tags: - AWS/RDS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: RDS DB instance encryption at rest should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_events_subscription.yaml b/compliance/controls/aws/aws_rds_db_instance_events_subscription.yaml old mode 100755 new mode 100644 index 0e02aab11..720468e22 --- a/compliance/controls/aws/aws_rds_db_instance_events_subscription.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_events_subscription.yaml @@ -1,30 +1,41 @@ +Description: This control checks whether an AWS RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs. ID: aws_rds_db_instance_events_subscription -Title: "An RDS event notifications subscription should be configured for critical database instance events" -Description: "This control checks whether an AWS RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when source_type <> 'db-instance' then 'skip' - when source_type = 'db-instance' and enabled and event_categories_list @> '["failure", "maintenance", "configuration change"]' then 'ok' - else 'alarm' - end as status, - case - when source_type <> 'db-instance' then cust_subscription_id || ' event subscription of ' || source_type || ' type.' - when source_type like 'db-instance' and enabled and event_categories_list @> '["failure", "maintenance", "configuration change"]' then cust_subscription_id || ' event subscription enabled for critical instance events.' - else cust_subscription_id || ' event subscription missing critical instance events.' - end as reason - , region, account_id - from - aws_rds_db_event_subscription; - PrimaryTable: aws_rds_db_event_subscription ListOfTables: - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_rds_db_event_subscription + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN source_type <> 'db-instance' THEN 'skip' + WHEN source_type = 'db-instance' + AND enabled + AND event_categories_list @> '["failure", "maintenance", "configuration change"]' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN source_type <> 'db-instance' THEN + cust_subscription_id || ' event subscription of ' || source_type || ' type.' + WHEN source_type LIKE 'db-instance' + AND enabled + AND event_categories_list @> '["failure", "maintenance", "configuration change"]' + THEN + cust_subscription_id || ' event subscription enabled for critical instance events.' + ELSE + cust_subscription_id || ' event subscription missing critical instance events.' + END AS reason, + region, + account_id + FROM + aws_rds_db_event_subscription; Severity: low Tags: aws_foundational_security: @@ -39,5 +50,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: An RDS event notifications subscription should be configured for critical database instance events \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_iam_authentication_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_iam_authentication_enabled.yaml old mode 100755 new mode 100644 index 4974db1c0..beb3859ca --- a/compliance/controls/aws/aws_rds_db_instance_iam_authentication_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_iam_authentication_enabled.yaml @@ -1,13 +1,30 @@ +Description: Checks if an AWS Relational Database Service (AWS RDS) instance has AWS Identity and Access Management (IAM) authentication enabled. ID: aws_rds_db_instance_iam_authentication_enabled -Title: "RDS DB instances should have iam authentication enabled" -Description: "Checks if an AWS Relational Database Service (AWS RDS) instance has AWS Identity and Access Management (IAM) authentication enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when iam_database_authentication_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when iam_database_authentication_enabled then title || ' IAM authentication enabled.'\n else title || ' IAM authentication not enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN iam_database_authentication_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN iam_database_authentication_enabled THEN title || ' IAM authentication enabled.' + ELSE title || ' IAM authentication not enabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: medium Tags: aws_foundational_security: @@ -15,12 +32,11 @@ Tags: category: - Compliance foundational_security_category: - - passwordless_aauthentication + - passwordless_authentication foundational_security_item_id: - rds_10 plugin: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS DB instances should have IAM authentication enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_in_backup_plan.yaml b/compliance/controls/aws/aws_rds_db_instance_in_backup_plan.yaml old mode 100755 new mode 100644 index a9fe8df12..9d77f9204 --- a/compliance/controls/aws/aws_rds_db_instance_in_backup_plan.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_in_backup_plan.yaml @@ -1,14 +1,63 @@ +Description: To help with data back-up processes, ensure your AWS Relational Database Service (AWS RDS) instances are a part of an AWS Backup plan. ID: aws_rds_db_instance_in_backup_plan -Title: "RDS DB instances should be in a backup plan" -Description: "To help with data back-up processes, ensure your AWS Relational Database Service (AWS RDS) instances are a part of an AWS Backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with mapped_with_id as (\n select\n jsonb_agg(elems) as mapped_ids\n from\n aws_backup_selection,\n jsonb_array_elements(resources) as elems\n group by backup_plan_id\n),\nmapped_with_tags as (\n select\n jsonb_agg(elems ->> 'ConditionKey') as mapped_tags\n from\n aws_backup_selection,\n jsonb_array_elements(list_of_tags) as elems\n group by backup_plan_id\n),\nbacked_up_instance as (\n select\n i.db_instance_identifier\n from\n aws_rds_db_instance as i\n join mapped_with_id as t on t.mapped_ids ?| array[i.arn]\n union\n select\n i.db_instance_identifier\n from\n aws_rds_db_instance as i\n join mapped_with_tags as t on t.mapped_tags ?| array(select jsonb_object_keys(tags))\n)\nselect\n i.arn as resource,\n i.og_account_id as og_account_id,\n i.og_resource_id as og_resource_id,\n case\n when b.db_instance_identifier is null then 'alarm'\n else 'ok'\n end as status,\n case\n when b.db_instance_identifier is null then i.title || ' not in backup plan.'\n else i.title || ' in backup plan.'\n end as reason\n \n , i.region, i.account_id\nfrom\n aws_rds_db_instance as i\n left join backed_up_instance as b on i.db_instance_identifier = b.db_instance_identifier;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_backup_selection - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + WITH mapped_with_id AS ( + SELECT + jsonb_agg(elems) AS mapped_ids + FROM + aws_backup_selection, + jsonb_array_elements(resources) AS elems + GROUP BY + backup_plan_id + ), + mapped_with_tags AS ( + SELECT + jsonb_agg(elems ->> 'ConditionKey') AS mapped_tags + FROM + aws_backup_selection, + jsonb_array_elements(list_of_tags) AS elems + GROUP BY + backup_plan_id + ), + backed_up_instance AS ( + SELECT + i.db_instance_identifier + FROM + aws_rds_db_instance AS i + JOIN mapped_with_id AS t ON t.mapped_ids ?| ARRAY[i.arn] + UNION + SELECT + i.db_instance_identifier + FROM + aws_rds_db_instance AS i + JOIN mapped_with_tags AS t ON t.mapped_tags ?| ARRAY(SELECT jsonb_object_keys(tags)) + ) + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN b.db_instance_identifier IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.db_instance_identifier IS NULL THEN i.title || ' not in backup plan.' + ELSE i.title || ' in backup plan.' + END AS reason, + i.region, + i.account_id + FROM + aws_rds_db_instance AS i + LEFT JOIN backed_up_instance AS b ON i.db_instance_identifier = b.db_instance_identifier Severity: high Tags: category: @@ -29,12 +78,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -47,5 +96,4 @@ Tags: - AWS/RDS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: RDS DB instances should be in a backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_in_vpc.yaml b/compliance/controls/aws/aws_rds_db_instance_in_vpc.yaml old mode 100755 new mode 100644 index 861ed8967..bd692caa0 --- a/compliance/controls/aws/aws_rds_db_instance_in_vpc.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_in_vpc.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether an RDS instance is deployed in a VPC (EC2-VPC). ID: aws_rds_db_instance_in_vpc -Title: "RDS instances should be deployed in a VPC" -Description: "This control checks whether an RDS instance is deployed in a VPC (EC2-VPC)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when vpc_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when vpc_id is null then title || ' is not in VPC.'\n else title || ' is in VPC ' || vpc_id || '.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vpc_id IS NULL THEN title || ' is not in VPC.' + ELSE title || ' is in VPC ' || vpc_id || '.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: high Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS instances should be deployed in a VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_logging_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_logging_enabled.yaml old mode 100755 new mode 100644 index b6c0a129f..40d1b0e9f --- a/compliance/controls/aws/aws_rds_db_instance_logging_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_logging_enabled.yaml @@ -1,13 +1,55 @@ +Description: To help with logging and monitoring within your environment, ensure AWS Relational Database Service (AWS RDS) logging is enabled. ID: aws_rds_db_instance_logging_enabled -Title: "Database logging should be enabled" -Description: "To help with logging and monitoring within your environment, ensure AWS Relational Database Service (AWS RDS) logging is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when engine = 'docdb' then 'skip'\n when engine like any (array ['mariadb', '%mysql']) and enabled_cloudwatch_logs_exports ?& array ['audit','error','general','slowquery'] then 'ok'\n when engine like any (array['%postgres%']) and enabled_cloudwatch_logs_exports ?& array ['postgresql','upgrade'] then 'ok'\n when engine like 'oracle%' and enabled_cloudwatch_logs_exports ?& array ['alert','audit', 'trace','listener'] then 'ok'\n when engine = 'sqlserver-ex' and enabled_cloudwatch_logs_exports ?& array ['error'] then 'ok'\n when engine like 'sqlserver%' and enabled_cloudwatch_logs_exports ?& array ['error','agent'] then 'ok'\n else 'alarm'\n end as status,\n case\n when engine = 'docdb' then title || ' is docdb instance.'\n when engine like any (array ['mariadb', '%mysql']) and enabled_cloudwatch_logs_exports ?& array ['audit','error','general','slowquery']\n then title || ' ' || engine || ' logging enabled.'\n when engine like any (array['%postgres%']) and enabled_cloudwatch_logs_exports ?& array ['postgresql','upgrade']\n then title || ' ' || engine || ' logging enabled.'\n when engine like 'oracle%' and enabled_cloudwatch_logs_exports ?& array ['alert','audit', 'trace','listener']\n then title || ' ' || engine || ' logging enabled.'\n when engine = 'sqlserver-ex' and enabled_cloudwatch_logs_exports ?& array ['error']\n then title || ' ' || engine || ' logging enabled.'\n when engine like 'sqlserver%' and enabled_cloudwatch_logs_exports ?& array ['error','agent']\n then title || ' ' || engine || ' logging enabled.'\n else title || ' logging not enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine = 'docdb' THEN 'skip' + WHEN engine LIKE ANY (ARRAY['mariadb', '%mysql']) + AND enabled_cloudwatch_logs_exports ?& ARRAY['audit', 'error', 'general', 'slowquery'] THEN 'ok' + WHEN engine LIKE ANY (ARRAY['%postgres%']) + AND enabled_cloudwatch_logs_exports ?& ARRAY['postgresql', 'upgrade'] THEN 'ok' + WHEN engine LIKE 'oracle%' + AND enabled_cloudwatch_logs_exports ?& ARRAY['alert', 'audit', 'trace', 'listener'] THEN 'ok' + WHEN engine = 'sqlserver-ex' + AND enabled_cloudwatch_logs_exports ?& ARRAY['error'] THEN 'ok' + WHEN engine LIKE 'sqlserver%' + AND enabled_cloudwatch_logs_exports ?& ARRAY['error', 'agent'] THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine = 'docdb' THEN title || ' is docdb instance.' + WHEN engine LIKE ANY (ARRAY['mariadb', '%mysql']) + AND enabled_cloudwatch_logs_exports ?& ARRAY['audit', 'error', 'general', 'slowquery'] + THEN title || ' ' || engine || ' logging enabled.' + WHEN engine LIKE ANY (ARRAY['%postgres%']) + AND enabled_cloudwatch_logs_exports ?& ARRAY['postgresql', 'upgrade'] + THEN title || ' ' || engine || ' logging enabled.' + WHEN engine LIKE 'oracle%' + AND enabled_cloudwatch_logs_exports ?& ARRAY['alert', 'audit', 'trace', 'listener'] + THEN title || ' ' || engine || ' logging enabled.' + WHEN engine = 'sqlserver-ex' + AND enabled_cloudwatch_logs_exports ?& ARRAY['error'] + THEN title || ' ' || engine || ' logging enabled.' + WHEN engine LIKE 'sqlserver%' + AND enabled_cloudwatch_logs_exports ?& ARRAY['error', 'agent'] + THEN title || ' ' || engine || ' logging enabled.' + ELSE title || ' logging not enabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: high Tags: category: @@ -30,12 +72,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +90,4 @@ Tags: - AWS/RDS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Database logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_multiple_az_enabled.yaml b/compliance/controls/aws/aws_rds_db_instance_multiple_az_enabled.yaml old mode 100755 new mode 100644 index e34db73c0..514b5b04a --- a/compliance/controls/aws/aws_rds_db_instance_multiple_az_enabled.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_multiple_az_enabled.yaml @@ -1,13 +1,32 @@ +Description: Multi-AZ support in AWS Relational Database Service (AWS RDS) provides enhanced availability and durability for database instances. ID: aws_rds_db_instance_multiple_az_enabled -Title: "RDS DB instance multiple az should be enabled" -Description: "Multi-AZ support in AWS Relational Database Service (AWS RDS) provides enhanced availability and durability for database instances." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when engine ilike any (array ['%aurora-mysql%', '%aurora-postgres%']) then 'skip'\n when multi_az then 'ok'\n else 'alarm'\n end as status,\n case\n when engine ilike any (array ['%aurora-mysql%', '%aurora-postgres%']) then title || ' cluster instance.'\n when multi_az then title || ' Multi-AZ enabled.'\n else title || ' Multi-AZ disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine ILIKE ANY (ARRAY ['%aurora-mysql%', '%aurora-postgres%']) THEN 'skip' + WHEN multi_az THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine ILIKE ANY (ARRAY ['%aurora-mysql%', '%aurora-postgres%']) THEN title || ' cluster instance.' + WHEN multi_az THEN title || ' Multi-AZ enabled.' + ELSE title || ' Multi-AZ disabled.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: low Tags: category: @@ -26,17 +45,16 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS DB instance multiple az should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_no_default_admin_name.yaml b/compliance/controls/aws/aws_rds_db_instance_no_default_admin_name.yaml old mode 100755 new mode 100644 index ceb1ea35d..9038f6dcc --- a/compliance/controls/aws/aws_rds_db_instance_no_default_admin_name.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_no_default_admin_name.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether you've changed the administrative username for AWS Relational Database Service (AWS RDS) database instances from the default value. The control fails if the administrative username is set to the default value. ID: aws_rds_db_instance_no_default_admin_name -Title: "RDS database instances should use a custom administrator username" -Description: "This control checks whether you've changed the administrative username for AWS Relational Database Service (AWS RDS) database instances from the default value. The control fails if the administrative username is set to the default value." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when master_user_name in ('admin','postgres') then 'alarm'\n else 'ok'\n end status,\n case\n when master_user_name in ('admin', 'postgres') then title || ' using default master user name.'\n else title || ' not using default master user name.'\n end reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN master_user_name IN ('admin', 'postgres') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN master_user_name IN ('admin', 'postgres') THEN title || ' using default master user name.' + ELSE title || ' not using default master user name.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: RDS database instances should use a custom administrator username \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_postgres_not_exposed_to_local_file_read_vulnerability.yaml b/compliance/controls/aws/aws_rds_db_instance_postgres_not_exposed_to_local_file_read_vulnerability.yaml old mode 100755 new mode 100644 index 71711428b..422a1f372 --- a/compliance/controls/aws/aws_rds_db_instance_postgres_not_exposed_to_local_file_read_vulnerability.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_postgres_not_exposed_to_local_file_read_vulnerability.yaml @@ -1,30 +1,38 @@ +Description: This control checks whether AWS PostgreSQL DB instance are exposed to local file read vulnerability by ensuring that AWS RDS PostgreSQL instances use a non-vulnerable version of the log_fdw. ID: aws_rds_db_instance_postgres_not_exposed_to_local_file_read_vulnerability -Title: "RDS PostgreSQL DB instances should not be exposed to local file read vulnerability" -Description: "This control checks whether AWS PostgreSQL DB isntance are exposed to local file read vulnerability by ensuring that AWS RDS PostgreSQL instances use a non-vulnerable version of the log_fdw." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not engine = 'postgres' then 'skip' - when engine = 'postgres' and engine_version like any (array ['10.11', '10.12', '10.13', '11.6', '11.7', '11.8']) then 'alarm' - else 'ok' - end as status, - case - when not engine = 'postgres' then title || ' not PostgreSQL edition.' - when engine = 'postgres' and engine_version like any (array ['13.2','13.1','12.6','12.5','12.4','12.3','12.2','11.11','11.10','11.9','11.8','11.7','11.6','11.5','11.4','11.3','11.2','11.1','10.16','10.15','10.14','10.13','10.12','10.11','10.10','10.9','10.7','10.6','10.5','10.4','10.3','10.1','9.6.21','9.6.20','9.6.19','9.6.18','9.6.17','9.6.16','9.6.15','9.6.14','9.6.12','9.6.11','9.6.10','9.6.9','9.6.8','9.6.6','9.6.5','9.6.3','9.6.2','9.6.1','9.5','9.4','9.3']) then title || ' exposed to local file read vulnerability.' - else title || ' not exposed to local file read vulnerability.' - end as reason - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT engine = 'postgres' THEN 'skip' + WHEN engine = 'postgres' AND engine_version LIKE ANY (ARRAY ['10.11', '10.12', '10.13', '11.6', '11.7', '11.8']) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT engine = 'postgres' THEN title || ' not PostgreSQL edition.' + WHEN engine = 'postgres' AND engine_version LIKE ANY (ARRAY + [ + '13.2','13.1','12.6','12.5','12.4','12.3','12.2','11.11','11.10','11.9', + '11.8','11.7','11.6','11.5','11.4','11.3','11.2','11.1','10.16','10.15', + '10.14','10.13','10.12','10.11','10.10','10.9','10.7','10.6','10.5', + '10.4','10.3','10.1','9.6.21','9.6.20','9.6.19','9.6.18','9.6.17', + '9.6.16','9.6.15','9.6.14','9.6.12','9.6.11','9.6.10','9.6.9','9.6.8', + '9.6.6','9.6.5','9.6.3','9.6.2','9.6.1','9.5','9.4','9.3' + ]) THEN title || ' exposed to local file read vulnerability.' + ELSE title || ' not exposed to local file read vulnerability.' + END AS reason + FROM + aws_rds_db_instance; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS PostgreSQL DB instances should not be exposed to local file read vulnerability \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_prohibit_public_access.yaml b/compliance/controls/aws/aws_rds_db_instance_prohibit_public_access.yaml old mode 100755 new mode 100644 index 7082a1959..0bb1fbd39 --- a/compliance/controls/aws/aws_rds_db_instance_prohibit_public_access.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_prohibit_public_access.yaml @@ -1,13 +1,30 @@ +Description: Manage access to resources in the AWS Cloud by ensuring that AWS Relational Database Service (AWS RDS) instances are not public. ID: aws_rds_db_instance_prohibit_public_access -Title: "RDS DB instances should prohibit public access" -Description: "Manage access to resources in the AWS Cloud by ensuring that AWS Relational Database Service (AWS RDS) instances are not public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when publicly_accessible then 'alarm'\n else 'ok'\n end status,\n case\n when publicly_accessible then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end reason\n \n , region, account_id\nfrom\n aws_rds_db_instance;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: high Tags: audit_manager_control_tower: @@ -30,12 +47,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +65,4 @@ Tags: - AWS/RDS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: RDS DB instances should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_instance_protected_by_backup_plan.yaml b/compliance/controls/aws/aws_rds_db_instance_protected_by_backup_plan.yaml old mode 100755 new mode 100644 index f609c79af..98ba8b0f7 --- a/compliance/controls/aws/aws_rds_db_instance_protected_by_backup_plan.yaml +++ b/compliance/controls/aws/aws_rds_db_instance_protected_by_backup_plan.yaml @@ -1,14 +1,40 @@ +Description: Ensure that AWS Relational Database Service (AWS RDS) instances are protected by a backup plan. The rule is non-compliant if the AWS RDS Database instance is not covered by a backup plan. ID: aws_rds_db_instance_protected_by_backup_plan -Title: "RDS DB instance should be protected by backup plan" -Description: "Ensure that AWS Relational Database Service (AWS RDS) instances are protected by a backup plan. The rule is non-compliant if the AWS RDS Database instance is not covered by a backup plan." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with backup_protected_rds_isntance as (\n select\n resource_arn as arn\n from\n aws_backup_protected_resource as b\n where\n resource_type = 'RDS'\n)\nselect\n r.arn as resource,\n r.og_account_id as og_account_id,\n r.og_resource_id as og_resource_id,\n case\n when b.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is not null then r.title || ' is protected by backup plan.'\n else r.title || ' is not protected by backup plan.'\n end as reason\n \n , r.region, r.account_id\nfrom\n aws_rds_db_instance as r\n left join backup_protected_rds_isntance as b on r.arn = b.arn;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_backup_protected_resource - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + WITH backup_protected_rds_instance AS ( + SELECT + resource_arn AS arn + FROM + aws_backup_protected_resource AS b + WHERE + resource_type = 'RDS' + ) + SELECT + r.arn AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NOT NULL THEN r.title || ' is protected by backup plan.' + ELSE r.title || ' is not protected by backup plan.' + END AS reason, + r.region, + r.account_id + FROM + aws_rds_db_instance AS r + LEFT JOIN backup_protected_rds_instance AS b ON r.arn = b.arn; Severity: high Tags: category: @@ -27,10 +53,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -41,5 +67,4 @@ Tags: - AWS/RDS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: RDS DB instance should be protected by backup plan \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_parameter_group_events_subscription.yaml b/compliance/controls/aws/aws_rds_db_parameter_group_events_subscription.yaml old mode 100755 new mode 100644 index 4a5e13a04..a5aad33bd --- a/compliance/controls/aws/aws_rds_db_parameter_group_events_subscription.yaml +++ b/compliance/controls/aws/aws_rds_db_parameter_group_events_subscription.yaml @@ -1,30 +1,36 @@ +Description: This control checks whether an AWS RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs. ID: aws_rds_db_parameter_group_events_subscription -Title: "An RDS event notifications subscription should be configured for critical database parameter group events" -Description: "This control checks whether an AWS RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when source_type <> 'db-parameter-group' then 'skip' - when source_type = 'db-parameter-group' and enabled and event_categories_list @> '["maintenance", "failure"]' then 'ok' - else 'alarm' - end as status, - case - when source_type <> 'db-parameter-group' then cust_subscription_id || ' event subscription of ' || source_type || ' type.' - when source_type = 'db-parameter-group' and enabled and event_categories_list @> '["configuration change"]' then cust_subscription_id || ' event subscription enabled for critical database parameter group events.' - else cust_subscription_id || ' event subscription missing critical database parameter group events.' - end as reason - , region, account_id - from - aws_rds_db_event_subscription; - PrimaryTable: aws_rds_db_event_subscription ListOfTables: - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_rds_db_event_subscription + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN source_type <> 'db-parameter-group' THEN 'skip' + WHEN source_type = 'db-parameter-group' + AND enabled + AND event_categories_list @> '["maintenance", "failure"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN source_type <> 'db-parameter-group' THEN cust_subscription_id || ' event subscription of ' || source_type || ' type.' + WHEN source_type = 'db-parameter-group' + AND enabled + AND event_categories_list @> '["configuration change"]' THEN cust_subscription_id || ' event subscription enabled for critical database parameter group events.' + ELSE cust_subscription_id || ' event subscription missing critical database parameter group events.' + END AS reason, + region, + account_id + FROM + aws_rds_db_event_subscription; Severity: low Tags: aws_foundational_security: @@ -39,5 +45,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: An RDS event notifications subscription should be configured for critical database parameter group events \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_security_group_events_subscription.yaml b/compliance/controls/aws/aws_rds_db_security_group_events_subscription.yaml old mode 100755 new mode 100644 index df4f10de9..1d0919503 --- a/compliance/controls/aws/aws_rds_db_security_group_events_subscription.yaml +++ b/compliance/controls/aws/aws_rds_db_security_group_events_subscription.yaml @@ -1,30 +1,39 @@ +Description: This control checks whether an AWS RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs. ID: aws_rds_db_security_group_events_subscription -Title: "An RDS event notifications subscription should be configured for critical database security group events" -Description: "This control checks whether an AWS RDS event subscription exists with notifications enabled for the following source type, event category key-value pairs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when source_type <> 'db-security-group' then 'skip' - when source_type = 'db-security-group' and enabled and event_categories_list @> '["failure", "configuration change"]' then 'ok' - else 'alarm' - end as status, - case - when source_type <> 'db-security-group' then cust_subscription_id || ' event subscription of ' || source_type || ' type.' - when source_type = 'db-security-group' and enabled and event_categories_list @> '["failure", "configuration change"]' then cust_subscription_id || ' event subscription enabled for critical database security group events.' - else cust_subscription_id || ' event subscription missing critical database security group events.' - end as reason - , region, account_id - from - aws_rds_db_event_subscription; - PrimaryTable: aws_rds_db_event_subscription ListOfTables: - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_rds_db_event_subscription + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN source_type <> 'db-security-group' THEN 'skip' + WHEN source_type = 'db-security-group' + AND enabled + AND event_categories_list @> '["failure", "configuration change"]' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN source_type <> 'db-security-group' + THEN cust_subscription_id || ' event subscription of ' || source_type || ' type.' + WHEN source_type = 'db-security-group' + AND enabled + AND event_categories_list @> '["failure", "configuration change"]' + THEN cust_subscription_id || ' event subscription enabled for critical database security group events.' + ELSE cust_subscription_id || ' event subscription missing critical database security group events.' + END AS reason, + region, + account_id + FROM + aws_rds_db_event_subscription; Severity: low Tags: aws_foundational_security: @@ -39,5 +48,4 @@ Tags: - aws service: - AWS/RDS -IntegrationType: - - aws_cloud_account +Title: An RDS event notifications subscription should be configured for critical database security group events \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_snapshot_encrypted_at_rest.yaml b/compliance/controls/aws/aws_rds_db_snapshot_encrypted_at_rest.yaml old mode 100755 new mode 100644 index 0b8d3dfc3..ab17d6d78 --- a/compliance/controls/aws/aws_rds_db_snapshot_encrypted_at_rest.yaml +++ b/compliance/controls/aws/aws_rds_db_snapshot_encrypted_at_rest.yaml @@ -1,14 +1,54 @@ +Description: Ensure that encryption is enabled for your AWS Relational Database Service (AWS RDS) snapshots. ID: aws_rds_db_snapshot_encrypted_at_rest -Title: "RDS DB snapshots should be encrypted at rest" -Description: "Ensure that encryption is enabled for your AWS Relational Database Service (AWS RDS) snapshots." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_rds_db_cluster_snapshot' as og_table_name,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_cluster_snapshot\n)\nunion\n(\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_rds_db_snapshot' as og_table_name,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n , region, account_id\nfrom\n aws_rds_db_snapshot\n);\n" - PrimaryTable: "" ListOfTables: - aws_rds_db_cluster_snapshot - aws_rds_db_snapshot Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_rds_db_cluster_snapshot' AS og_table_name, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster_snapshot + ) + UNION + ( + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_rds_db_snapshot' AS og_table_name, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason, + region, + account_id + FROM + aws_rds_db_snapshot + ); Severity: high Tags: audit_manager_control_tower: @@ -29,12 +69,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -47,5 +87,4 @@ Tags: - AWS/RDS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: RDS DB snapshots should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_rds_db_snapshot_prohibit_public_access.yaml b/compliance/controls/aws/aws_rds_db_snapshot_prohibit_public_access.yaml old mode 100755 new mode 100644 index 0e8bf5bd4..ae89049a9 --- a/compliance/controls/aws/aws_rds_db_snapshot_prohibit_public_access.yaml +++ b/compliance/controls/aws/aws_rds_db_snapshot_prohibit_public_access.yaml @@ -1,14 +1,56 @@ +Description: Manage access to resources in the AWS Cloud by ensuring that AWS Relational Database Service (AWS RDS) instances are not public. ID: aws_rds_db_snapshot_prohibit_public_access -Title: "RDS snapshots should prohibit public access" -Description: "Manage access to resources in the AWS Cloud by ensuring that AWS Relational Database Service (AWS RDS) instances are not public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_rds_db_cluster_snapshot' as og_table_name,\n case\n when cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then title || ' publicly restorable.'\n else title || ' not publicly restorable.'\n end reason\n \n , region, account_id\nfrom\n aws_rds_db_cluster_snapshot,\n jsonb_array_elements(db_cluster_snapshot_attributes) as cluster_snapshot\n)\nunion\n(\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n 'aws_rds_db_snapshot' as og_table_name,\n case\n when database_snapshot -> 'AttributeValues' = '[\"all\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when database_snapshot -> 'AttributeValues' = '[\"all\"]' then title || ' publicly restorable.'\n else title || ' not publicly restorable.'\n end reason\n \n , region, account_id\nfrom\n aws_rds_db_snapshot,\n jsonb_array_elements(db_snapshot_attributes) as database_snapshot\n);\n" - PrimaryTable: "" ListOfTables: - aws_rds_db_cluster_snapshot - aws_rds_db_snapshot Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_rds_db_cluster_snapshot' AS og_table_name, + CASE + WHEN cluster_snapshot -> 'AttributeValues' = '["all"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN cluster_snapshot -> 'AttributeValues' = '["all"]' THEN title || ' publicly restorable.' + ELSE title || ' not publicly restorable.' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster_snapshot, + jsonb_array_elements(db_cluster_snapshot_attributes) AS cluster_snapshot + ) + UNION + ( + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'aws_rds_db_snapshot' AS og_table_name, + CASE + WHEN database_snapshot -> 'AttributeValues' = '["all"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN database_snapshot -> 'AttributeValues' = '["all"]' THEN title || ' publicly restorable.' + ELSE title || ' not publicly restorable.' + END AS reason, + region, + account_id + FROM + aws_rds_db_snapshot, + jsonb_array_elements(db_snapshot_attributes) AS database_snapshot + ); Severity: high Tags: audit_manager_control_tower: @@ -31,12 +73,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -49,5 +91,4 @@ Tags: - AWS/RDS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: RDS snapshots should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_audit_logging_enabled.yaml b/compliance/controls/aws/aws_redshift_cluster_audit_logging_enabled.yaml old mode 100755 new mode 100644 index ef0b99e9a..7624a5819 --- a/compliance/controls/aws/aws_redshift_cluster_audit_logging_enabled.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_audit_logging_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control ensures if redshift clusters are logging audits to a specific bucket. The rule is non-compliant if audit logging is not enabled for a redshift cluster or if the 'bucketNames' parameter is provided but the audit logging destination does not match. ID: aws_redshift_cluster_audit_logging_enabled -Title: "AWS Redshift audit logging should be enabled" -Description: "This control ensures if redshift clusters are logging audits to a specific bucket. The rule is no compliant if audit logging is not enabled for a redshift cluster or if the 'bucketNames' parameter is provided but the audit logging destination does not match." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when logging_status ->> 'LoggingEnabled' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when logging_status ->> 'LoggingEnabled' = 'true' then title || ' logging enabled.'\n else title || ' logging disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_redshift_cluster;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logging_status ->> 'LoggingEnabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN logging_status ->> 'LoggingEnabled' = 'true' THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason, + region, + account_id + FROM + aws_redshift_cluster; Severity: high Tags: category: @@ -24,5 +41,4 @@ Tags: - AWS/Redshift soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: AWS Redshift audit logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_automatic_snapshots_min_7_days.yaml b/compliance/controls/aws/aws_redshift_cluster_automatic_snapshots_min_7_days.yaml old mode 100755 new mode 100644 index 1ac839f45..d56574192 --- a/compliance/controls/aws/aws_redshift_cluster_automatic_snapshots_min_7_days.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_automatic_snapshots_min_7_days.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether AWS Redshift clusters have automated snapshots enabled. It also checks whether the snapshot retention period is greater than or equal to seven. ID: aws_redshift_cluster_automatic_snapshots_min_7_days -Title: "AWS Redshift clusters should have automatic snapshots enabled" -Description: "This control checks whether AWS Redshift clusters have automated snapshots enabled. It also checks whether the snapshot retention period is greater than or equal to seven." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when automated_snapshot_retention_period >= 7 then 'ok'\n else 'alarm'\n end as status,\n case\n when automated_snapshot_retention_period >= 7 then title || ' automatic snapshots enabled with retention period greater than equals 7 days.'\n else title || ' automatic snapshots enabled with retention period less than 7 days.'\n end as reason\n \n , region, account_id\nfrom\n aws_redshift_cluster;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN automated_snapshot_retention_period >= 7 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN automated_snapshot_retention_period >= 7 THEN title || ' automatic snapshots enabled with retention period greater than equals 7 days.' + ELSE title || ' automatic snapshots enabled with retention period less than 7 days.' + END AS reason, + region, + account_id + FROM + aws_redshift_cluster; Severity: medium Tags: category: @@ -32,10 +49,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +65,4 @@ Tags: - AWS/Redshift soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: AWS Redshift clusters should have automatic snapshots enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_automatic_upgrade_major_versions_enabled.yaml b/compliance/controls/aws/aws_redshift_cluster_automatic_upgrade_major_versions_enabled.yaml old mode 100755 new mode 100644 index 946cd92d3..f810f6c45 --- a/compliance/controls/aws/aws_redshift_cluster_automatic_upgrade_major_versions_enabled.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_automatic_upgrade_major_versions_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether automatic major version upgrades are enabled for the AWS Redshift cluster. ID: aws_redshift_cluster_automatic_upgrade_major_versions_enabled -Title: "AWS Redshift should have automatic upgrades to major versions enabled" -Description: "This control checks whether automatic major version upgrades are enabled for the AWS Redshift cluster." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when allow_version_upgrade then 'ok'\n else 'alarm'\n end as status,\n case\n when allow_version_upgrade then title || ' automatic upgrades to major versions enabled.'\n else title || ' automatic upgrades to major versions disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_redshift_cluster;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN allow_version_upgrade THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN allow_version_upgrade THEN title || ' automatic upgrades to major versions enabled.' + ELSE title || ' automatic upgrades to major versions disabled.' + END AS reason, + region, + account_id + FROM + aws_redshift_cluster; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/Redshift -IntegrationType: - - aws_cloud_account +Title: AWS Redshift should have automatic upgrades to major versions enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_encryption_in_transit_enabled.yaml b/compliance/controls/aws/aws_redshift_cluster_encryption_in_transit_enabled.yaml old mode 100755 new mode 100644 index 79487f72f..87afea45e --- a/compliance/controls/aws/aws_redshift_cluster_encryption_in_transit_enabled.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_encryption_in_transit_enabled.yaml @@ -1,14 +1,44 @@ +Description: Ensure that your AWS Redshift clusters require TLS/SSL encryption to connect to SQL clients. ID: aws_redshift_cluster_encryption_in_transit_enabled -Title: "Redshift cluster encryption in transit should be enabled" -Description: "Ensure that your AWS Redshift clusters require TLS/SSL encryption to connect to SQL clients." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with pg_with_ssl as (\nselect\n name as pg_name,\n p ->> 'ParameterName' as parameter_name,\n p ->> 'ParameterValue' as parameter_value\nfrom\n aws_redshift_parameter_group,\n jsonb_array_elements(parameters) as p\nwhere\n p ->> 'ParameterName' = 'require_ssl'\n and p ->> 'ParameterValue' = 'true'\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when cpg ->> 'ParameterGroupName' in (select pg_name from pg_with_ssl ) then 'ok'\n else 'alarm'\n end as status,\n case\n when cpg ->> 'ParameterGroupName' in (select pg_name from pg_with_ssl ) then title || ' encryption in transit enabled.'\n else title || ' encryption in transit disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_redshift_cluster,\n jsonb_array_elements(cluster_parameter_groups) as cpg;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster - aws_redshift_parameter_group Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + WITH pg_with_ssl AS ( + SELECT + name AS pg_name, + p ->> 'ParameterName' AS parameter_name, + p ->> 'ParameterValue' AS parameter_value + FROM + aws_redshift_parameter_group, + jsonb_array_elements(parameters) AS p + WHERE + p ->> 'ParameterName' = 'require_ssl' + AND p ->> 'ParameterValue' = 'true' + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN cpg ->> 'ParameterGroupName' IN (SELECT pg_name FROM pg_with_ssl) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cpg ->> 'ParameterGroupName' IN (SELECT pg_name FROM pg_with_ssl) THEN title || ' encryption in transit enabled.' + ELSE title || ' encryption in transit disabled.' + END AS reason, + region, + account_id + FROM + aws_redshift_cluster, + jsonb_array_elements(cluster_parameter_groups) AS cpg; Severity: high Tags: category: @@ -29,12 +59,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -47,5 +77,4 @@ Tags: - AWS/Redshift soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Redshift cluster encryption in transit should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_encryption_logging_enabled.yaml b/compliance/controls/aws/aws_redshift_cluster_encryption_logging_enabled.yaml old mode 100755 new mode 100644 index 7646abe0a..834154aa4 --- a/compliance/controls/aws/aws_redshift_cluster_encryption_logging_enabled.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_encryption_logging_enabled.yaml @@ -1,13 +1,32 @@ +Description: To protect data at rest, ensure that encryption is enabled for your AWS Redshift clusters. You must also ensure that required configurations are deployed on AWS Redshift clusters. The audit logging should be enabled to provide information about connections and user activities in the database. ID: aws_redshift_cluster_encryption_logging_enabled -Title: "Redshift cluster audit logging and encryption should be enabled" -Description: "To protect data at rest, ensure that encryption is enabled for your AWS Redshift clusters. You must also ensure that required configurations are deployed on AWS Redshift clusters. The audit logging should be enabled to provide information about connections and user activities in the database." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when not encrypted then 'alarm'\n when not (logging_status ->> 'LoggingEnabled') :: boolean then 'alarm'\n else 'ok'\n end as status,\n case\n when not encrypted then title || ' not encrypted.'\n when not (logging_status ->> 'LoggingEnabled')::boolean then title || ' audit logging not enabled.'\n else title || ' audit logging and encryption enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_redshift_cluster;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT encrypted THEN 'alarm' + WHEN NOT (logging_status ->> 'LoggingEnabled')::BOOLEAN THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT encrypted THEN title || ' not encrypted.' + WHEN NOT (logging_status ->> 'LoggingEnabled')::BOOLEAN THEN title || ' audit logging not enabled.' + ELSE title || ' audit logging and encryption enabled.' + END AS reason, + region, + account_id + FROM + aws_redshift_cluster; Severity: high Tags: category: @@ -32,12 +51,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -50,5 +69,4 @@ Tags: - AWS/Redshift soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Redshift cluster audit logging and encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_enhanced_vpc_routing_enabled.yaml b/compliance/controls/aws/aws_redshift_cluster_enhanced_vpc_routing_enabled.yaml old mode 100755 new mode 100644 index 9cf01c664..b2e7bed1f --- a/compliance/controls/aws/aws_redshift_cluster_enhanced_vpc_routing_enabled.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_enhanced_vpc_routing_enabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure that AWS Redshift cluster has 'enhancedVpcRouting' enabled. The rule is non-compliant if 'enhancedVpcRouting' is not enabled or if the configuration.enhancedVpcRouting field is 'false'. ID: aws_redshift_cluster_enhanced_vpc_routing_enabled -Title: "AWS Redshift enhanced VPC routing should be enabled" -Description: "Ensure that AWS Redshift cluster has 'enhancedVpcRouting' enabled. The rule is non-compliant if 'enhancedVpcRouting' is not enabled or if the configuration.enhancedVpcRouting field is 'false'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when enhanced_vpc_routing then 'ok'\n else 'alarm'\n end as status,\n case\n when enhanced_vpc_routing then title || ' enhanced VPC routing enabled.'\n else title || ' enhanced VPC routing disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_redshift_cluster;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enhanced_vpc_routing THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enhanced_vpc_routing THEN title || ' enhanced VPC routing enabled.' + ELSE title || ' enhanced VPC routing disabled.' + END AS reason, + region, + account_id + FROM + aws_redshift_cluster; Severity: medium Tags: category: @@ -18,15 +35,14 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: - aws service: - AWS/Redshift -IntegrationType: - - aws_cloud_account +Title: AWS Redshift enhanced VPC routing should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_kms_enabled.yaml b/compliance/controls/aws/aws_redshift_cluster_kms_enabled.yaml old mode 100755 new mode 100644 index f67968d1f..63867b26f --- a/compliance/controls/aws/aws_redshift_cluster_kms_enabled.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_kms_enabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure that AWS Redshift clusters are using a specified AWS Key Management Service (AWS KMS) key for encryption. The rule is compliant if encryption is enabled and the cluster is encrypted with the key provided in the kmsKeyArn parameter. The rule is non-compliant if the cluster is not encrypted or encrypted with another key. ID: aws_redshift_cluster_kms_enabled -Title: "AWS Redshift clusters should be encrypted with KMS" -Description: "Ensure that AWS Redshift clusters are using a specified AWS Key Management Service (AWS KMS) key for encryption. The rule is compliant if encryption is enabled and the cluster is encrypted with the key provided in the kmsKeyArn parameter. The rule is non-compliant if the cluster is not encrypted or encrypted with another key." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when encrypted and kms_key_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted and kms_key_id is not null then title || ' encrypted with KMS.'\n else title || ' not encrypted with KMS'\n end as reason\n \n , region, account_id\nfrom\n aws_redshift_cluster;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN encrypted AND kms_key_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted AND kms_key_id IS NOT NULL THEN title || ' encrypted with KMS.' + ELSE title || ' not encrypted with KMS.' + END AS reason, + region, + account_id + FROM + aws_redshift_cluster; Severity: high Tags: category: @@ -36,5 +53,4 @@ Tags: - "true" service: - AWS/Redshift -IntegrationType: - - aws_cloud_account +Title: AWS Redshift clusters should be encrypted with KMS \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_maintenance_settings_check.yaml b/compliance/controls/aws/aws_redshift_cluster_maintenance_settings_check.yaml old mode 100755 new mode 100644 index 00961e018..3670ca80d --- a/compliance/controls/aws/aws_redshift_cluster_maintenance_settings_check.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_maintenance_settings_check.yaml @@ -1,13 +1,30 @@ +Description: Ensure whether AWS Redshift clusters have the specified maintenance settings. Redshift clusters `allowVersionUpgrade` should be set to `true` and `automatedSnapshotRetentionPeriod` should be greater than 7. ID: aws_redshift_cluster_maintenance_settings_check -Title: "AWS Redshift should have required maintenance settings" -Description: "Ensure whether AWS Redshift clusters have the specified maintenance settings. Redshift clusters `allowVersionUpgrade` should be set to `true` and `automatedSnapshotRetentionPeriod` should be greater than 7." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when allow_version_upgrade and automated_snapshot_retention_period >= 7 then 'ok'\n else 'alarm'\n end as status,\n case\n when allow_version_upgrade and automated_snapshot_retention_period >= 7 then title || ' has the required maintenance settings.'\n else title || ' does not have required maintenance settings.'\n end as reason\n \n , region, account_id\nfrom\n aws_redshift_cluster;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN allow_version_upgrade AND automated_snapshot_retention_period >= 7 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN allow_version_upgrade AND automated_snapshot_retention_period >= 7 THEN title || ' has the required maintenance settings.' + ELSE title || ' does not have required maintenance settings.' + END AS reason, + region, + account_id + FROM + aws_redshift_cluster; Severity: medium Tags: category: @@ -20,10 +37,10 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -32,5 +49,4 @@ Tags: - "true" service: - AWS/Redshift -IntegrationType: - - aws_cloud_account +Title: AWS Redshift should have required maintenance settings \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_no_default_admin_name.yaml b/compliance/controls/aws/aws_redshift_cluster_no_default_admin_name.yaml old mode 100755 new mode 100644 index 02fd55872..d67772613 --- a/compliance/controls/aws/aws_redshift_cluster_no_default_admin_name.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_no_default_admin_name.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether a AWS Redshift cluster has changed the admin username from its default value. This control will fail if the admin username for a Redshift cluster is set to awsuser. ID: aws_redshift_cluster_no_default_admin_name -Title: "AWS Redshift clusters should not use the default Admin username" -Description: "This control checks whether a AWS Redshift cluster has changed the admin username from its default value. This control will fail if the admin username for a Redshift cluster is set to awsuser." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when master_username = 'awsuser' then 'alarm'\n else 'ok'\n end as status,\n case\n when master_username = 'awsuser' then title || ' using default master user name.'\n else title || ' not using default master user name.'\n end as reason\n \n , region, account_id\nfrom\n aws_redshift_cluster;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN master_username = 'awsuser' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN master_username = 'awsuser' THEN title || ' using default master user name.' + ELSE title || ' not using default master user name.' + END AS reason, + region, + account_id + FROM + aws_redshift_cluster; Severity: high Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/Redshift -IntegrationType: - - aws_cloud_account +Title: AWS Redshift clusters should not use the default Admin username \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_no_default_database_name.yaml b/compliance/controls/aws/aws_redshift_cluster_no_default_database_name.yaml old mode 100755 new mode 100644 index 36cc4b5ac..e28cccf93 --- a/compliance/controls/aws/aws_redshift_cluster_no_default_database_name.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_no_default_database_name.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether an AWS Redshift cluster has changed the database name from its default value. The control will fail if the database name for a Redshift cluster is set to dev. ID: aws_redshift_cluster_no_default_database_name -Title: "Redshift clusters should not use the default database name" -Description: "This control checks whether an AWS Redshift cluster has changed the database name from its default value. The control will fail if the database name for a Redshift cluster is set to dev." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when db_name = 'dev' then 'alarm'\n else 'ok'\n end as status,\n case\n when db_name = 'dev' then title || ' using default database name.'\n else title || ' not using default database name.'\n end as reason\n \n , region, account_id\nfrom\n aws_redshift_cluster;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN db_name = 'dev' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN db_name = 'dev' THEN title || ' using default database name.' + ELSE title || ' not using default database name.' + END AS reason, + region, + account_id + FROM + aws_redshift_cluster; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/Redshift -IntegrationType: - - aws_cloud_account +Title: Redshift clusters should not use the default database name \ No newline at end of file diff --git a/compliance/controls/aws/aws_redshift_cluster_prohibit_public_access.yaml b/compliance/controls/aws/aws_redshift_cluster_prohibit_public_access.yaml old mode 100755 new mode 100644 index 9a50df06c..4031f36bf --- a/compliance/controls/aws/aws_redshift_cluster_prohibit_public_access.yaml +++ b/compliance/controls/aws/aws_redshift_cluster_prohibit_public_access.yaml @@ -1,13 +1,30 @@ +Description: Manage access to resources in the AWS Cloud by ensuring that AWS Redshift clusters are not public. ID: aws_redshift_cluster_prohibit_public_access -Title: "Redshift clusters should prohibit public access" -Description: "Manage access to resources in the AWS Cloud by ensuring that AWS Redshift clusters are not public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n cluster_namespace_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when publicly_accessible then 'alarm'\n else 'ok'\n end status,\n case\n when publicly_accessible then title || ' publicly accessible.'\n else title || ' not publicly accessible.'\n end reason\n\n \n , region, account_id\nfrom\n aws_redshift_cluster;\n" - PrimaryTable: aws_redshift_cluster ListOfTables: - aws_redshift_cluster Parameters: [] + PrimaryTable: aws_redshift_cluster + QueryToExecute: | + SELECT + cluster_namespace_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END reason, + region, + account_id + FROM + aws_redshift_cluster; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/Redshift soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Redshift clusters should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_root_accounts_needs_to_have_mfa.yaml b/compliance/controls/aws/aws_root_accounts_needs_to_have_mfa.yaml old mode 100755 new mode 100644 index af57f27f4..aa3745f87 --- a/compliance/controls/aws/aws_root_accounts_needs_to_have_mfa.yaml +++ b/compliance/controls/aws/aws_root_accounts_needs_to_have_mfa.yaml @@ -1,35 +1,36 @@ +Description: AWS Root Account cannot have API Keys ID: aws_root_accounts_needs_to_have_mfa -Title: "AWS Root Accounts needs to have MFA" -Description: "AWS Root Account cannot have API Keys" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - user_name as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not mfa_active then 'alarm' - else 'ok' - end as status, - case - when not mfa_active then 'root account MFA is not activated' - else 'root account MFA is activated' - end as reason - , region, account_id - from - aws_iam_credential_report - where - user_name = ''; - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT mfa_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT mfa_active THEN 'root account MFA is not activated' + ELSE 'root account MFA is activated' + END AS reason, + region, + account_id + FROM + aws_iam_credential_report + WHERE + user_name = ''; Severity: medium Tags: category: - Compliance score_service_name: - AWS Identity and Access Management (IAM) -IntegrationType: - - aws_cloud_account +Title: AWS Root Accounts needs to have MFA \ No newline at end of file diff --git a/compliance/controls/aws/aws_route53_domain_auto_renew_enabled.yaml b/compliance/controls/aws/aws_route53_domain_auto_renew_enabled.yaml old mode 100755 new mode 100644 index f520bbe5f..cae21345e --- a/compliance/controls/aws/aws_route53_domain_auto_renew_enabled.yaml +++ b/compliance/controls/aws/aws_route53_domain_auto_renew_enabled.yaml @@ -1,14 +1,28 @@ +Description: This control ensures that AWS Route 53 Auto Renew feature is enabled to automatically renew your domain names as the expiration date approaches. ID: aws_route53_domain_auto_renew_enabled -Title: "Route 53 domains auto renew should be enabled" -Description: "This control ensures that AWS Route 53 Auto Renew feature is enabled to automatically renew your domain names as the expiration date approaches." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when auto_renew then 'ok'\n else 'alarm'\n end as status,\n case\n when auto_renew then title || ' auto renew enabled.'\n else title || ' auto renew disabled.'\n end as reason\n \n \nfrom\n aws_route53_domain;" - PrimaryTable: aws_route53_domain ListOfTables: - aws_route53_domain Parameters: [] + PrimaryTable: aws_route53_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN auto_renew THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_renew THEN title || ' auto renew enabled.' + ELSE title || ' auto renew disabled.' + END AS reason + FROM + aws_route53_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Route 53 domains auto renew should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_route53_domain_expires_30_days.yaml b/compliance/controls/aws/aws_route53_domain_expires_30_days.yaml old mode 100755 new mode 100644 index 251454750..b8310f61d --- a/compliance/controls/aws/aws_route53_domain_expires_30_days.yaml +++ b/compliance/controls/aws/aws_route53_domain_expires_30_days.yaml @@ -1,25 +1,25 @@ +Description: This control ensures that all the domain names registered with AWS Route 53 or transferred to AWS Route 53 are renewed 30 days before their validity period ends. ID: aws_route53_domain_expires_30_days -Title: "Route 53 domains should not expire within next 30 days" -Description: "This control ensures that all the domain names registered with AWS Route 53 or transferred to AWS Route 53 are renewed 30 days before their validity period ends." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when date(expiration_date) - date(current_date) >= 30 then 'ok' - else 'alarm' - end as status, - title || ' set to expire in ' || extract(day from expiration_date - current_date) || ' days.' as reason - from - aws_route53_domain; - PrimaryTable: aws_route53_domain ListOfTables: - aws_route53_domain Parameters: [] + PrimaryTable: aws_route53_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN DATE(expiration_date) - DATE(current_date) >= 30 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' set to expire in ' || EXTRACT(DAY FROM expiration_date - current_date) || ' days.' AS reason + FROM + aws_route53_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Route 53 domains should not expire within next 30 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_route53_domain_expires_7_days.yaml b/compliance/controls/aws/aws_route53_domain_expires_7_days.yaml old mode 100755 new mode 100644 index c72442070..65246c238 --- a/compliance/controls/aws/aws_route53_domain_expires_7_days.yaml +++ b/compliance/controls/aws/aws_route53_domain_expires_7_days.yaml @@ -1,25 +1,25 @@ +Description: This controls ensures that all the domain names registered with AWS Route 53 or transferred to AWS Route 53 are renewed 7 days before their validity period ends. ID: aws_route53_domain_expires_7_days -Title: "Route 53 domains should not expire within next 7 days" -Description: "This controls ensures that all the domain names registered with AWS Route 53 or transferred to AWS Route 53 are renewed 7 days before their validity period ends." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when date(expiration_date) - date(current_date) >= 7 then 'ok' - else 'alarm' - end as status, - title || ' set to expire in ' || extract(day from expiration_date - current_date) || ' days.' as reason - from - aws_route53_domain; - PrimaryTable: aws_route53_domain ListOfTables: - aws_route53_domain Parameters: [] + PrimaryTable: aws_route53_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN DATE(expiration_date) - DATE(current_date) >= 7 THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' set to expire in ' || EXTRACT(DAY FROM expiration_date - current_date) || ' days.' AS reason + FROM + aws_route53_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Route 53 domains should not expire within next 7 days \ No newline at end of file diff --git a/compliance/controls/aws/aws_route53_domain_not_expired.yaml b/compliance/controls/aws/aws_route53_domain_not_expired.yaml old mode 100755 new mode 100644 index eabf1f712..a37fb235f --- a/compliance/controls/aws/aws_route53_domain_not_expired.yaml +++ b/compliance/controls/aws/aws_route53_domain_not_expired.yaml @@ -1,14 +1,28 @@ +Description: This control identifies any expired domain names registered with AWS Route 53. When the expired domain names are not restored promptly, they will become available for others to register. Restoring on time your Route 53 expired domains will allow you to reestablish full control over their registration. ID: aws_route53_domain_not_expired -Title: "Route 53 domains should not be expired" -Description: "This control identifes any expired domain names registered with AWS Route 53. When the expired domain names are not restored promptly, they will become available for others to register. Restoring on time your Route 53 expired domains will allow you to reestablish full control over their registration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when expiration_date < (current_date - interval '1' minute) then 'alarm'\n else 'ok'\n end as status,\n case\n when expiration_date < (current_date - interval '1' minute) then title || ' expired on ' || to_char(expiration_date, 'DD-Mon-YYYY') || '.'\n else title || ' set to expire in ' || extract(day from expiration_date - current_date) || ' days.'\n end as reason\n \n \nfrom\n aws_route53_domain;" - PrimaryTable: aws_route53_domain ListOfTables: - aws_route53_domain Parameters: [] + PrimaryTable: aws_route53_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN expiration_date < (CURRENT_DATE - INTERVAL '1' MINUTE) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expiration_date < (CURRENT_DATE - INTERVAL '1' MINUTE) THEN title || ' expired on ' || TO_CHAR(expiration_date, 'DD-Mon-YYYY') || '.' + ELSE title || ' set to expire in ' || EXTRACT(DAY FROM expiration_date - CURRENT_DATE) || ' days.' + END AS reason + FROM + aws_route53_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Route 53 domains should not be expired \ No newline at end of file diff --git a/compliance/controls/aws/aws_route53_domain_privacy_protection_enabled.yaml b/compliance/controls/aws/aws_route53_domain_privacy_protection_enabled.yaml old mode 100755 new mode 100644 index a864d5402..49367012d --- a/compliance/controls/aws/aws_route53_domain_privacy_protection_enabled.yaml +++ b/compliance/controls/aws/aws_route53_domain_privacy_protection_enabled.yaml @@ -1,28 +1,28 @@ +Description: Ensure that your AWS Route 53 domains have Privacy Protection feature enabled in order to hide all their contact information from WHOIS queries and reduce the amount of spam received. The feature allows you to conceal your personal phone number, email and physical address for the domain names registered and/or transferred to AWS Route 53 service. ID: aws_route53_domain_privacy_protection_enabled -Title: "Route53 domains privacy protection should be enabled" -Description: "Ensure that your AWS Route 53 domains have Privacy Protection feature enabled in order to hide all their contact information from WHOIS queries and reduce the amount of spam received. The feature allows you to conceal your personal phone number, email and physical address for the domain names registered and/or transferred to AWS Route 53 service." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when admin_privacy then 'ok' - else 'alarm' - end as status, - case - when admin_privacy then title || ' privacy protection enabled.' - else title || ' privacy protection disabled.' - end as reason - from - aws_route53_domain; - PrimaryTable: aws_route53_domain ListOfTables: - aws_route53_domain Parameters: [] + PrimaryTable: aws_route53_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN admin_privacy THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN admin_privacy THEN title || ' privacy protection enabled.' + ELSE title || ' privacy protection disabled.' + END AS reason + FROM + aws_route53_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Route53 domains privacy protection should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_route53_domain_transfer_lock_enabled.yaml b/compliance/controls/aws/aws_route53_domain_transfer_lock_enabled.yaml old mode 100755 new mode 100644 index 746679da7..c00470523 --- a/compliance/controls/aws/aws_route53_domain_transfer_lock_enabled.yaml +++ b/compliance/controls/aws/aws_route53_domain_transfer_lock_enabled.yaml @@ -1,28 +1,28 @@ +Description: Ensure Route 53 registered domains are locked to prevent any unauthorized transfers to another domain name registrar. ID: aws_route53_domain_transfer_lock_enabled -Title: "Route 53 domains should have transfer lock enabled" -Description: "Ensure Route 53 registered domains are locked to prevent any unauthorized transfers to another domain name registrar." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when transfer_lock then 'ok' - else 'alarm' - end as status, - case - when transfer_lock then title || ' transfer lock enabled.' - else title || ' transfer lock disabled.' - end reason - from - aws_route53_domain; - PrimaryTable: aws_route53_domain ListOfTables: - aws_route53_domain Parameters: [] + PrimaryTable: aws_route53_domain + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN transfer_lock THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN transfer_lock THEN title || ' transfer lock enabled.' + ELSE title || ' transfer lock disabled.' + END AS reason + FROM + aws_route53_domain; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Route 53 domains should have transfer lock enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_route53_zone_query_logging_enabled.yaml b/compliance/controls/aws/aws_route53_zone_query_logging_enabled.yaml old mode 100755 new mode 100644 index 6bc93e2e3..29b3351d0 --- a/compliance/controls/aws/aws_route53_zone_query_logging_enabled.yaml +++ b/compliance/controls/aws/aws_route53_zone_query_logging_enabled.yaml @@ -1,30 +1,30 @@ +Description: Ensure Route 53 zones have query logging enabled. ID: aws_route53_zone_query_logging_enabled -Title: "Route 53 zones should have query logging enabled" -Description: "Ensure Route 53 zones have query logging enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when private_zone then 'skip' - when query_logging_configs is not null or jsonb_array_length(query_logging_configs) > 0 then 'ok' - else 'alarm' - end as status, - case - when private_zone then title || ' is private hosted zone.' - when query_logging_configs is not null or jsonb_array_length(query_logging_configs) > 0 then title || ' query logging to CloudWatch enabled.' - else title || ' query logging to CloudWatch disabled.' - end as reason - from - aws_route53_zone; - PrimaryTable: aws_route53_zone ListOfTables: - aws_route53_zone Parameters: [] + PrimaryTable: aws_route53_zone + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN private_zone THEN 'skip' + WHEN query_logging_configs IS NOT NULL OR jsonb_array_length(query_logging_configs) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN private_zone THEN title || ' is private hosted zone.' + WHEN query_logging_configs IS NOT NULL OR jsonb_array_length(query_logging_configs) > 0 THEN title || ' query logging to CloudWatch enabled.' + ELSE title || ' query logging to CloudWatch disabled.' + END AS reason + FROM + aws_route53_zone; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Route 53 zones should have query logging enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_access_point_restrict_public_access.yaml b/compliance/controls/aws/aws_s3_access_point_restrict_public_access.yaml old mode 100755 new mode 100644 index c2f6acc47..99ddd8793 --- a/compliance/controls/aws/aws_s3_access_point_restrict_public_access.yaml +++ b/compliance/controls/aws/aws_s3_access_point_restrict_public_access.yaml @@ -1,42 +1,42 @@ +Description: This control checks whether an Amazon S3 access point has block public access settings enabled. The control fails if block public access settings aren't enabled for the access point. ID: aws_s3_access_point_restrict_public_access -Title: "S3 access points should have block public access settings enabled" -Description: "This control checks whether an Amazon S3 access point has block public access settings enabled. The control fails if block public access settings aren't enabled for the access point." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - access_point_arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when block_public_acls - and block_public_policy - and ignore_public_acls - and restrict_public_buckets - then 'ok' - else 'alarm' - end as status, - case - when block_public_acls - and block_public_policy - and ignore_public_acls - and restrict_public_buckets - then name || ' all public access blocks enabled.' - else name || ' not enabled for: ' || - concat_ws(', ', - case when not block_public_acls then 'block_public_acls' end, - case when not block_public_policy then 'block_public_policy' end, - case when not ignore_public_acls then 'ignore_public_acls' end, - case when not restrict_public_buckets then 'restrict_public_buckets' end - ) || '.' - end as reason - from - aws_s3_access_point; - PrimaryTable: aws_s3_access_point ListOfTables: - aws_s3_access_point Parameters: [] + PrimaryTable: aws_s3_access_point + QueryToExecute: | + SELECT + access_point_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN name || ' all public access blocks enabled.' + ELSE name || ' not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT block_public_acls THEN 'block_public_acls' END, + CASE WHEN NOT block_public_policy THEN 'block_public_policy' END, + CASE WHEN NOT ignore_public_acls THEN 'ignore_public_acls' END, + CASE WHEN NOT restrict_public_buckets THEN 'restrict_public_buckets' END + ) || '.' + END AS reason + FROM + aws_s3_access_point; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: S3 access points should have block public access settings enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_acls_should_prohibit_user_access.yaml b/compliance/controls/aws/aws_s3_bucket_acls_should_prohibit_user_access.yaml old mode 100755 new mode 100644 index e7790ec27..dcd9dbd38 --- a/compliance/controls/aws/aws_s3_bucket_acls_should_prohibit_user_access.yaml +++ b/compliance/controls/aws/aws_s3_bucket_acls_should_prohibit_user_access.yaml @@ -1,13 +1,75 @@ +Description: This control checks whether AWS S3 buckets provide user permissions via ACLs. The control fails if ACLs are configured for managing user access on S3 buckets. ID: aws_s3_bucket_acls_should_prohibit_user_access -Title: "S3 buckets access control lists (ACLs) should not be used to manage user access to buckets" -Description: "This control checks whether AWS S3 buckets provide user permissions via ACLs. The control fails if ACLs are configured for managing user access on S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bucket_acl_details as (\n select\n arn,\n title,\n array[acl -> 'Owner' ->> 'ID'] as bucket_owner,\n array_agg(grantee_id) as bucket_acl_permissions,\n object_ownership_controls,\n region,\n account_id,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n _ctx,\n tags\n from\n aws_s3_bucket,\n jsonb_path_query(acl, '$.Grants.Grantee.ID') as grantee_id\n group by\n arn,\n title,\n acl,\n region,\n account_id,\n object_ownership_controls,\n og_account_id,\n og_resource_id,\n _ctx,\n tags\n),\nbucket_acl_checks as (\n select\n arn,\n title,\n to_jsonb(bucket_acl_permissions) - bucket_owner as additional_permissions,\n object_ownership_controls,\n region,\n account_id,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n _ctx,\n tags\n from\n bucket_acl_details\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when object_ownership_controls -> 'Rules' @> '[{\"ObjectOwnership\": \"BucketOwnerEnforced\"} ]' then 'ok'\n when jsonb_array_length(additional_permissions) = 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when object_ownership_controls -> 'Rules' @> '[{\"ObjectOwnership\": \"BucketOwnerEnforced\"} ]' then title || ' ACLs are disabled.'\n when jsonb_array_length(additional_permissions) = 0 then title || ' does not have ACLs for user access.'\n else title || ' has ACLs for user access.'\n end as reason\n \n , region, account_id\nfrom\n bucket_acl_checks;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH bucket_acl_details AS ( + SELECT + arn, + title, + ARRAY[acl -> 'Owner' ->> 'ID'] AS bucket_owner, + ARRAY_AGG(grantee_id) AS bucket_acl_permissions, + object_ownership_controls, + region, + account_id, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + _ctx, + tags + FROM + aws_s3_bucket, + JSONB_PATH_QUERY(acl, '$.Grants.Grantee.ID') AS grantee_id + GROUP BY + arn, + title, + acl, + region, + account_id, + object_ownership_controls, + og_account_id, + og_resource_id, + _ctx, + tags + ), + bucket_acl_checks AS ( + SELECT + arn, + title, + TO_JSONB(bucket_acl_permissions) - bucket_owner AS additional_permissions, + object_ownership_controls, + region, + account_id, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + _ctx, + tags + FROM + bucket_acl_details + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN object_ownership_controls -> 'Rules' @> '[{"ObjectOwnership": "BucketOwnerEnforced"}]' THEN 'ok' + WHEN JSONB_ARRAY_LENGTH(additional_permissions) = 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN object_ownership_controls -> 'Rules' @> '[{"ObjectOwnership": "BucketOwnerEnforced"}]' THEN title || ' ACLs are disabled.' + WHEN JSONB_ARRAY_LENGTH(additional_permissions) = 0 THEN title || ' does not have ACLs for user access.' + ELSE title || ' has ACLs for user access.' + END AS reason, + region, + account_id + FROM + bucket_acl_checks; Severity: medium Tags: aws_foundational_security: @@ -22,5 +84,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: S3 buckets access control lists (ACLs) should not be used to manage user access to buckets \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_cross_region_replication_enabled.yaml b/compliance/controls/aws/aws_s3_bucket_cross_region_replication_enabled.yaml old mode 100755 new mode 100644 index 77f6ac0dc..04495adcb --- a/compliance/controls/aws/aws_s3_bucket_cross_region_replication_enabled.yaml +++ b/compliance/controls/aws/aws_s3_bucket_cross_region_replication_enabled.yaml @@ -1,13 +1,39 @@ +Description: AWS Simple Storage Service (AWS S3) Cross-Region Replication (CRR) supports maintaining adequate capacity and availability. ID: aws_s3_bucket_cross_region_replication_enabled -Title: "S3 bucket cross-region replication should be enabled" -Description: "AWS Simple Storage Service (AWS S3) Cross-Region Replication (CRR) supports maintaining adequate capacity and availability." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bucket_with_replication as (\n select\n name,\n r ->> 'Status' as rep_status\n from\n aws_s3_bucket,\n jsonb_array_elements(replication -> 'Rules' ) as r\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when b.name = r.name and r.rep_status = 'Enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when b.name = r.name and r.rep_status = 'Enabled' then b.title || ' enabled with cross-region replication.'\n else b.title || ' not enabled with cross-region replication.'\n end as reason\n \n , b.region, b.account_id\nfrom\n aws_s3_bucket b\n left join bucket_with_replication r on b.name = r.name;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH bucket_with_replication AS ( + SELECT + name, + r ->> 'Status' AS rep_status + FROM + aws_s3_bucket, + jsonb_array_elements(replication -> 'Rules') AS r + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN b.name = r.name AND r.rep_status = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.name = r.name AND r.rep_status = 'Enabled' THEN b.title || ' enabled with cross-region replication.' + ELSE b.title || ' not enabled with cross-region replication.' + END AS reason, + b.region, + b.account_id + FROM + aws_s3_bucket b + LEFT JOIN bucket_with_replication r ON b.name = r.name; Severity: low Tags: category: @@ -30,12 +56,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +74,4 @@ Tags: - AWS/S3 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: S3 bucket cross-region replication should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_default_encryption_enabled.yaml b/compliance/controls/aws/aws_s3_bucket_default_encryption_enabled.yaml old mode 100755 new mode 100644 index 5fcfbcaaa..4047fd1c6 --- a/compliance/controls/aws/aws_s3_bucket_default_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_s3_bucket_default_encryption_enabled.yaml @@ -1,13 +1,30 @@ +Description: To help protect data at rest, ensure encryption is enabled for your AWS Simple Storage Service (AWS S3) buckets. ID: aws_s3_bucket_default_encryption_enabled -Title: "S3 bucket default encryption should be enabled" -Description: "To help protect data at rest, ensure encryption is enabled for your AWS Simple Storage Service (AWS S3) buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when server_side_encryption_configuration is not null then 'ok'\n else 'alarm'\n end status,\n case\n when server_side_encryption_configuration is not null then name || ' default encryption enabled.'\n else name || ' default encryption disabled.'\n end reason\n \n , region, account_id\nfrom\n aws_s3_bucket;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN server_side_encryption_configuration IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN server_side_encryption_configuration IS NOT NULL THEN name || ' default encryption enabled.' + ELSE name || ' default encryption disabled.' + END AS reason, + region, + account_id + FROM + aws_s3_bucket; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/S3 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: S3 bucket default encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_default_encryption_enabled_kms.yaml b/compliance/controls/aws/aws_s3_bucket_default_encryption_enabled_kms.yaml old mode 100755 new mode 100644 index 9054382f2..6950422e6 --- a/compliance/controls/aws/aws_s3_bucket_default_encryption_enabled_kms.yaml +++ b/compliance/controls/aws/aws_s3_bucket_default_encryption_enabled_kms.yaml @@ -1,38 +1,41 @@ +Description: To help protect data at rest, ensure encryption is enabled for your AWS Simple Storage Service (AWS S3) buckets. ID: aws_s3_bucket_default_encryption_enabled_kms -Title: "S3 bucket default encryption should be enabled with KMS" -Description: "To help protect data at rest, ensure encryption is enabled for your AWS Simple Storage Service (AWS S3) buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with data as ( - select - distinct name - from - aws_s3_bucket, - jsonb_array_elements(server_side_encryption_configuration -> 'Rules') as rules - where - rules -> 'ApplyServerSideEncryptionByDefault' ->> 'KMSMasterKeyID' is not null - ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when d.name is not null then 'ok' - else 'alarm' - end status, - case - when d.name is not null then b.name || ' default encryption with KMS enabled.' - else b.name || ' default encryption with KMS disabled.' - end reason - , b.region, b.account_id - from - aws_s3_bucket as b - left join data as d on b.name = d.name; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH data AS ( + SELECT + DISTINCT name + FROM + aws_s3_bucket, + jsonb_array_elements(server_side_encryption_configuration -> 'Rules') AS rules + WHERE + rules -> 'ApplyServerSideEncryptionByDefault' ->> 'KMSMasterKeyID' IS NOT NULL + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN d.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.name IS NOT NULL THEN b.name || ' default encryption with KMS enabled.' + ELSE b.name || ' default encryption with KMS disabled.' + END AS reason, + b.region, + b.account_id + FROM + aws_s3_bucket AS b + LEFT JOIN + data AS d ON b.name = d.name; Severity: high Tags: category: @@ -55,10 +58,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -69,5 +72,4 @@ Tags: - "true" service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: S3 bucket default encryption should be enabled with KMS \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_enforces_ssl.yaml b/compliance/controls/aws/aws_s3_bucket_enforces_ssl.yaml old mode 100755 new mode 100644 index 2bb493b19..3bec2a381 --- a/compliance/controls/aws/aws_s3_bucket_enforces_ssl.yaml +++ b/compliance/controls/aws/aws_s3_bucket_enforces_ssl.yaml @@ -1,13 +1,48 @@ +Description: To help protect data in transit, ensure that your AWS Simple Storage Service (AWS S3) buckets require requests to use Secure Socket Layer (SSL). ID: aws_s3_bucket_enforces_ssl -Title: "S3 buckets should enforce SSL" -Description: "To help protect data in transit, ensure that your AWS Simple Storage Service (AWS S3) buckets require requests to use Secure Socket Layer (SSL)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with ssl_ok as (\n select\n distinct name,\n arn,\n 'ok' as status\n from\n aws_s3_bucket,\n jsonb_array_elements(policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p,\n jsonb_array_elements_text(s -> 'Action') as a,\n jsonb_array_elements_text(s -> 'Resource') as r,\n jsonb_array_elements_text(\n s -> 'Condition' -> 'Bool' -> 'aws:securetransport'\n ) as ssl\n where\n p = '*'\n and s ->> 'Effect' = 'Deny'\n and ssl :: bool = false\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when ok.status = 'ok' then 'ok'\n else 'alarm'\n end status,\n case\n when ok.status = 'ok' then b.name || ' bucket policy enforces HTTPS.'\n else b.name || ' bucket policy does not enforce HTTPS.'\n end reason\n \n , b.region, b.account_id\nfrom\n aws_s3_bucket as b\n left join ssl_ok as ok on ok.name = b.name;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH ssl_ok AS ( + SELECT + DISTINCT name, + arn, + 'ok' AS status + FROM + aws_s3_bucket, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + jsonb_array_elements_text(s -> 'Action') AS a, + jsonb_array_elements_text(s -> 'Resource') AS r, + jsonb_array_elements_text(s -> 'Condition' -> 'Bool' -> 'aws:securetransport') AS ssl + WHERE + p = '*' + AND s ->> 'Effect' = 'Deny' + AND ssl::bool = FALSE + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN ok.status = 'ok' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ok.status = 'ok' THEN b.name || ' bucket policy enforces HTTPS.' + ELSE b.name || ' bucket policy does not enforce HTTPS.' + END AS reason, + b.region, + b.account_id + FROM + aws_s3_bucket AS b + LEFT JOIN ssl_ok AS ok ON ok.name = b.name; Severity: high Tags: category: @@ -30,12 +65,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +83,4 @@ Tags: - AWS/S3 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: S3 buckets should enforce SSL \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_event_notifications_enabled.yaml b/compliance/controls/aws/aws_s3_bucket_event_notifications_enabled.yaml old mode 100755 new mode 100644 index a20fe74b1..ce78dd98a --- a/compliance/controls/aws/aws_s3_bucket_event_notifications_enabled.yaml +++ b/compliance/controls/aws/aws_s3_bucket_event_notifications_enabled.yaml @@ -1,13 +1,36 @@ +Description: This control checks whether S3 Event Notifications are enabled on an AWS S3 bucket. This control fails if S3 Event Notifications are not enabled on a bucket. ID: aws_s3_bucket_event_notifications_enabled -Title: "S3 buckets should have event notifications enabled" -Description: "This control checks whether S3 Event Notifications are enabled on an AWS S3 bucket. This control fails if S3 Event Notifications are not enabled on a bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when\n event_notification_configuration ->> 'EventBridgeConfiguration' is null\n and event_notification_configuration ->> 'LambdaFunctionConfigurations' is null\n and event_notification_configuration ->> 'QueueConfigurations' is null\n and event_notification_configuration ->> 'TopicConfigurations' is null then 'alarm'\n else 'ok'\n end as status,\n case\n when\n event_notification_configuration ->> 'EventBridgeConfiguration' is null\n and event_notification_configuration ->> 'LambdaFunctionConfigurations' is null\n and event_notification_configuration ->> 'QueueConfigurations' is null\n and event_notification_configuration ->> 'TopicConfigurations' is null then title || ' event notifications disabled.'\n else title || ' event notifications enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_s3_bucket;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN event_notification_configuration ->> 'EventBridgeConfiguration' IS NULL + AND event_notification_configuration ->> 'LambdaFunctionConfigurations' IS NULL + AND event_notification_configuration ->> 'QueueConfigurations' IS NULL + AND event_notification_configuration ->> 'TopicConfigurations' IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN event_notification_configuration ->> 'EventBridgeConfiguration' IS NULL + AND event_notification_configuration ->> 'LambdaFunctionConfigurations' IS NULL + AND event_notification_configuration ->> 'QueueConfigurations' IS NULL + AND event_notification_configuration ->> 'TopicConfigurations' IS NULL THEN title || ' event notifications disabled.' + ELSE title || ' event notifications enabled.' + END AS reason, + region, + account_id + FROM + aws_s3_bucket; Severity: medium Tags: aws_foundational_security: @@ -22,5 +45,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: S3 buckets should have event notifications enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_lifecycle_policy_enabled.yaml b/compliance/controls/aws/aws_s3_bucket_lifecycle_policy_enabled.yaml old mode 100755 new mode 100644 index a97a4f931..c2fe39be0 --- a/compliance/controls/aws/aws_s3_bucket_lifecycle_policy_enabled.yaml +++ b/compliance/controls/aws/aws_s3_bucket_lifecycle_policy_enabled.yaml @@ -1,13 +1,40 @@ +Description: This control checks if AWS Simple Storage Service (AWS S3) buckets have lifecycle policy configured. This rule fails if AWS S3 lifecycle policy is not enabled. ID: aws_s3_bucket_lifecycle_policy_enabled -Title: "S3 buckets should have lifecycle policies configured" -Description: "This control checks if AWS Simple Storage Service (AWS S3) buckets have lifecycle policy configured. This rule fails if AWS S3 lifecycle policy is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with lifecycle_rules_enabled as (\n select\n arn\n from\n aws_s3_bucket,\n jsonb_array_elements(lifecycle_rules) as r\n where\n r ->> 'Status' = 'Enabled'\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when r.arn is not null then 'ok'\n else 'alarm'\n end status,\n case\n when r.arn is not null then name || ' lifecycle policy or rules configured.'\n else name || ' lifecycle policy or rules not configured.'\n end reason\n \n , b.region, b.account_id\nfrom\n aws_s3_bucket as b\n left join lifecycle_rules_enabled as r on r.arn = b.arn;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH lifecycle_rules_enabled AS ( + SELECT + arn + FROM + aws_s3_bucket, + jsonb_array_elements(lifecycle_rules) AS r + WHERE + r ->> 'Status' = 'Enabled' + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN r.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.arn IS NOT NULL THEN name || ' lifecycle policy or rules configured.' + ELSE name || ' lifecycle policy or rules not configured.' + END AS reason, + b.region, + b.account_id + FROM + aws_s3_bucket AS b + LEFT JOIN lifecycle_rules_enabled AS r ON r.arn = b.arn; Severity: low Tags: aws_foundational_security: @@ -22,5 +49,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: S3 buckets should have lifecycle policies configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_logging_enabled.yaml b/compliance/controls/aws/aws_s3_bucket_logging_enabled.yaml old mode 100755 new mode 100644 index 990fd2cc7..40a83dadd --- a/compliance/controls/aws/aws_s3_bucket_logging_enabled.yaml +++ b/compliance/controls/aws/aws_s3_bucket_logging_enabled.yaml @@ -1,28 +1,30 @@ +Description: AWS Simple Storage Service (AWS S3) server access logging provides a method to monitor the network for potential cybersecurity events. ID: aws_s3_bucket_logging_enabled -Title: "S3 bucket logging should be enabled" -Description: "AWS Simple Storage Service (AWS S3) server access logging provides a method to monitor the network for potential cybersecurity events." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when logging -> 'TargetBucket' is null then 'alarm' - else 'ok' - end as status, - case - when logging -> 'TargetBucket' is null then title || ' logging disabled.' - else title || ' logging enabled.' - end as reason - , region, account_id - from - aws_s3_bucket; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logging -> 'TargetBucket' IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN logging -> 'TargetBucket' IS NULL THEN title || ' logging disabled.' + ELSE title || ' logging enabled.' + END AS reason, + region, + account_id + FROM + aws_s3_bucket; Severity: low Tags: category: @@ -43,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -61,5 +63,4 @@ Tags: - AWS/S3 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: S3 bucket logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_mfa_delete_enabled.yaml b/compliance/controls/aws/aws_s3_bucket_mfa_delete_enabled.yaml old mode 100755 new mode 100644 index 4b74650f3..43340815f --- a/compliance/controls/aws/aws_s3_bucket_mfa_delete_enabled.yaml +++ b/compliance/controls/aws/aws_s3_bucket_mfa_delete_enabled.yaml @@ -1,13 +1,30 @@ +Description: Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication. ID: aws_s3_bucket_mfa_delete_enabled -Title: "Ensure MFA Delete is enabled on S3 buckets" -Description: "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when versioning_mfa_delete then 'ok'\n else 'alarm'\n end as status,\n case\n when versioning_mfa_delete then name || ' MFA delete enabled.'\n else name || ' MFA delete disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_s3_bucket;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN versioning_mfa_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN versioning_mfa_delete THEN name || ' MFA delete enabled.' + ELSE name || ' MFA delete disabled.' + END AS reason, + region, + account_id + FROM + aws_s3_bucket; Severity: high Tags: category: @@ -28,5 +45,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: Ensure MFA Delete is enabled on S3 buckets \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_not_accessible_to_all_authenticated_user.yaml b/compliance/controls/aws/aws_s3_bucket_not_accessible_to_all_authenticated_user.yaml old mode 100755 new mode 100644 index c0d8e085e..b1c859dae --- a/compliance/controls/aws/aws_s3_bucket_not_accessible_to_all_authenticated_user.yaml +++ b/compliance/controls/aws/aws_s3_bucket_not_accessible_to_all_authenticated_user.yaml @@ -1,38 +1,38 @@ +Description: This control checks whether AWS S3 bucket ACL allow access to all authenticated users. ID: aws_s3_bucket_not_accessible_to_all_authenticated_user -Title: "S3 bucket ACLs should not be accessible to all authenticated user" -Description: "This control checks whether AWS S3 bucket ACL allow access to all authenticated users." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with public_acl as ( - select - distinct name - from - aws_s3_bucket, - jsonb_array_elements(acl -> 'Grants') as grants - where - grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers' - ) - select - b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when p.name is null then 'ok' - else 'alarm' - end status, - case - when p.name is null then b.title || ' not accessible to all authenticated user.' - else b.title || ' accessible to all authenticated user.' - end as reason - from - aws_s3_bucket as b - left join public_acl as p on b.name = p.name; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH public_acl AS ( + SELECT + DISTINCT name + FROM + aws_s3_bucket, + jsonb_array_elements(acl -> 'Grants') AS grants + WHERE + grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers' + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN p.name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.name IS NULL THEN b.title || ' not accessible to all authenticated user.' + ELSE b.title || ' accessible to all authenticated user.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN public_acl AS p ON b.name = p.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: S3 bucket ACLs should not be accessible to all authenticated user \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_object_lock_enabled.yaml b/compliance/controls/aws/aws_s3_bucket_object_lock_enabled.yaml old mode 100755 new mode 100644 index 42a7b666a..d4044f3dc --- a/compliance/controls/aws/aws_s3_bucket_object_lock_enabled.yaml +++ b/compliance/controls/aws/aws_s3_bucket_object_lock_enabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure that your AWS Simple Storage Service (AWS S3) bucket has lock enabled, by default. ID: aws_s3_bucket_object_lock_enabled -Title: "S3 bucket object lock should be enabled" -Description: "Ensure that your AWS Simple Storage Service (AWS S3) bucket has lock enabled, by default." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when object_lock_configuration is null then 'alarm'\n else 'ok'\n end as status,\n case\n when object_lock_configuration is null then title || ' object lock not enabled.'\n else title || ' object lock enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_s3_bucket;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN object_lock_configuration IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN object_lock_configuration IS NULL THEN title || ' object lock not enabled.' + ELSE title || ' object lock enabled.' + END AS reason, + region, + account_id + FROM + aws_s3_bucket; Severity: high Tags: category: @@ -22,10 +39,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -34,5 +51,4 @@ Tags: - AWS/S3 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: S3 bucket object lock should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_policy_restrict_public_access.yaml b/compliance/controls/aws/aws_s3_bucket_policy_restrict_public_access.yaml old mode 100755 new mode 100644 index efdcd8056..e97299205 --- a/compliance/controls/aws/aws_s3_bucket_policy_restrict_public_access.yaml +++ b/compliance/controls/aws/aws_s3_bucket_policy_restrict_public_access.yaml @@ -1,44 +1,46 @@ +Description: This control checks that the access granted by the S3 bucket is restricted by any of the principals, federated users, service principals, IP addresses, or VPCs that you provide. The rule is compliant if a bucket policy is not present. ID: aws_s3_bucket_policy_restrict_public_access -Title: "S3 bucket policy should prohibit public access" -Description: "This control checks that the access granted by the S3 bucket is restricted by any of the principals, federated users, service principals, IP addresses, or VPCs that you provide. The rule is compliant if a bucket policy is not present." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with public_buckets as ( - select distinct arn as arn - from aws_s3_bucket - where not block_public_acls - union all - select arn as arn - from aws_s3_bucket, - jsonb_array_elements(policy_std->'Statement') as s, - jsonb_array_elements_text(s->'Principal'->'AWS') as p - where ( - p = '*' - and s->>'Effect' = 'Allow' - ) - ) - select b.arn as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when b.policy_std is null then 'info' - when p.arn is not null then 'alarm' - else 'ok' - end as status, - case - when b.policy_std is null then title || ' does not have defined policy or insufficient access to the policy.' - when p.arn is not null then title || ' publicly accessible.' - else title || ' not publicly accessible.' - end as reason, - region, - account_id - from aws_s3_bucket as b - left join public_buckets as p on p.arn = b.arn; - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH public_buckets AS ( + SELECT DISTINCT arn AS arn + FROM aws_s3_bucket + WHERE NOT block_public_acls + UNION ALL + SELECT arn AS arn + FROM aws_s3_bucket, + jsonb_array_elements(policy_std->'Statement') AS s, + jsonb_array_elements_text(s->'Principal'->'AWS') AS p + WHERE ( + p = '*' + AND s->>'Effect' = 'Allow' + ) + ) + + SELECT b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN b.policy_std IS NULL THEN 'info' + WHEN p.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.policy_std IS NULL THEN title || ' does not have defined policy or insufficient access to the policy.' + WHEN p.arn IS NOT NULL THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason, + region, + account_id + FROM aws_s3_bucket AS b + LEFT JOIN public_buckets AS p ON p.arn = b.arn; Severity: high Tags: category: @@ -59,5 +61,4 @@ Tags: - AWS/S3 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: S3 bucket policy should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_policy_restricts_cross_account_permission_changes.yaml b/compliance/controls/aws/aws_s3_bucket_policy_restricts_cross_account_permission_changes.yaml old mode 100755 new mode 100644 index 6c6faec54..295eb661d --- a/compliance/controls/aws/aws_s3_bucket_policy_restricts_cross_account_permission_changes.yaml +++ b/compliance/controls/aws/aws_s3_bucket_policy_restricts_cross_account_permission_changes.yaml @@ -1,13 +1,54 @@ +Description: This control checks whether the S3 bucket policy prevents principals from other AWS accounts from performing denied actions on resources in the S3 bucket. ID: aws_s3_bucket_policy_restricts_cross_account_permission_changes -Title: "AWS S3 permissions granted to other AWS accounts in bucket policies should be restricted" -Description: "This control checks whether the S3 bucket policy prevents principals from other AWS accounts from performing denied actions on resources in the S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with cross_account_buckets as (\n select\n distinct arn\n from\n aws_s3_bucket,\n jsonb_array_elements(policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p,\n string_to_array(p, ':') as pa,\n jsonb_array_elements_text(s -> 'Action') as a\n where\n s ->> 'Effect' = 'Allow'\n and (\n pa [5] != account_id\n or p = '*'\n )\n and a in (\n 's3:deletebucketpolicy',\n 's3:putbucketacl',\n 's3:putbucketpolicy',\n 's3:putencryptionconfiguration',\n 's3:putobjectacl'\n )\n)\nselect\n a.arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.arn is null then title || ' restricts cross-account bucket access.'\n else title || ' allows cross-account bucket access.'\n end as reason\n \n , a.region, a.account_id\nfrom\n aws_s3_bucket a\n left join cross_account_buckets b on a.arn = b.arn;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH cross_account_buckets AS ( + SELECT + DISTINCT arn + FROM + aws_s3_bucket, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p, + string_to_array(p, ':') AS pa, + jsonb_array_elements_text(s -> 'Action') AS a + WHERE + s ->> 'Effect' = 'Allow' + AND ( + pa [5] != account_id + OR p = '*' + ) + AND a IN ( + 's3:deletebucketpolicy', + 's3:putbucketacl', + 's3:putbucketpolicy', + 's3:putencryptionconfiguration', + 's3:putobjectacl' + ) + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.arn IS NULL THEN title || ' restricts cross-account bucket access.' + ELSE title || ' allows cross-account bucket access.' + END AS reason, + a.region, + a.account_id + FROM + aws_s3_bucket a + LEFT JOIN cross_account_buckets b ON a.arn = b.arn; Severity: high Tags: category: @@ -20,5 +61,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: AWS S3 permissions granted to other AWS accounts in bucket policies should be restricted \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_protected_by_macie.yaml b/compliance/controls/aws/aws_s3_bucket_protected_by_macie.yaml old mode 100755 new mode 100644 index d7aecab5c..0c1b8808b --- a/compliance/controls/aws/aws_s3_bucket_protected_by_macie.yaml +++ b/compliance/controls/aws/aws_s3_bucket_protected_by_macie.yaml @@ -1,14 +1,42 @@ +Description: AWS S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of AWS S3 buckets. ID: aws_s3_bucket_protected_by_macie -Title: "Ensure all data in AWS S3 has been discovered, classified and secured when required" -Description: "AWS S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of AWS S3 buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bucket_list as (\n select\n trim(b::text, '\"' ) as bucket_name\n from\n aws_macie2_classification_job,\n jsonb_array_elements(s3_job_definition -> 'BucketDefinitions') as d,\n jsonb_array_elements(d -> 'Buckets') as b\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when b.region = any(array['us-gov-east-1', 'us-gov-west-1']) then 'skip'\n when l.bucket_name is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.region = any(array['us-gov-east-1', 'us-gov-west-1']) then b.title || ' not protected by Macie as Macie is not supported in ' || b.region || '.'\n when l.bucket_name is not null then b.title || ' protected by Macie.'\n else b.title || ' not protected by Macie.'\n end as reason\n \n , b.region, b.account_id\nfrom\n aws_s3_bucket as b\n left join bucket_list as l on b.name = l.bucket_name;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_macie2_classification_job - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH bucket_list AS ( + SELECT + TRIM(b::text, '"') AS bucket_name + FROM + aws_macie2_classification_job, + jsonb_array_elements(s3_job_definition -> 'BucketDefinitions') AS d, + jsonb_array_elements(d -> 'Buckets') AS b + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN b.region = ANY(ARRAY['us-gov-east-1', 'us-gov-west-1']) THEN 'skip' + WHEN l.bucket_name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.region = ANY(ARRAY['us-gov-east-1', 'us-gov-west-1']) THEN b.title || ' not protected by Macie as Macie is not supported in ' || b.region || '.' + WHEN l.bucket_name IS NOT NULL THEN b.title || ' protected by Macie.' + ELSE b.title || ' not protected by Macie.' + END AS reason, + b.region, + b.account_id + FROM + aws_s3_bucket AS b + LEFT JOIN bucket_list AS l ON b.name = l.bucket_name; Severity: high Tags: category: @@ -29,5 +57,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: Ensure all data in AWS S3 has been discovered, classified and secured when required \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_restrict_public_read_access.yaml b/compliance/controls/aws/aws_s3_bucket_restrict_public_read_access.yaml old mode 100755 new mode 100644 index db667c5b1..7689805a2 --- a/compliance/controls/aws/aws_s3_bucket_restrict_public_read_access.yaml +++ b/compliance/controls/aws/aws_s3_bucket_restrict_public_read_access.yaml @@ -1,13 +1,82 @@ +Description: Manage access to resources in the AWS Cloud by only allowing authorized users, processes, and devices access to AWS Simple Storage Service (AWS S3) buckets. ID: aws_s3_bucket_restrict_public_read_access -Title: "S3 buckets should prohibit public read access" -Description: "Manage access to resources in the AWS Cloud by only allowing authorized users, processes, and devices access to AWS Simple Storage Service (AWS S3) buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with public_acl as (\n select\n distinct name\n from\n aws_s3_bucket,\n jsonb_array_elements(case jsonb_typeof(acl -> 'Grants') \n when 'array' then acl -> 'Grants' \n else '[]' end) as grants\n where\n (grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers'\n or grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers')\n and (\n grants ->> 'Permission' = 'FULL_CONTROL'\n or grants ->> 'Permission' = 'READ_ACP'\n or grants ->> 'Permission' = 'READ'\n )\n ),read_access_policy as (\n select\n distinct name\n from\n aws_s3_bucket,\n jsonb_array_elements(case jsonb_typeof(policy_std -> 'Statement') \n when 'array' then policy_std -> 'Statement' \n else '[]' end ) as s,\n jsonb_array_elements_text(case jsonb_typeof(s -> 'Action') \n when 'array' then s -> 'Action'\n else '[]' end) as action\n where\n s ->> 'Effect' = 'Allow'\n and (\n s -> 'Principal' -> 'AWS' = '[\"*\"]'\n or s ->> 'Principal' = '*'\n )\n and (\n action = '*'\n or action = '*:*'\n or action = 's3:*'\n or action ilike 's3:get%'\n or action ilike 's3:list%'\n )\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when (block_public_acls or a.name is null) and not bucket_policy_is_public then 'ok'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then 'ok'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and p.name is null) then 'ok'\n else 'alarm'\n end as status,\n case\n when (block_public_acls or a.name is null) and not bucket_policy_is_public then b.title || ' not publicly readable.'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then b.title || ' not publicly readable.'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and p.name is null) then b.title || ' not publicly readable.'\n else b.title || ' publicly readable.'\n end as reason\n \n , b.region, b.account_id\nfrom\n aws_s3_bucket as b\n left join public_acl as a on b.name = a.name\n left join read_access_policy as p on b.name = p.name;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH public_acl AS ( + SELECT DISTINCT name + FROM aws_s3_bucket, + jsonb_array_elements( + CASE jsonb_typeof(acl -> 'Grants') + WHEN 'array' THEN acl -> 'Grants' + ELSE '[]' + END + ) AS grants + WHERE + (grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers' + OR grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers') + AND ( + grants ->> 'Permission' = 'FULL_CONTROL' + OR grants ->> 'Permission' = 'READ_ACP' + OR grants ->> 'Permission' = 'READ' + ) + ), + read_access_policy AS ( + SELECT DISTINCT name + FROM aws_s3_bucket, + jsonb_array_elements( + CASE jsonb_typeof(policy_std -> 'Statement') + WHEN 'array' THEN policy_std -> 'Statement' + ELSE '[]' + END + ) AS s, + jsonb_array_elements_text( + CASE jsonb_typeof(s -> 'Action') + WHEN 'array' THEN s -> 'Action' + ELSE '[]' + END + ) AS action + WHERE + s ->> 'Effect' = 'Allow' + AND ( + s -> 'Principal' -> 'AWS' = '[\"*\"]' + OR s ->> 'Principal' = '*' + ) + AND ( + action = '*' + OR action = '*:*' + OR action = 's3:*' + OR action ILIKE 's3:get%' + OR action ILIKE 's3:list%' + ) + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN (block_public_acls OR a.name IS NULL) AND NOT bucket_policy_is_public THEN 'ok' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND block_public_policy) THEN 'ok' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND p.name IS NULL) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (block_public_acls OR a.name IS NULL) AND NOT bucket_policy_is_public THEN b.title || ' not publicly readable.' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND block_public_policy) THEN b.title || ' not publicly readable.' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND p.name IS NULL) THEN b.title || ' not publicly readable.' + ELSE b.title || ' publicly readable.' + END AS reason, + b.region, + b.account_id + FROM aws_s3_bucket AS b + LEFT JOIN public_acl AS a ON b.name = a.name + LEFT JOIN read_access_policy AS p ON b.name = p.name Severity: high Tags: audit_manager_control_tower: @@ -30,12 +99,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +117,4 @@ Tags: - AWS/S3 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: S3 buckets should prohibit public read access \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_restrict_public_write_access.yaml b/compliance/controls/aws/aws_s3_bucket_restrict_public_write_access.yaml old mode 100755 new mode 100644 index 92f04d6df..bfe06bcb6 --- a/compliance/controls/aws/aws_s3_bucket_restrict_public_write_access.yaml +++ b/compliance/controls/aws/aws_s3_bucket_restrict_public_write_access.yaml @@ -1,13 +1,68 @@ +Description: Manage access to resources in the AWS Cloud by only allowing authorized users, processes, and devices access to AWS Simple Storage Service (AWS S3) buckets. ID: aws_s3_bucket_restrict_public_write_access -Title: "S3 buckets should prohibit public write access" -Description: "Manage access to resources in the AWS Cloud by only allowing authorized users, processes, and devices access to AWS Simple Storage Service (AWS S3) buckets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with public_acl as (\n select\n distinct name\n from\n aws_s3_bucket,\n jsonb_array_elements(case jsonb_typeof(acl -> 'Grants') \n when 'array' then acl -> 'Grants' \n else '[]' end) as grants\n where\n (grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers'\n or grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers')\n and (\n grants ->> 'Permission' = 'FULL_CONTROL'\n or grants ->> 'Permission' = 'WRITE_ACP'\n or grants ->> 'Permission' = 'WRITE'\n )\n), write_access_policy as (\n select\n distinct name\n from\n aws_s3_bucket,\n jsonb_array_elements(case jsonb_typeof(policy_std -> 'Statement') \n when 'array' then policy_std -> 'Statement' \n else '[]' end ) as s,\n jsonb_array_elements_text(case jsonb_typeof(s -> 'Action') \n when 'array' then s -> 'Action'\n else '[]' end) as action\n where\n s ->> 'Effect' = 'Allow'\n and (\n s -> 'Principal' -> 'AWS' = '[\"*\"]'\n or s ->> 'Principal' = '*'\n )\n and (\n action = '*'\n or action = '*:*'\n or action = 's3:*'\n or action ilike 's3:put%'\n or action ilike 's3:delete%'\n or action ilike 's3:create%'\n or action ilike 's3:update%'\n or action ilike 's3:replicate%'\n or action ilike 's3:restore%'\n )\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when (block_public_acls or a.name is null) and not bucket_policy_is_public then 'ok'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then 'ok'\n when bucket_policy_is_public and p.name is null then 'ok'\n else 'alarm'\n end status,\n case\n when (block_public_acls or a.name is null ) and not bucket_policy_is_public then b.title || ' not publicly writable.'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then b.title || ' not publicly writable.'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and p.name is null) then b.title || ' not publicly writable.'\n else b.title || ' publicly writable.'\n end reason\n\n , b.region, b.account_id\nfrom\n aws_s3_bucket as b\n left join public_acl as a on b.name = a.name\n left join write_access_policy as p on b.name = p.name;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH public_acl AS ( + SELECT DISTINCT name + FROM aws_s3_bucket, + jsonb_array_elements(CASE jsonb_typeof(acl -> 'Grants') + WHEN 'array' THEN acl -> 'Grants' + ELSE '[]' END) AS grants + WHERE (grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers' + OR grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers') + AND (grants ->> 'Permission' = 'FULL_CONTROL' + OR grants ->> 'Permission' = 'WRITE_ACP' + OR grants ->> 'Permission' = 'WRITE') + ), + write_access_policy AS ( + SELECT DISTINCT name + FROM aws_s3_bucket, + jsonb_array_elements(CASE jsonb_typeof(policy_std -> 'Statement') + WHEN 'array' THEN policy_std -> 'Statement' + ELSE '[]' END) AS s, + jsonb_array_elements_text(CASE jsonb_typeof(s -> 'Action') + WHEN 'array' THEN s -> 'Action' + ELSE '[]' END) AS action + WHERE s ->> 'Effect' = 'Allow' + AND (s -> 'Principal' -> 'AWS' = '[\"*\"]' + OR s ->> 'Principal' = '*') + AND (action = '*' + OR action = '*:*' + OR action = 's3:*' + OR action ILIKE 's3:put%' + OR action ILIKE 's3:delete%' + OR action ILIKE 's3:create%' + OR action ILIKE 's3:update%' + OR action ILIKE 's3:replicate%' + OR action ILIKE 's3:restore%') + ) + SELECT b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN (block_public_acls OR a.name IS NULL) AND NOT bucket_policy_is_public THEN 'ok' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND block_public_policy) THEN 'ok' + WHEN bucket_policy_is_public AND p.name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (block_public_acls OR a.name IS NULL) AND NOT bucket_policy_is_public THEN b.title || ' not publicly writable.' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND block_public_policy) THEN b.title || ' not publicly writable.' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND p.name IS NULL) THEN b.title || ' not publicly writable.' + ELSE b.title || ' publicly writable.' + END AS reason, + b.region, + b.account_id + FROM aws_s3_bucket AS b + LEFT JOIN public_acl AS a ON b.name = a.name + LEFT JOIN write_access_policy AS p ON b.name = p.name; Severity: high Tags: audit_manager_control_tower: @@ -30,12 +85,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +103,4 @@ Tags: - AWS/S3 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: S3 buckets should prohibit public write access \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_static_website_hosting_disabled.yaml b/compliance/controls/aws/aws_s3_bucket_static_website_hosting_disabled.yaml old mode 100755 new mode 100644 index 7a35014bf..d3b2c93bd --- a/compliance/controls/aws/aws_s3_bucket_static_website_hosting_disabled.yaml +++ b/compliance/controls/aws/aws_s3_bucket_static_website_hosting_disabled.yaml @@ -1,14 +1,28 @@ +Description: Enabling static website on a S3 bucket requires to grant public read access to the bucket. There is a potential risk of exposure when you turn off block public access settings to make your bucket public. This is recommend to not configure static website on S3 bucket. ID: aws_s3_bucket_static_website_hosting_disabled -Title: "S3 buckets static website hosting should be disabled" -Description: "Enabling static website on a S3 bucket requires to grant public read access to the bucket. There is a potential risk of exposure when you turn off block public access settings to make your bucket public. This is recommend to not configure static website on S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when website_configuration -> 'IndexDocument' ->> 'Suffix' is not null then 'alarm'\n else 'ok'\n end status,\n case\n when website_configuration -> 'IndexDocument' ->> 'Suffix' is not null then name || ' static website hosting enabled.'\n else name || ' static website hosting disabled.'\n end reason\n \n \nfrom\n aws_s3_bucket;" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN website_configuration -> 'IndexDocument' ->> 'Suffix' IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN website_configuration -> 'IndexDocument' ->> 'Suffix' IS NOT NULL THEN name || ' static website hosting enabled.' + ELSE name || ' static website hosting disabled.' + END AS reason + FROM + aws_s3_bucket; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: S3 buckets static website hosting should be disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_versioning_and_lifecycle_policy_enabled.yaml b/compliance/controls/aws/aws_s3_bucket_versioning_and_lifecycle_policy_enabled.yaml old mode 100755 new mode 100644 index 2f4313c68..e1cd900c7 --- a/compliance/controls/aws/aws_s3_bucket_versioning_and_lifecycle_policy_enabled.yaml +++ b/compliance/controls/aws/aws_s3_bucket_versioning_and_lifecycle_policy_enabled.yaml @@ -1,13 +1,42 @@ +Description: This control checks if AWS Simple Storage Service (AWS S3) version enabled buckets have lifecycle policy configured. This rule fails if AWS S3 lifecycle policy is not enabled. ID: aws_s3_bucket_versioning_and_lifecycle_policy_enabled -Title: "S3 buckets with versioning enabled should have lifecycle policies configured" -Description: "This control checks if AWS Simple Storage Service (AWS S3) version enabled buckets have lifecycle policy configured. This rule fails if AWS S3 lifecycle policy is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with lifecycle_rules_enabled as (\n select\n arn\n from\n aws_s3_bucket,\n jsonb_array_elements(lifecycle_rules) as r\n where\n r ->> 'Status' = 'Enabled'\n)\nselect\n b.arn as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when not versioning_enabled then 'alarm'\n when versioning_enabled and r.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when not versioning_enabled then name || ' versioning diabled.'\n when versioning_enabled and r.arn is not null then name || ' lifecycle policy configured.'\n else name || ' lifecycle policy not configured.'\n end as reason\n \n , b.region, b.account_id\nfrom\n aws_s3_bucket as b\n left join lifecycle_rules_enabled as r on r.arn = b.arn;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + WITH lifecycle_rules_enabled AS ( + SELECT + arn + FROM + aws_s3_bucket, + jsonb_array_elements(lifecycle_rules) AS r + WHERE + r ->> 'Status' = 'Enabled' + ) + SELECT + b.arn AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN NOT versioning_enabled THEN 'alarm' + WHEN versioning_enabled AND r.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT versioning_enabled THEN name || ' versioning disabled.' + WHEN versioning_enabled AND r.arn IS NOT NULL THEN name || ' lifecycle policy configured.' + ELSE name || ' lifecycle policy not configured.' + END AS reason, + b.region, + b.account_id + FROM + aws_s3_bucket AS b + LEFT JOIN lifecycle_rules_enabled AS r ON r.arn = b.arn; Severity: medium Tags: aws_foundational_security: @@ -22,5 +51,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: S3 buckets with versioning enabled should have lifecycle policies configured \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_bucket_versioning_enabled.yaml b/compliance/controls/aws/aws_s3_bucket_versioning_enabled.yaml old mode 100755 new mode 100644 index df0da802f..c28f7793e --- a/compliance/controls/aws/aws_s3_bucket_versioning_enabled.yaml +++ b/compliance/controls/aws/aws_s3_bucket_versioning_enabled.yaml @@ -1,13 +1,30 @@ +Description: AWS Simple Storage Service (AWS S3) bucket versioning helps keep multiple variants of an object in the same AWS S3 bucket. ID: aws_s3_bucket_versioning_enabled -Title: "S3 bucket versioning should be enabled" -Description: "AWS Simple Storage Service (AWS S3) bucket versioning helps keep multiple variants of an object in the same AWS S3 bucket." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when versioning_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when versioning_enabled then name || ' versioning enabled.'\n else name || ' versioning disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_s3_bucket;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN versioning_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN versioning_enabled THEN name || ' versioning enabled.' + ELSE name || ' versioning disabled.' + END AS reason, + region, + account_id + FROM + aws_s3_bucket; Severity: low Tags: audit_manager_control_tower: @@ -32,12 +49,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -50,5 +67,4 @@ Tags: - AWS/S3 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: S3 bucket versioning should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_public_access_block_account.yaml b/compliance/controls/aws/aws_s3_public_access_block_account.yaml old mode 100755 new mode 100644 index bb9adb96d..af4fef61c --- a/compliance/controls/aws/aws_s3_public_access_block_account.yaml +++ b/compliance/controls/aws/aws_s3_public_access_block_account.yaml @@ -1,42 +1,43 @@ +Description: Manage access to resources in the AWS Cloud by ensuring that AWS Simple Storage Service (AWS S3) buckets cannot be publicly accessed. ID: aws_s3_public_access_block_account -Title: "S3 public access should be blocked at account level" -Description: "Manage access to resources in the AWS Cloud by ensuring that AWS Simple Storage Service (AWS S3) buckets cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn' || ':' || 'aws' || ':::' || account_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when block_public_acls - and block_public_policy - and ignore_public_acls - and restrict_public_buckets - then 'ok' - else 'alarm' - end as status, - case - when block_public_acls - and block_public_policy - and ignore_public_acls - and restrict_public_buckets - then 'Account level public access blocks enabled.' - else 'Account level public access blocks not enabled for: ' || - concat_ws(', ', - case when not (block_public_acls ) then 'block_public_acls' end, - case when not (block_public_policy) then 'block_public_policy' end, - case when not (ignore_public_acls ) then 'ignore_public_acls' end, - case when not (restrict_public_buckets) then 'restrict_public_buckets' end - ) || '.' - end as reason - , account_id - from - aws_s3_account_settings; - PrimaryTable: aws_s3_account_settings ListOfTables: - aws_s3_account_settings Parameters: [] + PrimaryTable: aws_s3_account_settings + QueryToExecute: | + SELECT + 'arn' || ':' || 'aws' || ':::' || account_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN 'Account level public access blocks enabled.' + ELSE 'Account level public access blocks not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT (block_public_acls) THEN 'block_public_acls' END, + CASE WHEN NOT (block_public_policy) THEN 'block_public_policy' END, + CASE WHEN NOT (ignore_public_acls) THEN 'ignore_public_acls' END, + CASE WHEN NOT (restrict_public_buckets) THEN 'restrict_public_buckets' END + ) || '.' + END AS reason, + account_id + FROM + aws_s3_account_settings; Severity: high Tags: category: @@ -57,12 +58,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -73,5 +74,4 @@ Tags: - AWS/S3 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: S3 public access should be blocked at account level \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_public_access_block_bucket.yaml b/compliance/controls/aws/aws_s3_public_access_block_bucket.yaml old mode 100755 new mode 100644 index 93107cf22..2cb2ae193 --- a/compliance/controls/aws/aws_s3_public_access_block_bucket.yaml +++ b/compliance/controls/aws/aws_s3_public_access_block_bucket.yaml @@ -1,13 +1,44 @@ +Description: Ensure that AWS Simple Storage Service (AWS S3) buckets are publicly accessible. This rule is non-compliant if an AWS S3 bucket is not listed in the excludedPublicBuckets parameter and bucket level settings are public. ID: aws_s3_public_access_block_bucket -Title: "S3 public access should be blocked at bucket levels" -Description: "Ensure that AWS Simple Storage Service (AWS S3) buckets are publicly accessible. This rule is non-compliant if an AWS S3 bucket is not listed in the excludedPublicBuckets parameter and bucket level settings are public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when block_public_acls\n and block_public_policy\n and ignore_public_acls\n and restrict_public_buckets\n then 'ok'\n else 'alarm'\n end as status,\n case\n when block_public_acls\n and block_public_policy\n and ignore_public_acls\n and restrict_public_buckets\n then name || ' all public access blocks enabled.'\n else name || ' not enabled for: ' ||\n concat_ws(', ',\n case when not block_public_acls then 'block_public_acls' end,\n case when not block_public_policy then 'block_public_policy' end,\n case when not ignore_public_acls then 'ignore_public_acls' end,\n case when not restrict_public_buckets then 'restrict_public_buckets' end\n ) || '.'\n end as reason\n \n , region, account_id\nfrom\n aws_s3_bucket;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN block_public_acls + AND block_public_policy + AND ignore_public_acls + AND restrict_public_buckets + THEN name || ' all public access blocks enabled.' + ELSE name || ' not enabled for: ' || + concat_ws(', ', + CASE WHEN NOT block_public_acls THEN 'block_public_acls' END, + CASE WHEN NOT block_public_policy THEN 'block_public_policy' END, + CASE WHEN NOT ignore_public_acls THEN 'ignore_public_acls' END, + CASE WHEN NOT restrict_public_buckets THEN 'restrict_public_buckets' END + ) || '.' + END AS reason, + region, + account_id + FROM + aws_s3_bucket; Severity: high Tags: category: @@ -32,5 +63,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: S3 public access should be blocked at bucket levels \ No newline at end of file diff --git a/compliance/controls/aws/aws_s3_public_access_block_bucket_account.yaml b/compliance/controls/aws/aws_s3_public_access_block_bucket_account.yaml old mode 100755 new mode 100644 index 9da59c94b..23287e760 --- a/compliance/controls/aws/aws_s3_public_access_block_bucket_account.yaml +++ b/compliance/controls/aws/aws_s3_public_access_block_bucket_account.yaml @@ -1,14 +1,48 @@ +Description: Manage access to resources in the AWS Cloud by ensuring that AWS Simple Storage Service (AWS S3) buckets cannot be publicly accessed. ID: aws_s3_public_access_block_bucket_account -Title: "S3 public access should be blocked at account and bucket levels" -Description: "Manage access to resources in the AWS Cloud by ensuring that AWS Simple Storage Service (AWS S3) buckets cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n bucket.arn as resource,\n bucket.og_account_id as og_account_id,\n bucket.og_resource_id as og_resource_id,\n case\n when (bucket.block_public_acls or s3account.block_public_acls)\n and (bucket.block_public_policy or s3account.block_public_policy)\n and (bucket.ignore_public_acls or s3account.ignore_public_acls)\n and (bucket.restrict_public_buckets or s3account.restrict_public_buckets)\n then 'ok'\n else 'alarm'\n end as status,\n case\n when (bucket.block_public_acls or s3account.block_public_acls)\n and (bucket.block_public_policy or s3account.block_public_policy)\n and (bucket.ignore_public_acls or s3account.ignore_public_acls)\n and (bucket.restrict_public_buckets or s3account.restrict_public_buckets)\n then name || ' all public access blocks enabled.'\n else name || ' not enabled for: ' ||\n concat_ws(', ',\n case when not (bucket.block_public_acls or s3account.block_public_acls) then 'block_public_acls' end,\n case when not (bucket.block_public_policy or s3account.block_public_policy) then 'block_public_policy' end,\n case when not (bucket.ignore_public_acls or s3account.ignore_public_acls) then 'ignore_public_acls' end,\n case when not (bucket.restrict_public_buckets or s3account.restrict_public_buckets) then 'restrict_public_buckets' end\n ) || '.'\n end as reason\n \n , bucket.region, bucket.account_id\nfrom\n aws_s3_bucket as bucket,\n aws_s3_account_settings as s3account\nwhere\n s3account.account_id = bucket.account_id;\n" - PrimaryTable: aws_s3_bucket ListOfTables: - aws_s3_account_settings - aws_s3_bucket Parameters: [] + PrimaryTable: aws_s3_bucket + QueryToExecute: | + SELECT + bucket.arn AS resource, + bucket.og_account_id AS og_account_id, + bucket.og_resource_id AS og_resource_id, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN name || ' all public access blocks enabled.' + ELSE name || ' not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT (bucket.block_public_acls OR s3account.block_public_acls) THEN 'block_public_acls' END, + CASE WHEN NOT (bucket.block_public_policy OR s3account.block_public_policy) THEN 'block_public_policy' END, + CASE WHEN NOT (bucket.ignore_public_acls OR s3account.ignore_public_acls) THEN 'ignore_public_acls' END, + CASE WHEN NOT (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) THEN 'restrict_public_buckets' END + ) || '.' + END AS reason, + bucket.region, + bucket.account_id + FROM + aws_s3_bucket AS bucket, + aws_s3_account_settings AS s3account + WHERE + s3account.account_id = bucket.account_id; Severity: high Tags: category: @@ -29,5 +63,4 @@ Tags: - aws service: - AWS/S3 -IntegrationType: - - aws_cloud_account +Title: S3 public access should be blocked at account and bucket levels \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_endpoint_configuration_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_sagemaker_endpoint_configuration_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 951eda23a..eba234778 --- a/compliance/controls/aws/aws_sagemaker_endpoint_configuration_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_sagemaker_endpoint_configuration_encryption_at_rest_enabled.yaml @@ -1,13 +1,30 @@ +Description: To help protect data at rest, ensure encryption with AWS Key Management Service (AWS KMS) is enabled for your SageMaker endpoint. ID: aws_sagemaker_endpoint_configuration_encryption_at_rest_enabled -Title: "SageMaker endpoint configuration encryption should be enabled" -Description: "To help protect data at rest, ensure encryption with AWS Key Management Service (AWS KMS) is enabled for your SageMaker endpoint." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kms_key_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_key_id is null then title || ' encryption at rest disabled.'\n else title || ' encryption at rest enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_sagemaker_endpoint_configuration;\n" - PrimaryTable: aws_sagemaker_endpoint_configuration ListOfTables: - aws_sagemaker_endpoint_configuration Parameters: [] + PrimaryTable: aws_sagemaker_endpoint_configuration + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' encryption at rest disabled.' + ELSE title || ' encryption at rest enabled.' + END AS reason, + region, + account_id + FROM + aws_sagemaker_endpoint_configuration; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/SageMaker soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: SageMaker endpoint configuration encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_model_in_vpc.yaml b/compliance/controls/aws/aws_sagemaker_model_in_vpc.yaml old mode 100755 new mode 100644 index 18cbdd382..e87bc9d9a --- a/compliance/controls/aws/aws_sagemaker_model_in_vpc.yaml +++ b/compliance/controls/aws/aws_sagemaker_model_in_vpc.yaml @@ -1,14 +1,28 @@ +Description: Manage access to the AWS Cloud by ensuring SageMaker models are within an AWS Virtual Private Cloud (AWS VPC). ID: aws_sagemaker_model_in_vpc -Title: "SageMaker models should be in a VPC" -Description: "Manage access to the AWS Cloud by ensuring SageMaker models are within an AWS Virtual Private Cloud (AWS VPC)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when vpc_config is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when vpc_config is not null then title || ' in VPC.'\n else title || ' not in VPC.'\n end as reason\n \n \nfrom\n aws_sagemaker_model;\n" - PrimaryTable: aws_sagemaker_model ListOfTables: - aws_sagemaker_model Parameters: [] + PrimaryTable: aws_sagemaker_model + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_config IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN vpc_config IS NOT NULL THEN title || ' in VPC.' + ELSE title || ' not in VPC.' + END AS reason + FROM + aws_sagemaker_model; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker models should be in a VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_model_network_isolation_enabled.yaml b/compliance/controls/aws/aws_sagemaker_model_network_isolation_enabled.yaml old mode 100755 new mode 100644 index a63bfefa4..29224ba33 --- a/compliance/controls/aws/aws_sagemaker_model_network_isolation_enabled.yaml +++ b/compliance/controls/aws/aws_sagemaker_model_network_isolation_enabled.yaml @@ -1,28 +1,28 @@ +Description: SageMaker models are internet-enabled by default. Network isolation should be enabled to avoid external network access to your inference containers. ID: aws_sagemaker_model_network_isolation_enabled -Title: "SageMaker models should have network isolation enabled" -Description: "SageMaker models are internet-enabled by default. Network isolation should be enabled to avoid external network access to your inference containers." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when enable_network_isolation then 'ok' - else 'alarm' - end as status, - case - when enable_network_isolation then title || ' network isolation enabled.' - else title || ' network isolation disabled.' - end as reason - from - aws_sagemaker_model; - PrimaryTable: aws_sagemaker_model ListOfTables: - aws_sagemaker_model Parameters: [] + PrimaryTable: aws_sagemaker_model + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enable_network_isolation THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_network_isolation THEN title || ' network isolation enabled.' + ELSE title || ' network isolation disabled.' + END AS reason + FROM + aws_sagemaker_model; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker models should have network isolation enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_notebook_instance_direct_internet_access_disabled.yaml b/compliance/controls/aws/aws_sagemaker_notebook_instance_direct_internet_access_disabled.yaml old mode 100755 new mode 100644 index e8c3dd161..4b77710a1 --- a/compliance/controls/aws/aws_sagemaker_notebook_instance_direct_internet_access_disabled.yaml +++ b/compliance/controls/aws/aws_sagemaker_notebook_instance_direct_internet_access_disabled.yaml @@ -1,13 +1,30 @@ +Description: Manage access to resources in the AWS Cloud by ensuring that AWS SageMaker notebooks do not allow direct internet access. ID: aws_sagemaker_notebook_instance_direct_internet_access_disabled -Title: "SageMaker notebook instances should not have direct internet access" -Description: "Manage access to resources in the AWS Cloud by ensuring that AWS SageMaker notebooks do not allow direct internet access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when direct_internet_access = 'Enabled' then 'alarm'\n else 'ok'\n end status,\n case\n when direct_internet_access = 'Enabled' then title || ' direct internet access enabled.'\n else title || ' direct internet access disabled.'\n end reason\n \n , region, account_id\nfrom\n aws_sagemaker_notebook_instance;\n" - PrimaryTable: aws_sagemaker_notebook_instance ListOfTables: - aws_sagemaker_notebook_instance Parameters: [] + PrimaryTable: aws_sagemaker_notebook_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN direct_internet_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN direct_internet_access = 'Enabled' THEN title || ' direct internet access enabled.' + ELSE title || ' direct internet access disabled.' + END reason, + region, + account_id + FROM + aws_sagemaker_notebook_instance; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/SageMaker soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: SageMaker notebook instances should not have direct internet access \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_notebook_instance_encrypted_with_kms_cmk.yaml b/compliance/controls/aws/aws_sagemaker_notebook_instance_encrypted_with_kms_cmk.yaml old mode 100755 new mode 100644 index 4da00cd0d..74b5fab7f --- a/compliance/controls/aws/aws_sagemaker_notebook_instance_encrypted_with_kms_cmk.yaml +++ b/compliance/controls/aws/aws_sagemaker_notebook_instance_encrypted_with_kms_cmk.yaml @@ -1,11 +1,17 @@ +Description: This control checks if SageMaker notebook instance storage volumes are encrypted with AWS KMS Customer Master Keys (CMKs) instead of AWS managed-keys. ID: aws_sagemaker_notebook_instance_encrypted_with_kms_cmk -Title: "SageMaker notebook instances should be encrypted using CMK" -Description: "This control checks if SageMaker notebook instance storage volumes are encrypted with AWS KMS Customer Master Keys (CMKs) instead of AWS managed-keys." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with sagemaker_notebook_instances as ( - select + ListOfTables: + - aws_sagemaker_notebook_instance + - aws_kms_key + Parameters: [] + PrimaryTable: aws_sagemaker_notebook_instance + QueryToExecute: | + WITH sagemaker_notebook_instances AS ( + SELECT arn, region, account_id, @@ -15,39 +21,33 @@ Query: _ctx, og_account_id, og_resource_id - from + FROM aws_sagemaker_notebook_instance - ), kms_keys as ( - select + ), kms_keys AS ( + SELECT arn, key_manager, enabled - from + FROM aws_kms_key ) - select - i.arn as resource, - i.og_account_id as og_account_id, - i.og_resource_id as og_resource_id, - case - when kms_key_id is null then 'alarm' - when k.key_manager = 'CUSTOMER' then 'ok' - else 'alarm' - end as status, - case - when kms_key_id is null then i.title || ' encryption disabled.' - when k.key_manager = 'CUSTOMER' then i.title || ' encryption at rest with CMK enabled.' - else i.title || ' encryption at rest with CMK disabled.' - end as reason - from - sagemaker_notebook_instances as i - left join kms_keys as k on i.kms_key_id = k.arn; - PrimaryTable: aws_sagemaker_notebook_instance - ListOfTables: - - aws_sagemaker_notebook_instance - - aws_kms_key - Parameters: [] + SELECT + i.arn AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + WHEN k.key_manager = 'CUSTOMER' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN i.title || ' encryption disabled.' + WHEN k.key_manager = 'CUSTOMER' THEN i.title || ' encryption at rest with CMK enabled.' + ELSE i.title || ' encryption at rest with CMK disabled.' + END AS reason + FROM + sagemaker_notebook_instances AS i + LEFT JOIN kms_keys AS k ON i.kms_key_id = k.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker notebook instances should be encrypted using CMK \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_notebook_instance_encryption_at_rest_enabled.yaml b/compliance/controls/aws/aws_sagemaker_notebook_instance_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index 056507902..9d1841ce0 --- a/compliance/controls/aws/aws_sagemaker_notebook_instance_encryption_at_rest_enabled.yaml +++ b/compliance/controls/aws/aws_sagemaker_notebook_instance_encryption_at_rest_enabled.yaml @@ -1,13 +1,30 @@ +Description: To help protect data at rest, ensure encryption with AWS Key Management Service (AWS KMS) is enabled for your SageMaker notebook. ID: aws_sagemaker_notebook_instance_encryption_at_rest_enabled -Title: "SageMaker notebook instance encryption should be enabled" -Description: "To help protect data at rest, ensure encryption with AWS Key Management Service (AWS KMS) is enabled for your SageMaker notebook." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kms_key_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_key_id is null then title || ' encryption at rest enabled'\n else title || ' encryption at rest not enabled'\n end as reason\n \n , region, account_id\nfrom\n aws_sagemaker_notebook_instance;\n" - PrimaryTable: aws_sagemaker_notebook_instance ListOfTables: - aws_sagemaker_notebook_instance Parameters: [] + PrimaryTable: aws_sagemaker_notebook_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN title || ' encryption at rest enabled' + ELSE title || ' encryption at rest not enabled' + END AS reason, + region, + account_id + FROM + aws_sagemaker_notebook_instance; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -46,5 +63,4 @@ Tags: - AWS/SageMaker soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: SageMaker notebook instance encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_notebook_instance_in_vpc.yaml b/compliance/controls/aws/aws_sagemaker_notebook_instance_in_vpc.yaml old mode 100755 new mode 100644 index 598affae2..8c712138e --- a/compliance/controls/aws/aws_sagemaker_notebook_instance_in_vpc.yaml +++ b/compliance/controls/aws/aws_sagemaker_notebook_instance_in_vpc.yaml @@ -1,13 +1,30 @@ +Description: Manage access to the AWS Cloud by ensuring SageMaker notebook instances are within an AWS Virtual Private Cloud (AWS VPC). ID: aws_sagemaker_notebook_instance_in_vpc -Title: "SageMaker notebook instances should be in a VPC" -Description: "Manage access to the AWS Cloud by ensuring SageMaker notebook instances are within an AWS Virtual Private Cloud (AWS VPC)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when subnet_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when subnet_id is not null then title || ' in VPC.'\n else title || ' not in VPC.'\n end as reason\n \n , region, account_id\nfrom\n aws_sagemaker_notebook_instance;\n" - PrimaryTable: aws_sagemaker_notebook_instance ListOfTables: - aws_sagemaker_notebook_instance Parameters: [] + PrimaryTable: aws_sagemaker_notebook_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN subnet_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN subnet_id IS NOT NULL THEN title || ' in VPC.' + ELSE title || ' not in VPC.' + END AS reason, + region, + account_id + FROM + aws_sagemaker_notebook_instance; Severity: high Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/SageMaker -IntegrationType: - - aws_cloud_account +Title: SageMaker notebook instances should be in a VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_notebook_instance_root_access_disabled.yaml b/compliance/controls/aws/aws_sagemaker_notebook_instance_root_access_disabled.yaml old mode 100755 new mode 100644 index a84aa8cb3..178d2557c --- a/compliance/controls/aws/aws_sagemaker_notebook_instance_root_access_disabled.yaml +++ b/compliance/controls/aws/aws_sagemaker_notebook_instance_root_access_disabled.yaml @@ -1,13 +1,30 @@ +Description: Users with root access have administrator privileges and users can access and edit all files on a notebook instance. It is recommended to disable root access to restrict users from accessing and editing all the files. ID: aws_sagemaker_notebook_instance_root_access_disabled -Title: "SageMaker notebook instances root access should be disabled" -Description: "Users with root access have administrator privileges and users can access and edit all files on a notebook instance. It is recommeneded to disable root access to restrict users from accessing and editing all the files." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when root_access = 'Disabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when root_access = 'Disabled' then title || ' root access disabled.'\n else title || ' root access enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_sagemaker_notebook_instance;\n" - PrimaryTable: aws_sagemaker_notebook_instance ListOfTables: - aws_sagemaker_notebook_instance Parameters: [] + PrimaryTable: aws_sagemaker_notebook_instance + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN root_access = 'Disabled' THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN root_access = 'Disabled' THEN title || ' root access disabled.' + ELSE title || ' root access enabled.' + END AS reason, + region, + account_id + FROM + aws_sagemaker_notebook_instance; Severity: high Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/SageMaker -IntegrationType: - - aws_cloud_account +Title: SageMaker notebook instances root access should be disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_training_job_in_vpc.yaml b/compliance/controls/aws/aws_sagemaker_training_job_in_vpc.yaml old mode 100755 new mode 100644 index e931a2822..7c77bebdb --- a/compliance/controls/aws/aws_sagemaker_training_job_in_vpc.yaml +++ b/compliance/controls/aws/aws_sagemaker_training_job_in_vpc.yaml @@ -1,28 +1,28 @@ +Description: Manage access to the AWS Cloud by ensuring SageMaker training jobs are within an AWS Virtual Private Cloud (AWS VPC). ID: aws_sagemaker_training_job_in_vpc -Title: "SageMaker training jobs should be in VPC" -Description: "Manage access to the AWS Cloud by ensuring SageMaker training jobs are within an AWS Virtual Private Cloud (AWS VPC)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when vpc_config is not null then 'ok' - else 'alarm' - end as status, - case - when vpc_config is not null then title || ' in VPC.' - else title || ' not in VPC.' - end as reason - from - aws_sagemaker_training_job; - PrimaryTable: aws_sagemaker_training_job ListOfTables: - aws_sagemaker_training_job Parameters: [] + PrimaryTable: aws_sagemaker_training_job + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_config IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN vpc_config IS NOT NULL THEN title || ' in VPC.' + ELSE title || ' not in VPC.' + END AS reason + FROM + aws_sagemaker_training_job; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker training jobs should be in VPC \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_training_job_inter_container_traffic_encryption_enabled.yaml b/compliance/controls/aws/aws_sagemaker_training_job_inter_container_traffic_encryption_enabled.yaml old mode 100755 new mode 100644 index 4ef108416..167a3dc4d --- a/compliance/controls/aws/aws_sagemaker_training_job_inter_container_traffic_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_sagemaker_training_job_inter_container_traffic_encryption_enabled.yaml @@ -1,28 +1,30 @@ +Description: Inter-container traffic encryption should be used to protect data that is transmitted between instances while performing distributed training. This control is compliant when inter-container traffic encryption is enabled. ID: aws_sagemaker_training_job_inter_container_traffic_encryption_enabled -Title: "SageMaker training jobs should be enabled with inter-container traffic encryption" -Description: "Inter-container traffic encryption shoule be used to protect data that is transmitted between instances while performing distributed training. This control in compliant when inter-container traffic encryption is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when enable_inter_container_traffic_encryption then 'ok' - else 'alarm' - end as status, - case - when enable_inter_container_traffic_encryption then title || ' inter-container traffic encryption enabled.' - else title || ' inter-container traffic encryption disabled.' - end as reason - from - aws_sagemaker_training_job; - PrimaryTable: aws_sagemaker_training_job ListOfTables: - aws_sagemaker_training_job Parameters: [] + PrimaryTable: aws_sagemaker_training_job + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enable_inter_container_traffic_encryption THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_inter_container_traffic_encryption THEN + title || ' inter-container traffic encryption enabled.' + ELSE + title || ' inter-container traffic encryption disabled.' + END AS reason + FROM + aws_sagemaker_training_job; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker training jobs should be enabled with inter-container traffic encryption \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_training_job_network_isolation_enabled.yaml b/compliance/controls/aws/aws_sagemaker_training_job_network_isolation_enabled.yaml old mode 100755 new mode 100644 index dfdf9672a..bb8ba689a --- a/compliance/controls/aws/aws_sagemaker_training_job_network_isolation_enabled.yaml +++ b/compliance/controls/aws/aws_sagemaker_training_job_network_isolation_enabled.yaml @@ -1,28 +1,28 @@ +Description: SageMaker training jobs are internet-enabled by default. Network isolation should be enabled to avoid external network access to your training. ID: aws_sagemaker_training_job_network_isolation_enabled -Title: "SageMaker training jobs should have network isolation enabled" -Description: "SageMaker training jobs are internet-enabled by default. Network isolation should be enabled to avoid external network access to your training." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when enable_network_isolation then 'ok' - else 'alarm' - end as status, - case - when enable_network_isolation then title || ' network isolation enabled.' - else title || ' network isolation disabled.' - end as reason - from - aws_sagemaker_training_job; - PrimaryTable: aws_sagemaker_training_job ListOfTables: - aws_sagemaker_training_job Parameters: [] + PrimaryTable: aws_sagemaker_training_job + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enable_network_isolation THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_network_isolation THEN title || ' network isolation enabled.' + ELSE title || ' network isolation disabled.' + END AS reason + FROM + aws_sagemaker_training_job; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker training jobs should have network isolation enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_sagemaker_training_job_volume_and_data_encryption_enabled.yaml b/compliance/controls/aws/aws_sagemaker_training_job_volume_and_data_encryption_enabled.yaml old mode 100755 new mode 100644 index 3007f3fd1..cf9943c0b --- a/compliance/controls/aws/aws_sagemaker_training_job_volume_and_data_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_sagemaker_training_job_volume_and_data_encryption_enabled.yaml @@ -1,28 +1,28 @@ +Description: Ensure that SageMaker training jobs have volumes and outputs with KMS encryption enabled in order to have a more granular control over the data-at-rest encryption/decryption process and to meet compliance requirements. ID: aws_sagemaker_training_job_volume_and_data_encryption_enabled -Title: "SageMaker training jobs volumes and outputs should have KMS encryption enabled" -Description: "Ensure that SageMaker training jobs have volumes and outputs with KMS encryption enabled in order to have a more granular control over the data-at-rest encryption/decryption process and to meet compliance requirements." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when output_data_config ->> 'KmsKeyId' is null or output_data_config ->> 'KmsKeyId' = '' then 'alarm' - else 'ok' - end as status, - case - when output_data_config ->> 'KmsKeyId' is null or output_data_config ->> 'KmsKeyId' is null or output_data_config ->> 'KmsKeyId' = '' then title || ' volume and output data encryption disabled.' - else title || ' volume and output data encryption enabled.' - end as reason - from - aws_sagemaker_training_job; - PrimaryTable: aws_sagemaker_training_job ListOfTables: - aws_sagemaker_training_job Parameters: [] + PrimaryTable: aws_sagemaker_training_job + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN output_data_config ->> 'KmsKeyId' IS NULL OR output_data_config ->> 'KmsKeyId' = '' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN output_data_config ->> 'KmsKeyId' IS NULL OR output_data_config ->> 'KmsKeyId' = '' THEN title || ' volume and output data encryption disabled.' + ELSE title || ' volume and output data encryption enabled.' + END AS reason + FROM + aws_sagemaker_training_job; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SageMaker training jobs volumes and outputs should have KMS encryption enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_secretsmanager_secret_automatic_rotation_enabled.yaml b/compliance/controls/aws/aws_secretsmanager_secret_automatic_rotation_enabled.yaml old mode 100755 new mode 100644 index 983446ea4..14ce7aea8 --- a/compliance/controls/aws/aws_secretsmanager_secret_automatic_rotation_enabled.yaml +++ b/compliance/controls/aws/aws_secretsmanager_secret_automatic_rotation_enabled.yaml @@ -1,13 +1,30 @@ +Description: This rule ensures AWS Secrets Manager secrets have rotation enabled. Rotating secrets on a regular schedule can shorten the period a secret is active, and potentially reduce the business impact if the secret is compromised. ID: aws_secretsmanager_secret_automatic_rotation_enabled -Title: "Secrets Manager secrets should have automatic rotation enabled" -Description: "This rule ensures AWS Secrets Manager secrets have rotation enabled. Rotating secrets on a regular schedule can shorten the period a secret is active, and potentially reduce the business impact if the secret is compromised." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when rotation_rules is null then 'alarm'\n else 'ok'\n end as status,\n case\n when rotation_rules is null then title || ' automatic rotation not enabled.'\n else title || ' automatic rotation enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_secretsmanager_secret;\n" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN rotation_rules IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN rotation_rules IS NULL THEN title || ' automatic rotation not enabled.' + ELSE title || ' automatic rotation enabled.' + END AS reason, + region, + account_id + FROM + aws_secretsmanager_secret; Severity: high Tags: category: @@ -30,5 +47,4 @@ Tags: - AWS/SecretsManager soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Secrets Manager secrets should have automatic rotation enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_secretsmanager_secret_automatic_rotation_lambda_enabled.yaml b/compliance/controls/aws/aws_secretsmanager_secret_automatic_rotation_lambda_enabled.yaml old mode 100755 new mode 100644 index 1b8dbaad6..98def219b --- a/compliance/controls/aws/aws_secretsmanager_secret_automatic_rotation_lambda_enabled.yaml +++ b/compliance/controls/aws/aws_secretsmanager_secret_automatic_rotation_lambda_enabled.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether your secrets have been rotated at least once within 90 days. Rotating secrets can help you to reduce the risk of an unauthorized use of your secrets in your AWS account. Examples include database credentials, passwords, third-party API keys, and even arbitrary text. If you do not change your secrets for a long period of time, the secrets are more likely to be compromised. ID: aws_secretsmanager_secret_automatic_rotation_lambda_enabled -Title: "Secrets Manager secrets should be rotated within a specified number of days" -Description: "This control checks whether your secrets have been rotated at least once within 90 days. Rotating secrets can help you to reduce the risk of an unauthorized use of your secrets in your AWS account. Examples include database credentials, passwords, third-party API keys, and even arbitrary text. If you do not change your secrets for a long period of time, the secrets are more likely to be compromised." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when rotation_rules is not null and rotation_lambda_arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when rotation_rules is not null and rotation_lambda_arn is not null then title || ' scheduled for rotation using Lambda function.'\n else title || ' automatic rotation using Lambda function disabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_secretsmanager_secret;\n\n" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN rotation_rules IS NOT NULL AND rotation_lambda_arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN rotation_rules IS NOT NULL AND rotation_lambda_arn IS NOT NULL THEN title || ' scheduled for rotation using Lambda function.' + ELSE title || ' automatic rotation using Lambda function disabled.' + END AS reason, + region, + account_id + FROM + aws_secretsmanager_secret; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/SecretsManager -IntegrationType: - - aws_cloud_account +Title: Secrets Manager secrets should be rotated within a specified number of days \ No newline at end of file diff --git a/compliance/controls/aws/aws_secretsmanager_secret_encrypted_with_kms_cmk.yaml b/compliance/controls/aws/aws_secretsmanager_secret_encrypted_with_kms_cmk.yaml old mode 100755 new mode 100644 index 091c3e3fb..bc25dc331 --- a/compliance/controls/aws/aws_secretsmanager_secret_encrypted_with_kms_cmk.yaml +++ b/compliance/controls/aws/aws_secretsmanager_secret_encrypted_with_kms_cmk.yaml @@ -1,14 +1,51 @@ +Description: Ensure that all secrets in AWS Secrets Manager are encrypted using the AWS managed key (aws/secretsmanager) or a customer managed key that was created in AWS Key Management Service (AWS KMS). The rule is compliant if a secret is encrypted using a customer managed key. This rule is non-compliant if a secret is encrypted using aws/secretsmanager. ID: aws_secretsmanager_secret_encrypted_with_kms_cmk -Title: "Secrets Manager secrets should be encrypted using CMK" -Description: "Ensure that all secrets in AWS Secrets Manager are encrypted using the AWS managed key (aws/secretsmanager) or a customer managed key that was created in AWS Key Management Service (AWS KMS). The rule is compliant if a secret is encrypted using a customer managed key. This rule is non-compliant if a secret is encrypted using aws/secretsmanager." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with encryption_keys as (\n select\n distinct s.arn,\n k.aliases as alias\n from\n aws_secretsmanager_secret as s\n left join aws_kms_key as k on k.arn = s.kms_key_id\n where\n jsonb_array_length(k.aliases) > 0\n)\nselect\n s.arn as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when kms_key_id is null\n or kms_key_id = 'alias/aws/secretsmanager'\n or k.alias @> '[{\"AliasName\":\"alias/aws/secretsmanager\"}]'then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_key_id is null then title || ' not encrypted with KMS.'\n when kms_key_id = 'alias/aws/secretsmanager' or k.alias @> '[{\"AliasName\":\"alias/aws/secretsmanager\"}]' then title || ' encrypted with AWS managed key.'\n else title || ' encrypted with CMK.'\n end as reason\n \n , region, account_id\nfrom\n aws_secretsmanager_secret as s\n left join encryption_keys as k on s.arn = k.arn;" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_kms_key - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + WITH encryption_keys AS ( + SELECT + DISTINCT s.arn, + k.aliases AS alias + FROM + aws_secretsmanager_secret AS s + LEFT JOIN aws_kms_key AS k + ON k.arn = s.kms_key_id + WHERE + jsonb_array_length(k.aliases) > 0 + ) + SELECT + s.arn AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN kms_key_id IS NULL + OR kms_key_id = 'alias/aws/secretsmanager' + OR k.alias @> '[{"AliasName":"alias/aws/secretsmanager"}]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_key_id IS NULL + THEN title || ' not encrypted with KMS.' + WHEN kms_key_id = 'alias/aws/secretsmanager' + OR k.alias @> '[{"AliasName":"alias/aws/secretsmanager"}]' + THEN title || ' encrypted with AWS managed key.' + ELSE title || ' encrypted with CMK.' + END AS reason, + region, + account_id + FROM + aws_secretsmanager_secret AS s + LEFT JOIN encryption_keys AS k + ON s.arn = k.arn; Severity: high Tags: category: @@ -29,5 +66,4 @@ Tags: - aws service: - AWS/SecretsManager -IntegrationType: - - aws_cloud_account +Title: Secrets Manager secrets should be encrypted using CMK \ No newline at end of file diff --git a/compliance/controls/aws/aws_secretsmanager_secret_last_changed_90_day.yaml b/compliance/controls/aws/aws_secretsmanager_secret_last_changed_90_day.yaml old mode 100755 new mode 100644 index 16a0c17c4..fe8531304 --- a/compliance/controls/aws/aws_secretsmanager_secret_last_changed_90_day.yaml +++ b/compliance/controls/aws/aws_secretsmanager_secret_last_changed_90_day.yaml @@ -1,13 +1,32 @@ +Description: Ensure that AWS Secrets Manager secrets have been rotated in the past specified number of days. The rule is non-compliant if a secret has not been rotated for more than 'maxDaysSinceRotation' number of days. The default value is 90 days. ID: aws_secretsmanager_secret_last_changed_90_day -Title: "Secrets Manager secrets should be rotated within specific number of days" -Description: "Ensure that AWS Secrets Manager secrets have been rotated in the past specified number of days. The rule is non-compliant if a secret has not been rotated for more than 'maxDaysSinceRotation' number of days. The default value is 90 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when last_changed_date is null then 'alarm'\n when date(current_date) - date(last_changed_date) <= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when last_changed_date is null then title || ' never rotated.'\n else\n title || ' last rotated ' || extract(day from current_timestamp - last_changed_date) || ' day(s) ago.'\n end as reason\n \n , region, account_id\nfrom\n aws_secretsmanager_secret;\n" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN last_changed_date IS NULL THEN 'alarm' + WHEN DATE(current_date) - DATE(last_changed_date) <= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN last_changed_date IS NULL THEN title || ' never rotated.' + ELSE + title || ' last rotated ' || EXTRACT(DAY FROM current_timestamp - last_changed_date) || ' day(s) ago.' + END AS reason, + region, + account_id + FROM + aws_secretsmanager_secret; Severity: high Tags: category: @@ -24,5 +43,4 @@ Tags: - aws service: - AWS/SecretsManager -IntegrationType: - - aws_cloud_account +Title: Secrets Manager secrets should be rotated within specific number of days \ No newline at end of file diff --git a/compliance/controls/aws/aws_secretsmanager_secret_last_used_1_day.yaml b/compliance/controls/aws/aws_secretsmanager_secret_last_used_1_day.yaml old mode 100755 new mode 100644 index c38ff2f4b..15ad41631 --- a/compliance/controls/aws/aws_secretsmanager_secret_last_used_1_day.yaml +++ b/compliance/controls/aws/aws_secretsmanager_secret_last_used_1_day.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether your secrets have been accessed within a specified number of days. The default value is 90 days. If a secret was accessed even once within the defined number of days, this control fails. ID: aws_secretsmanager_secret_last_used_1_day -Title: "Remove unused Secrets Manager secrets" -Description: "This control checks whether your secrets have been accessed within a specified number of days. The default value is 90 days. If a secret was accessed even once within the defined number of days, this control fails." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when date(last_accessed_date) - date(created_date) >= 1 then 'ok'\n else 'alarm'\n end as status,\n case\n when date(last_accessed_date)- date(created_date) >= 1 then title || ' recently used.'\n else title || ' not used recently.'\n end as reason\n \n , region, account_id\nfrom\n aws_secretsmanager_secret;\n" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN DATE(last_accessed_date) - DATE(created_date) >= 1 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN DATE(last_accessed_date) - DATE(created_date) >= 1 THEN title || ' recently used.' + ELSE title || ' not used recently.' + END AS reason, + region, + account_id + FROM + aws_secretsmanager_secret; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/SecretsManager -IntegrationType: - - aws_cloud_account +Title: Remove unused Secrets Manager secrets \ No newline at end of file diff --git a/compliance/controls/aws/aws_secretsmanager_secret_rotated_as_scheduled.yaml b/compliance/controls/aws/aws_secretsmanager_secret_rotated_as_scheduled.yaml old mode 100755 new mode 100644 index 81fae1f94..1a5caf05a --- a/compliance/controls/aws/aws_secretsmanager_secret_rotated_as_scheduled.yaml +++ b/compliance/controls/aws/aws_secretsmanager_secret_rotated_as_scheduled.yaml @@ -1,13 +1,42 @@ +Description: This rule ensures that AWS Secrets Manager secrets have rotated successfully according to the rotation schedule. Rotating secrets on a regular schedule can shorten the period that a secret is active, and potentially reduce the business impact if it is compromised. ID: aws_secretsmanager_secret_rotated_as_scheduled -Title: "Secrets Manager secrets should be rotated as per the rotation schedule" -Description: "This rule ensures that AWS Secrets Manager secrets have rotated successfully according to the rotation schedule. Rotating secrets on a regular schedule can shorten the period that a secret is active, and potentially reduce the business impact if it is compromised." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when primary_region is not null and region != primary_region then 'skip' -- Replica secret\n when rotation_rules is null then 'alarm' -- Rotation not enabled\n when last_rotated_date is null\n and (date(current_date) - date(created_date)) <= (rotation_rules -> 'AutomaticallyAfterDays')::integer then 'ok' -- New secret not due for rotation yet\n when last_rotated_date is null\n and (date(current_date) - date(created_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer then 'alarm' -- New secret overdue for rotation\n when last_rotated_date is not null\n and (date(current_date) - date(last_rotated_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer then 'alarm' -- Secret has been rotated before but is overdue for another rotation\n end as status,\n case\n when primary_region is not null and region != primary_region then title || ' is a replica.'\n when rotation_rules is null then title || ' rotation not enabled.'\n when last_rotated_date is null\n and (date(current_date) - date(created_date)) <= (rotation_rules -> 'AutomaticallyAfterDays')::integer then title || ' scheduled for rotation.'\n when last_rotated_date is null\n and (date(current_date) - date(created_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer then title || ' not rotated as per schedule.'\n when last_rotated_date is not null\n and (date(current_date) - date(last_rotated_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer then title || ' not rotated as per schedule.'\n end as reason\n \n , region, account_id\nfrom\n aws_secretsmanager_secret;\n" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN primary_region IS NOT NULL AND region != primary_region THEN 'skip' + WHEN rotation_rules IS NULL THEN 'alarm' + WHEN last_rotated_date IS NULL + AND (DATE(current_date) - DATE(created_date)) <= (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN 'ok' + WHEN last_rotated_date IS NULL + AND (DATE(current_date) - DATE(created_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN 'alarm' + WHEN last_rotated_date IS NOT NULL + AND (DATE(current_date) - DATE(last_rotated_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN 'alarm' + END AS status, + CASE + WHEN primary_region IS NOT NULL AND region != primary_region THEN title || ' is a replica.' + WHEN rotation_rules IS NULL THEN title || ' rotation not enabled.' + WHEN last_rotated_date IS NULL + AND (DATE(current_date) - DATE(created_date)) <= (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN title || ' scheduled for rotation.' + WHEN last_rotated_date IS NULL + AND (DATE(current_date) - DATE(created_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN title || ' not rotated as per schedule.' + WHEN last_rotated_date IS NOT NULL + AND (DATE(current_date) - DATE(last_rotated_date)) > (rotation_rules -> 'AutomaticallyAfterDays')::integer THEN title || ' not rotated as per schedule.' + END AS reason, + region, + account_id + FROM + aws_secretsmanager_secret; Severity: medium Tags: aws_foundational_security: @@ -22,5 +51,4 @@ Tags: - aws service: - AWS/SecretsManager -IntegrationType: - - aws_cloud_account +Title: Secrets Manager secrets should be rotated as per the rotation schedule \ No newline at end of file diff --git a/compliance/controls/aws/aws_secretsmanager_secret_unused_90_day.yaml b/compliance/controls/aws/aws_secretsmanager_secret_unused_90_day.yaml old mode 100755 new mode 100644 index 59660e552..7dc85dd6c --- a/compliance/controls/aws/aws_secretsmanager_secret_unused_90_day.yaml +++ b/compliance/controls/aws/aws_secretsmanager_secret_unused_90_day.yaml @@ -1,13 +1,31 @@ +Description: Ensure that AWS Secrets Manager secrets have been accessed within a specified number of days. The rule is non-compliant if a secret has not been accessed in 'unusedForDays' number of days. The default value is 90 days. ID: aws_secretsmanager_secret_unused_90_day -Title: "Secrets Manager secrets that have not been used in 90 days should be removed" -Description: "Ensure that AWS Secrets Manager secrets have been accessed within a specified number of days. The rule is non-compliant if a secret has not been accessed in 'unusedForDays' number of days. The default value is 90 days." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when last_accessed_date is null then 'alarm'\n when date(current_date) - date(last_accessed_date) <= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when last_accessed_date is null then title || ' never accessed.'\n else\n title || ' last used ' || extract(day from current_timestamp - last_accessed_date) || ' day(s) ago.'\n end as reason\n \n , region, account_id\nfrom\n aws_secretsmanager_secret;\n" - PrimaryTable: aws_secretsmanager_secret ListOfTables: - aws_secretsmanager_secret Parameters: [] + PrimaryTable: aws_secretsmanager_secret + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN last_accessed_date IS NULL THEN 'alarm' + WHEN DATE(current_date) - DATE(last_accessed_date) <= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN last_accessed_date IS NULL THEN title || ' never accessed.' + ELSE title || ' last used ' || EXTRACT(day FROM current_timestamp - last_accessed_date) || ' day(s) ago.' + END AS reason, + region, + account_id + FROM + aws_secretsmanager_secret; Severity: low Tags: category: @@ -24,5 +42,4 @@ Tags: - aws service: - AWS/SecretsManager -IntegrationType: - - aws_cloud_account +Title: Secrets Manager secrets that have not been used in 90 days should be removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_securityhub_enabled.yaml b/compliance/controls/aws/aws_securityhub_enabled.yaml old mode 100755 new mode 100644 index 018479c02..eff7438e6 --- a/compliance/controls/aws/aws_securityhub_enabled.yaml +++ b/compliance/controls/aws/aws_securityhub_enabled.yaml @@ -1,15 +1,65 @@ +Description: AWS Security Hub helps to monitor unauthorized personnel, connections, devices, and software. AWS Security Hub aggregates, organizes, and prioritizes the security alerts, or findings, from multiple AWS services. ID: aws_securityhub_enabled -Title: "AWS Security Hub should be enabled for an AWS Account" -Description: "AWS Security Hub helps to monitor unauthorized personnel, connections, devices, and software. AWS Security Hub aggregates, organizes, and prioritizes the security alerts, or findings, from multiple AWS services." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with regions as (\n select\n 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource,\n r.og_account_id as og_account_id,\n r.og_resource_id as og_resource_id,\n case\n when r.region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) then 1\n when r.opt_in_status = 'not-opted-in' then 1\n when h.hub_arn is not null then 0\n else 2\n end as status,\n case\n when r.region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) then r.region || ' region not supported.'\n when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.'\n when h.hub_arn is not null then 'Security Hub enabled in ' || r.region || '.'\n else 'Security Hub disabled in ' || r.region || '.'\n end as reason\n , r.region, r.account_id\n from\n aws_region as r\n left join aws_securityhub_hub as h on r.account_id = h.account_id and r.name = h.region\n),\nresults as (\n SELECT \n account_id AS resource,\n og_account_id as og_account_id,\n og_account_id as og_resource_id,\n case\n when max(status) = 2 then 'alarm'\n when max(status) = 1 then 'skip'\n when max(status) = 0 then 'ok'\n end as status,\n case\n when max(status) = 2 then 'SecurityHub is not enabled for this account on regions: [' || string_agg(region, ',') || ']' \n when max(status) = 1 then 'Account is not opted in regions: [' || string_agg(region, ',') || ']'\n when max(status) = 0 then 'SecurityHub is enabled for this account on regions: [' || string_agg(region, ',') || ']'\n end as reason\n FROM regions\n GROUP BY account_id, og_account_id\n)\nSELECT \n r.resource AS resource,\n r.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n r.status as status,\n r.reason as reason\nFROM results as r JOIN aws_account as a ON r.og_account_id = a.og_account_id\n" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_region - aws_securityhub_hub Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH regions AS ( + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + r.og_account_id AS og_account_id, + r.og_resource_id AS og_resource_id, + CASE + WHEN r.region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) THEN 1 + WHEN r.opt_in_status = 'not-opted-in' THEN 1 + WHEN h.hub_arn IS NOT NULL THEN 0 + ELSE 2 + END AS status, + CASE + WHEN r.region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) THEN r.region || ' region not supported.' + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN h.hub_arn IS NOT NULL THEN 'Security Hub enabled in ' || r.region || '.' + ELSE 'Security Hub disabled in ' || r.region || '.' + END AS reason, + r.region, + r.account_id + FROM + aws_region AS r + LEFT JOIN aws_securityhub_hub AS h ON r.account_id = h.account_id AND r.name = h.region + ), + results AS ( + SELECT + account_id AS resource, + og_account_id AS og_account_id, + og_account_id AS og_resource_id, + CASE + WHEN MAX(status) = 2 THEN 'alarm' + WHEN MAX(status) = 1 THEN 'skip' + WHEN MAX(status) = 0 THEN 'ok' + END AS status, + CASE + WHEN MAX(status) = 2 THEN 'SecurityHub is not enabled for this account on regions: [' || STRING_AGG(region, ',') || ']' + WHEN MAX(status) = 1 THEN 'Account is not opted in regions: [' || STRING_AGG(region, ',') || ']' + WHEN MAX(status) = 0 THEN 'SecurityHub is enabled for this account on regions: [' || STRING_AGG(region, ',') || ']' + END AS reason + FROM regions + GROUP BY account_id, og_account_id + ) + SELECT + r.resource AS resource, + r.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + r.status AS status, + r.reason AS reason + FROM results AS r + JOIN aws_account AS a ON r.og_account_id = a.og_account_id Severity: low Tags: category: @@ -32,12 +82,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -48,5 +98,4 @@ Tags: - AWS/SecurityHub soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: AWS Security Hub should be enabled for an AWS Account \ No newline at end of file diff --git a/compliance/controls/aws/aws_sfn_state_machine_logging_enabled.yaml b/compliance/controls/aws/aws_sfn_state_machine_logging_enabled.yaml old mode 100755 new mode 100644 index ad5bd663b..6bae24bc5 --- a/compliance/controls/aws/aws_sfn_state_machine_logging_enabled.yaml +++ b/compliance/controls/aws/aws_sfn_state_machine_logging_enabled.yaml @@ -1,14 +1,28 @@ +Description: This controls checks whether an AWS Step Functions state machine has logging turned on. The control fails if a state machine doesn't have logging turned on. If you provide a custom value for the logLevel parameter, the control passes only if the state machine has the specified logging level turned on. ID: aws_sfn_state_machine_logging_enabled -Title: "Step Functions state machines should have logging turned on" -Description: "This controls checks whether an AWS Step Functions state machine has logging turned on. The control fails if a state machine doesn't have logging turned on. If you provide a custom value for the logLevel parameter, the control passes only if the state machine has the specified logging level turned on." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when logging_configuration ->> 'Level' = 'OFF' then 'alarm'\n else 'ok'\n end as status,\n case\n when logging_configuration ->> 'Level' = 'OFF' then title || ' loggging disabled.'\n else title || ' loggging enabled.'\n end as reason\n \n \nfrom\n aws_sfn_state_machine;" - PrimaryTable: aws_sfn_state_machine ListOfTables: - aws_sfn_state_machine Parameters: [] + PrimaryTable: aws_sfn_state_machine + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logging_configuration ->> 'Level' = 'OFF' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN logging_configuration ->> 'Level' = 'OFF' THEN title || ' logging disabled.' + ELSE title || ' logging enabled.' + END AS reason + FROM + aws_sfn_state_machine; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Step Functions state machines should have logging turned on \ No newline at end of file diff --git a/compliance/controls/aws/aws_sns_topic_encrypted_at_rest.yaml b/compliance/controls/aws/aws_sns_topic_encrypted_at_rest.yaml old mode 100755 new mode 100644 index d1d019492..345390680 --- a/compliance/controls/aws/aws_sns_topic_encrypted_at_rest.yaml +++ b/compliance/controls/aws/aws_sns_topic_encrypted_at_rest.yaml @@ -1,13 +1,30 @@ +Description: To help protect data at rest, ensure that your AWS Simple Notification Service (AWS SNS) topics require encryption using AWS Key Management Service (AWS KMS). ID: aws_sns_topic_encrypted_at_rest -Title: "SNS topics should be encrypted at rest" -Description: "To help protect data at rest, ensure that your AWS Simple Notification Service (AWS SNS) topics require encryption using AWS Key Management Service (AWS KMS)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n topic_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kms_master_key_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_master_key_id is null then title || ' encryption at rest disabled.'\n else title || ' encryption at rest enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_sns_topic;\n" - PrimaryTable: aws_sns_topic ListOfTables: - aws_sns_topic Parameters: [] + PrimaryTable: aws_sns_topic + QueryToExecute: | + SELECT + topic_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_master_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_master_key_id IS NULL THEN title || ' encryption at rest disabled.' + ELSE title || ' encryption at rest enabled.' + END AS reason, + region, + account_id + FROM + aws_sns_topic; Severity: high Tags: category: @@ -28,12 +45,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" pci_dss_v321: - "true" plugin: @@ -44,5 +61,4 @@ Tags: - AWS/SNS soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: SNS topics should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_sns_topic_notification_delivery_status_enabled.yaml b/compliance/controls/aws/aws_sns_topic_notification_delivery_status_enabled.yaml old mode 100755 new mode 100644 index 42d625dac..fc4bb8611 --- a/compliance/controls/aws/aws_sns_topic_notification_delivery_status_enabled.yaml +++ b/compliance/controls/aws/aws_sns_topic_notification_delivery_status_enabled.yaml @@ -1,13 +1,39 @@ +Description: This control checks whether logging is enabled for the delivery status of notification messages sent to an AWS SNS topic for the endpoints. This control fails if the delivery status notification for messages is not enabled. ID: aws_sns_topic_notification_delivery_status_enabled -Title: "Logging of delivery status should be enabled for notification messages sent to a topic" -Description: "This control checks whether logging is enabled for the delivery status of notification messages sent to an AWS SNS topic for the endpoints. This control fails if the delivery status notification for messages is not enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n topic_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when application_failure_feedback_role_arn is null\n and firehose_failure_feedback_role_arn is null\n and http_failure_feedback_role_arn is null\n and lambda_failure_feedback_role_arn is null\n and sqs_failure_feedback_role_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when application_failure_feedback_role_arn is null\n and firehose_failure_feedback_role_arn is null\n and http_failure_feedback_role_arn is null\n and lambda_failure_feedback_role_arn is null\n and sqs_failure_feedback_role_arn is null then title || ' has delivery status logging for notification messages disabled.'\n else title || ' has delivery status logging for notification messages enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_sns_topic;\n" - PrimaryTable: aws_sns_topic ListOfTables: - aws_sns_topic Parameters: [] + PrimaryTable: aws_sns_topic + QueryToExecute: | + SELECT + topic_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN application_failure_feedback_role_arn IS NULL + AND firehose_failure_feedback_role_arn IS NULL + AND http_failure_feedback_role_arn IS NULL + AND lambda_failure_feedback_role_arn IS NULL + AND sqs_failure_feedback_role_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN application_failure_feedback_role_arn IS NULL + AND firehose_failure_feedback_role_arn IS NULL + AND http_failure_feedback_role_arn IS NULL + AND lambda_failure_feedback_role_arn IS NULL + AND sqs_failure_feedback_role_arn IS NULL THEN title + || ' has delivery status logging for notification messages disabled.' + ELSE title || ' has delivery status logging for notification messages enabled.' + END AS reason, + region, + account_id + FROM + aws_sns_topic; Severity: medium Tags: aws_foundational_security: @@ -22,5 +48,4 @@ Tags: - aws service: - AWS/SNS -IntegrationType: - - aws_cloud_account +Title: Logging of delivery status should be enabled for notification messages sent to a topic \ No newline at end of file diff --git a/compliance/controls/aws/aws_sns_topic_policy_prohibit_cross_account_access.yaml b/compliance/controls/aws/aws_sns_topic_policy_prohibit_cross_account_access.yaml old mode 100755 new mode 100644 index 516f69578..825123997 --- a/compliance/controls/aws/aws_sns_topic_policy_prohibit_cross_account_access.yaml +++ b/compliance/controls/aws/aws_sns_topic_policy_prohibit_cross_account_access.yaml @@ -1,47 +1,48 @@ +Description: Manage access to resources in the AWS Cloud by ensuring SNS topics does not have cross account access. ID: aws_sns_topic_policy_prohibit_cross_account_access -Title: "SNS topic policies should prohibit cross account access" -Description: "Manage access to resources in the AWS Cloud by ensuring SNS topics does not have cross account access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with cross_account_policies as ( - select + ListOfTables: + - aws_sns_topic + Parameters: [] + PrimaryTable: aws_sns_topic + QueryToExecute: | + WITH cross_account_policies AS ( + SELECT topic_arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_sns_topic, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Principal' -> 'AWS') as p - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'AWS') AS p + WHERE s ->> 'Effect' = 'Allow' - and ( - ( s -> 'Principal' -> 'AWS') = '["*"]' - or s ->> 'Principal' = '*' - or split_part(p, ':', 5) <> account_id + AND ( + (s -> 'Principal' -> 'AWS') = '["*"]' + OR s ->> 'Principal' = '*' + OR split_part(p, ':', 5) <> account_id ) - group by + GROUP BY topic_arn ) - select - t.topic_arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when p.topic_arn is null then 'ok' - else 'alarm' - end as status, - case - when p.topic_arn is null then title || ' does not allow cross account access.' - else title || ' contains ' || coalesce(p.statements_num,0) || ' statements that allows cross account access.' - end as reason - from - aws_sns_topic as t - left join cross_account_policies as p on p.topic_arn = t.topic_arn; - PrimaryTable: aws_sns_topic - ListOfTables: - - aws_sns_topic - Parameters: [] + SELECT + t.topic_arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN p.topic_arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.topic_arn IS NULL THEN title || ' does not allow cross account access.' + ELSE title || ' contains ' || COALESCE(p.statements_num,0) || ' statements that allows cross account access.' + END AS reason + FROM + aws_sns_topic AS t + LEFT JOIN cross_account_policies AS p + ON p.topic_arn = t.topic_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SNS topic policies should prohibit cross account access \ No newline at end of file diff --git a/compliance/controls/aws/aws_sns_topic_policy_prohibit_public_access.yaml b/compliance/controls/aws/aws_sns_topic_policy_prohibit_public_access.yaml old mode 100755 new mode 100644 index fab86dc3d..b50552062 --- a/compliance/controls/aws/aws_sns_topic_policy_prohibit_public_access.yaml +++ b/compliance/controls/aws/aws_sns_topic_policy_prohibit_public_access.yaml @@ -1,46 +1,46 @@ +Description: Manage access to resources in the AWS Cloud by ensuring AWS SNS topics cannot be publicly accessed. ID: aws_sns_topic_policy_prohibit_public_access -Title: "SNS topic policies should prohibit public access" -Description: "Manage access to resources in the AWS Cloud by ensuring AWS SNS topics cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with wildcard_action_policies as ( - select + ListOfTables: + - aws_sns_topic + Parameters: [] + PrimaryTable: aws_sns_topic + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT topic_arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_sns_topic, - jsonb_array_elements(policy_std -> 'Statement') as s - where + jsonb_array_elements(policy_std -> 'Statement') AS s + WHERE s ->> 'Effect' = 'Allow' - and ( - ( s -> 'Principal' -> 'AWS') = '["*"]' - or s ->> 'Principal' = '*' + AND ( + (s -> 'Principal' -> 'AWS') = '["*"]' + OR s ->> 'Principal' = '*' ) - group by + GROUP BY topic_arn ) - select - t.topic_arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when p.topic_arn is null then 'ok' - else 'alarm' - end as status, - case - when p.topic_arn is null then title || ' does not allow public access.' - else title || ' contains ' || coalesce(p.statements_num,0) || - ' statements that allows public access.' - end as reason - from - aws_sns_topic as t - left join wildcard_action_policies as p on p.topic_arn = t.topic_arn; - PrimaryTable: aws_sns_topic - ListOfTables: - - aws_sns_topic - Parameters: [] + SELECT + t.topic_arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN p.topic_arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.topic_arn IS NULL THEN title || ' does not allow public access.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || ' statements that allows public access.' + END AS reason + FROM + aws_sns_topic AS t + LEFT JOIN wildcard_action_policies AS p + ON p.topic_arn = t.topic_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SNS topic policies should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_sns_topic_policy_prohibit_publishing_access.yaml b/compliance/controls/aws/aws_sns_topic_policy_prohibit_publishing_access.yaml old mode 100755 new mode 100644 index 928479283..9798df1d2 --- a/compliance/controls/aws/aws_sns_topic_policy_prohibit_publishing_access.yaml +++ b/compliance/controls/aws/aws_sns_topic_policy_prohibit_publishing_access.yaml @@ -1,48 +1,48 @@ +Description: Manage access to resources in the AWS Cloud by ensuring SNS topics cannot be accessed publicly for publishing. ID: aws_sns_topic_policy_prohibit_publishing_access -Title: "SNS topic policies should prohibit publishing access" -Description: "Manage access to resources in the AWS Cloud by ensuring SNS topics cannot be accessed publicly for publishing." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with wildcard_action_policies as ( - select + ListOfTables: + - aws_sns_topic + Parameters: [] + PrimaryTable: aws_sns_topic + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT topic_arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_sns_topic, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Action') as a - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS a + WHERE s ->> 'Effect' = 'Allow' - and ( - ( s -> 'Principal' -> 'AWS') = '["*"]' - or s ->> 'Principal' = '*' + AND ( + (s -> 'Principal' -> 'AWS') = '["*"]' + OR s ->> 'Principal' = '*' ) - and a = 'sns:publish' - and s -> 'Condition' is null - group by + AND a = 'sns:publish' + AND s -> 'Condition' IS NULL + GROUP BY topic_arn ) - select - t.topic_arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when p.topic_arn is null then 'ok' - else 'alarm' - end as status, - case - when p.topic_arn is null then title || ' does not allow publish access without condition.' - else title || ' contains ' || coalesce(p.statements_num,0) || ' statements that allows publish access without condition.' - end as reason - from - aws_sns_topic as t - left join wildcard_action_policies as p on p.topic_arn = t.topic_arn; - PrimaryTable: aws_sns_topic - ListOfTables: - - aws_sns_topic - Parameters: [] + SELECT + t.topic_arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN p.topic_arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.topic_arn IS NULL THEN title || ' does not allow publish access without condition.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || ' statements that allows publish access without condition.' + END AS reason + FROM + aws_sns_topic AS t + LEFT JOIN wildcard_action_policies AS p ON p.topic_arn = t.topic_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SNS topic policies should prohibit publishing access \ No newline at end of file diff --git a/compliance/controls/aws/aws_sns_topic_policy_prohibit_subscription_access.yaml b/compliance/controls/aws/aws_sns_topic_policy_prohibit_subscription_access.yaml old mode 100755 new mode 100644 index d6c1e65fa..9c1146ca7 --- a/compliance/controls/aws/aws_sns_topic_policy_prohibit_subscription_access.yaml +++ b/compliance/controls/aws/aws_sns_topic_policy_prohibit_subscription_access.yaml @@ -1,48 +1,48 @@ +Description: Manage access to resources in the AWS Cloud by ensuring SNS topics cannot be accessed publicly for subscription. ID: aws_sns_topic_policy_prohibit_subscription_access -Title: "SNS topic policies should prohibit subscription public access" -Description: "Manage access to resources in the AWS Cloud by ensuring SNS topics cannot be accessed publicly for subscription." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with wildcard_action_policies as ( - select + ListOfTables: + - aws_sns_topic + Parameters: [] + PrimaryTable: aws_sns_topic + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT topic_arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_sns_topic, - jsonb_array_elements(policy_std -> 'Statement') as s, - jsonb_array_elements_text(s -> 'Action') as a - where + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS a + WHERE s ->> 'Effect' = 'Allow' - and ( - ( s -> 'Principal' -> 'AWS') = '["*"]' - or s ->> 'Principal' = '*' + AND ( + (s -> 'Principal' -> 'AWS') = '["*"]' + OR s ->> 'Principal' = '*' ) - and a in ('sns:subscribe', 'sns:receive') - and s -> 'Condition' is null - group by + AND a IN ('sns:subscribe', 'sns:receive') + AND s -> 'Condition' IS NULL + GROUP BY topic_arn ) - select - t.topic_arn as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when p.topic_arn is null then 'ok' - else 'alarm' - end as status, - case - when p.topic_arn is null then title || ' does not allow subscribe access without condition.' - else title || ' contains ' || coalesce(p.statements_num,0) || ' statements that allows subscribe access without condition.' - end as reason - from - aws_sns_topic as t - left join wildcard_action_policies as p on p.topic_arn = t.topic_arn; - PrimaryTable: aws_sns_topic - ListOfTables: - - aws_sns_topic - Parameters: [] + SELECT + t.topic_arn AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN p.topic_arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.topic_arn IS NULL THEN title || ' does not allow subscribe access without condition.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || ' statements that allows subscribe access without condition.' + END AS reason + FROM + aws_sns_topic AS t + LEFT JOIN wildcard_action_policies AS p ON p.topic_arn = t.topic_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SNS topic policies should prohibit subscription public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_sqs_queue_dead_letter_queue_configured.yaml b/compliance/controls/aws/aws_sqs_queue_dead_letter_queue_configured.yaml old mode 100755 new mode 100644 index cb44b0a3b..057f46e11 --- a/compliance/controls/aws/aws_sqs_queue_dead_letter_queue_configured.yaml +++ b/compliance/controls/aws/aws_sqs_queue_dead_letter_queue_configured.yaml @@ -1,14 +1,28 @@ +Description: Ensure SQS queue is configured with a dead-letter queue. Dead-letter queues are useful for debugging your application or messaging system because they let you isolate problematic messages to determine why their processing didn't succeed. ID: aws_sqs_queue_dead_letter_queue_configured -Title: "SQS queues should be configured with a dead-letter queue." -Description: "Ensure SQS queue is configured with a dead-letter queue. Dead-letter queues are useful for debugging your application or messaging system because they let you isolate problematic messages to determine why their processing didn't succeed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n queue_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when redrive_policy is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when redrive_policy is not null then title || ' configured with dead-letter queue.'\n else title || ' not configured with dead-letter queue.'\n end as reason\n \n \nfrom\n aws_sqs_queue;" - PrimaryTable: aws_sqs_queue ListOfTables: - aws_sqs_queue Parameters: [] + PrimaryTable: aws_sqs_queue + QueryToExecute: | + SELECT + queue_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN redrive_policy IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN redrive_policy IS NOT NULL THEN title || ' configured with dead-letter queue.' + ELSE title || ' not configured with dead-letter queue.' + END AS reason + FROM + aws_sqs_queue; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SQS queues should be configured with a dead-letter queue. \ No newline at end of file diff --git a/compliance/controls/aws/aws_sqs_queue_encrypted_at_rest.yaml b/compliance/controls/aws/aws_sqs_queue_encrypted_at_rest.yaml old mode 100755 new mode 100644 index 8994269bd..d57249b1b --- a/compliance/controls/aws/aws_sqs_queue_encrypted_at_rest.yaml +++ b/compliance/controls/aws/aws_sqs_queue_encrypted_at_rest.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether AWS SQS queues are encrypted at rest. ID: aws_sqs_queue_encrypted_at_rest -Title: "AWS SQS queues should be encrypted at rest" -Description: "This control checks whether AWS SQS queues are encrypted at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n queue_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kms_master_key_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_master_key_id is null then title || ' encryption at rest disabled.'\n else title || ' encryption at rest enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_sqs_queue;\n" - PrimaryTable: aws_sqs_queue ListOfTables: - aws_sqs_queue Parameters: [] + PrimaryTable: aws_sqs_queue + QueryToExecute: | + SELECT + queue_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_master_key_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_master_key_id IS NULL THEN title || ' encryption at rest disabled.' + ELSE title || ' encryption at rest enabled.' + END AS reason, + region, + account_id + FROM + aws_sqs_queue; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/SQS -IntegrationType: - - aws_cloud_account +Title: AWS SQS queues should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/aws/aws_sqs_queue_encrypted_with_kms_cmk.yaml b/compliance/controls/aws/aws_sqs_queue_encrypted_with_kms_cmk.yaml old mode 100755 new mode 100644 index 8615103e9..a95c46c1d --- a/compliance/controls/aws/aws_sqs_queue_encrypted_with_kms_cmk.yaml +++ b/compliance/controls/aws/aws_sqs_queue_encrypted_with_kms_cmk.yaml @@ -1,14 +1,30 @@ +Description: To help protect sensitive data at rest, ensure encryption is enabled for your AWS SQS queues with KMS CMK. ID: aws_sqs_queue_encrypted_with_kms_cmk -Title: "SQS queues should be encrypted with KMS CMK" -Description: "To help protect sensitive data at rest, ensure encryption is enabled for your AWS SQS queues with KMS CMK." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n queue_arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when kms_master_key_id is null then 'alarm'\n when kms_master_key_id is not null and kms_master_key_id = 'alias/aws/sqs' then 'alarm'\n else 'ok'\n end as status,\n case\n when kms_master_key_id is null then title || ' encryption at rest disabled.'\n when kms_master_key_id is not null and kms_master_key_id = 'alias/aws/sqs' then title || ' not encrypted with CMK.'\n else title || ' encrypted with CMK.'\n end as reason\n \n \nfrom\n aws_sqs_queue;" - PrimaryTable: aws_sqs_queue ListOfTables: - aws_sqs_queue Parameters: [] + PrimaryTable: aws_sqs_queue + QueryToExecute: | + SELECT + queue_arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN kms_master_key_id IS NULL THEN 'alarm' + WHEN kms_master_key_id IS NOT NULL AND kms_master_key_id = 'alias/aws/sqs' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms_master_key_id IS NULL THEN title || ' encryption at rest disabled.' + WHEN kms_master_key_id IS NOT NULL AND kms_master_key_id = 'alias/aws/sqs' THEN title || ' not encrypted with CMK.' + ELSE title || ' encrypted with CMK.' + END AS reason + FROM + aws_sqs_queue; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SQS queues should be encrypted with KMS CMK \ No newline at end of file diff --git a/compliance/controls/aws/aws_sqs_queue_policy_prohibit_public_access.yaml b/compliance/controls/aws/aws_sqs_queue_policy_prohibit_public_access.yaml old mode 100755 new mode 100644 index b54c97181..5798ea737 --- a/compliance/controls/aws/aws_sqs_queue_policy_prohibit_public_access.yaml +++ b/compliance/controls/aws/aws_sqs_queue_policy_prohibit_public_access.yaml @@ -1,46 +1,47 @@ +Description: Manage access to resources in the AWS Cloud by ensuring AWS SQS queues cannot be publicly accessed. ID: aws_sqs_queue_policy_prohibit_public_access -Title: "SQS queue policies should prohibit public access" -Description: "Manage access to resources in the AWS Cloud by ensuring AWS SQS queues cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with wildcard_action_policies as ( - select + ListOfTables: + - aws_sqs_queue + Parameters: [] + PrimaryTable: aws_sqs_queue + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT queue_arn, - count(*) as statements_num - from + COUNT(*) AS statements_num + FROM aws_sqs_queue, - jsonb_array_elements(policy_std -> 'Statement') as s - where + JSONB_ARRAY_ELEMENTS(policy_std -> 'Statement') AS s + WHERE s ->> 'Effect' = 'Allow' - and ( - ( s -> 'Principal' -> 'AWS') = '["*"]' - or s ->> 'Principal' = '*' + AND ( + (s -> 'Principal' -> 'AWS') = '["*"]' + OR s ->> 'Principal' = '*' ) - group by + GROUP BY queue_arn ) - select - q.queue_arn as resource, - q.og_account_id as og_account_id, - q.og_resource_id as og_resource_id, - case - when p.queue_arn is null then 'ok' - else 'alarm' - end as status, - case - when p.queue_arn is null then title || ' does not allow public access.' - else title || ' contains ' || coalesce(p.statements_num,0) || - ' statements that allows public access.' - end as reason - from - aws_sqs_queue as q - left join wildcard_action_policies as p on q.queue_arn = p.queue_arn; - PrimaryTable: aws_sqs_queue - ListOfTables: - - aws_sqs_queue - Parameters: [] + SELECT + q.queue_arn AS resource, + q.og_account_id AS og_account_id, + q.og_resource_id AS og_resource_id, + CASE + WHEN p.queue_arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.queue_arn IS NULL THEN title || ' does not allow public access.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || + ' statements that allow public access.' + END AS reason + FROM + aws_sqs_queue AS q + LEFT JOIN wildcard_action_policies AS p + ON q.queue_arn = p.queue_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SQS queue policies should prohibit public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_ssm_document_prohibit_public_access.yaml b/compliance/controls/aws/aws_ssm_document_prohibit_public_access.yaml old mode 100755 new mode 100644 index babfa54bc..04a334094 --- a/compliance/controls/aws/aws_ssm_document_prohibit_public_access.yaml +++ b/compliance/controls/aws/aws_ssm_document_prohibit_public_access.yaml @@ -1,13 +1,32 @@ +Description: This control checks whether AWS Systems Manager documents that are owned by the account are public. This control fails if SSM documents with the owner Self are public. ID: aws_ssm_document_prohibit_public_access -Title: "SSM documents should not be public" -Description: "This control checks whether AWS Systems Manager documents that are owned by the account are public. This control fails if SSM documents with the owner Self are public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':ssm:' || region || ':' || account_id || ':document/' || name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when account_ids :: jsonb ? 'all' then 'alarm'\n else 'ok'\n end as status,\n case\n when account_ids :: jsonb ? 'all' then title || ' publicly accesible.'\n else title || ' not publicly accesible.'\n end as reason\n \n , region, account_id\nfrom\n aws_ssm_document\nwhere\n owner_type = 'Self';\n" - PrimaryTable: aws_ssm_document ListOfTables: - aws_ssm_document Parameters: [] + PrimaryTable: aws_ssm_document + QueryToExecute: | + SELECT + 'arn:' || partition || ':ssm:' || region || ':' || account_id || ':document/' || name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN account_ids :: jsonb ? 'all' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN account_ids :: jsonb ? 'all' THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason, + region, + account_id + FROM + aws_ssm_document + WHERE + owner_type = 'Self'; Severity: critical Tags: aws_foundational_security: @@ -22,5 +41,4 @@ Tags: - aws service: - AWS/SSM -IntegrationType: - - aws_cloud_account +Title: SSM documents should not be public \ No newline at end of file diff --git a/compliance/controls/aws/aws_ssm_managed_instance_compliance_association_compliant.yaml b/compliance/controls/aws/aws_ssm_managed_instance_compliance_association_compliant.yaml old mode 100755 new mode 100644 index 7dc6a1c2a..b192a6914 --- a/compliance/controls/aws/aws_ssm_managed_instance_compliance_association_compliant.yaml +++ b/compliance/controls/aws/aws_ssm_managed_instance_compliance_association_compliant.yaml @@ -1,34 +1,35 @@ +Description: Use AWS Systems Manager Associations to help with inventory of software platforms and applications within an organization. ID: aws_ssm_managed_instance_compliance_association_compliant -Title: "SSM managed instance associations should be compliant" -Description: "Use AWS Systems Manager Associations to help with inventory of software platforms and applications within an organization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when c.status = 'COMPLIANT' then 'ok' - else 'alarm' - end as status, - case - when c.status = 'COMPLIANT' then c.resource_id || ' association ' || c.title || ' is compliant.' - else c.resource_id || ' association ' || c.title || ' is non-compliant.' - end as reason - - , c.region, c.account_id - from - aws_ssm_managed_instance as i, - aws_ssm_managed_instance_compliance as c - where - c.resource_id = i.instance_id - and c.compliance_type = 'Association'; - PrimaryTable: aws_ssm_managed_instance_compliance ListOfTables: - aws_ssm_managed_instance - aws_ssm_managed_instance_compliance Parameters: [] + PrimaryTable: aws_ssm_managed_instance_compliance + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.status = 'COMPLIANT' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.status = 'COMPLIANT' THEN c.resource_id || ' association ' || c.title || ' is compliant.' + ELSE c.resource_id || ' association ' || c.title || ' is non-compliant.' + END AS reason, + c.region, + c.account_id + FROM + aws_ssm_managed_instance AS i, + aws_ssm_managed_instance_compliance AS c + WHERE + c.resource_id = i.instance_id + AND c.compliance_type = 'Association'; Severity: low Tags: category: @@ -49,12 +50,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -67,5 +68,4 @@ Tags: - AWS/SSM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: SSM managed instance associations should be compliant \ No newline at end of file diff --git a/compliance/controls/aws/aws_ssm_managed_instance_compliance_patch_compliant.yaml b/compliance/controls/aws/aws_ssm_managed_instance_compliance_patch_compliant.yaml old mode 100755 new mode 100644 index c48b4a7a2..7f5d116be --- a/compliance/controls/aws/aws_ssm_managed_instance_compliance_patch_compliant.yaml +++ b/compliance/controls/aws/aws_ssm_managed_instance_compliance_patch_compliant.yaml @@ -1,33 +1,35 @@ +Description: Enable this rule to help with identification and documentation of AWS Elastic Compute Cloud (AWS EC2) vulnerabilities. ID: aws_ssm_managed_instance_compliance_patch_compliant -Title: "SSM managed instance patching should be compliant" -Description: "Enable this rule to help with identification and documentation of AWS Elastic Compute Cloud (AWS EC2) vulnerabilities." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when c.status = 'COMPLIANT' then 'ok' - else 'alarm' - end as status, - case - when c.status = 'COMPLIANT' then c.resource_id || ' patch ' || c.title || ' is compliant.' - else c.resource_id || ' patch ' || c.title || ' is non-compliant.' - end as reason - , c.region, c.account_id - from - aws_ssm_managed_instance as i, - aws_ssm_managed_instance_compliance as c - where - c.resource_id = i.instance_id - and c.compliance_type = 'Patch'; - PrimaryTable: aws_ssm_managed_instance_compliance ListOfTables: - aws_ssm_managed_instance - aws_ssm_managed_instance_compliance Parameters: [] + PrimaryTable: aws_ssm_managed_instance_compliance + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.status = 'COMPLIANT' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.status = 'COMPLIANT' THEN c.resource_id || ' patch ' || c.title || ' is compliant.' + ELSE c.resource_id || ' patch ' || c.title || ' is non-compliant.' + END AS reason, + c.region, + c.account_id + FROM + aws_ssm_managed_instance AS i, + aws_ssm_managed_instance_compliance AS c + WHERE + c.resource_id = i.instance_id + AND c.compliance_type = 'Patch'; Severity: medium Tags: category: @@ -48,12 +50,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -66,5 +68,4 @@ Tags: - AWS/SSM soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: SSM managed instance patching should be compliant \ No newline at end of file diff --git a/compliance/controls/aws/aws_ssm_parameter_encryption_enabled.yaml b/compliance/controls/aws/aws_ssm_parameter_encryption_enabled.yaml old mode 100755 new mode 100644 index 097905002..ee282335f --- a/compliance/controls/aws/aws_ssm_parameter_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_ssm_parameter_encryption_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control checks if SSM parameter has encryption enabled. ID: aws_ssm_parameter_encryption_enabled -Title: "SSM parameters encryption should be enabled" -Description: "This control checks if SSM parameter has encryption enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when type = 'SecureString' then 'ok' - else 'alarm' - end as status, - case - when type = 'SecureString' then title || ' encryption enabled.' - else title || ' encryption disabled.' - end as reason - from - aws_ssm_parameter; - PrimaryTable: aws_ssm_parameter ListOfTables: - aws_ssm_parameter Parameters: [] + PrimaryTable: aws_ssm_parameter + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN type = 'SecureString' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN type = 'SecureString' THEN title || ' encryption enabled.' + ELSE title || ' encryption disabled.' + END AS reason + FROM + aws_ssm_parameter; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: SSM parameters encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_sso_users_with_permission_assignments_are_required_to_have_MFA_on_AzureAD.yaml b/compliance/controls/aws/aws_sso_users_with_permission_assignments_are_required_to_have_MFA_on_AzureAD.yaml old mode 100755 new mode 100644 index 5362b9701..37b02a060 --- a/compliance/controls/aws/aws_sso_users_with_permission_assignments_are_required_to_have_MFA_on_AzureAD.yaml +++ b/compliance/controls/aws/aws_sso_users_with_permission_assignments_are_required_to_have_MFA_on_AzureAD.yaml @@ -1,15 +1,41 @@ +Description: AWS SSO Users with Permission Assignments are required to have MFA on AzureAD ID: aws_sso_users_with_permission_assignments_are_required_to_have_MFA_on_AzureAD -Title: "AWS SSO Users with Permission Assignments are required to have MFA on AzureAD" -Description: "AWS SSO Users with Permission Assignments are required to have MFA on AzureAD" +IntegrationType: + - aws_cloud_account + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select \n iden.id as resource,\n iden.og_account_id,\n iden.og_resource_id,\n case\n when is_mfa_registered::bool then 'ok'\n else 'alarm'\n end status,\n case\n when is_mfa_registered::bool then iden.name || ' has MFA registered'\n else iden.name || ' doesnt have MFA'\n end reason\nfrom \n (aws_identitystore_user cross join jsonb_array_elements(external_ids) as external_id) iden\n inner join azuread_user_registration_details az on az.id = value ->> 'Id'\nwhere \n exists(select * from aws_ssoadmin_account_assignment where principal_type = 'USER' and principal_id = iden.id) \n" - PrimaryTable: aws_identitystore_user ListOfTables: - aws_identitystore_user - aws_ssoadmin_account_assignment - azuread_user_registration_details Parameters: [] + PrimaryTable: aws_identitystore_user + QueryToExecute: | + SELECT + iden.id AS resource, + iden.og_account_id, + iden.og_resource_id, + CASE + WHEN is_mfa_registered::BOOL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN is_mfa_registered::BOOL THEN iden.name || ' has MFA registered' + ELSE iden.name || ' doesnt have MFA' + END reason + FROM + (aws_identitystore_user + CROSS JOIN jsonb_array_elements(external_ids) AS external_id) iden + INNER JOIN azuread_user_registration_details az + ON az.id = value ->> 'Id' + WHERE + EXISTS ( + SELECT * + FROM aws_ssoadmin_account_assignment + WHERE principal_type = 'USER' + AND principal_id = iden.id + ) Severity: high Tags: category: @@ -18,6 +44,4 @@ Tags: - aws score_service_name: - AWS Single Sign-On (SSO) -IntegrationType: - - aws_cloud_account - - azure_subscription +Title: AWS SSO Users with Permission Assignments are required to have MFA on AzureAD \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_configured_to_use_vpc_endpoints.yaml b/compliance/controls/aws/aws_vpc_configured_to_use_vpc_endpoints.yaml old mode 100755 new mode 100644 index d6fe6141f..9c56d5305 --- a/compliance/controls/aws/aws_vpc_configured_to_use_vpc_endpoints.yaml +++ b/compliance/controls/aws/aws_vpc_configured_to_use_vpc_endpoints.yaml @@ -1,14 +1,45 @@ +Description: Checks if Service Endpoint for the service provided in rule parameter is created for each AWS Virtual Private Cloud (AWS VPC). The rule is non-compliant if an AWS VPC doesn't have an AWS VPC endpoint created for the service. ID: aws_vpc_configured_to_use_vpc_endpoints -Title: "VPC should be configured to use VPC endpoints" -Description: "Checks if Service Endpoint for the service provided in rule parameter is created for each AWS Virtual Private Cloud (AWS VPC). The rule is non-compliant if an AWS VPC doesn't have an AWS VPC endpoint created for the service." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when vpc_id not in (\n select\n vpc_id\n from\n aws_vpc_endpoint\n where\n service_name like 'com.amazonaws.' || region || '.ec2'\n ) then 'alarm'\n else 'ok'\n end as status,\n case\n when vpc_id not in (\n select\n vpc_id\n from\n aws_vpc_endpoint\n where\n service_name like 'com.amazonaws.' || region || '.ec2'\n ) then title || ' not configured to use VPC endpoints.'\n else title || ' configured to use VPC endpoints.'\n end as reason\n \n , region, account_id\nfrom\n aws_vpc;\n" - PrimaryTable: aws_vpc ListOfTables: - aws_vpc - aws_vpc_endpoint Parameters: [] + PrimaryTable: aws_vpc + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN vpc_id NOT IN ( + SELECT + vpc_id + FROM + aws_vpc_endpoint + WHERE + service_name LIKE 'com.amazonaws.' || region || '.ec2' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vpc_id NOT IN ( + SELECT + vpc_id + FROM + aws_vpc_endpoint + WHERE + service_name LIKE 'com.amazonaws.' || region || '.ec2' + ) THEN title || ' not configured to use VPC endpoints.' + ELSE title || ' configured to use VPC endpoints.' + END AS reason, + region, + account_id + FROM + aws_vpc; Severity: medium Tags: aws_foundational_security: @@ -23,5 +54,4 @@ Tags: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: VPC should be configured to use VPC endpoints \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_default_security_group_restricts_all_traffic.yaml b/compliance/controls/aws/aws_vpc_default_security_group_restricts_all_traffic.yaml old mode 100755 new mode 100644 index a9d7d4d83..aa6f8e9d3 --- a/compliance/controls/aws/aws_vpc_default_security_group_restricts_all_traffic.yaml +++ b/compliance/controls/aws/aws_vpc_default_security_group_restricts_all_traffic.yaml @@ -1,13 +1,38 @@ +Description: AWS Elastic Compute Cloud (AWS EC2) security groups can help in the management of network access by providing stateful filtering of ingress and egress network traffic to AWS resources. ID: aws_vpc_default_security_group_restricts_all_traffic -Title: "VPC default security group should not allow inbound and outbound traffic" -Description: "AWS Elastic Compute Cloud (AWS EC2) security groups can help in the management of network access by providing stateful filtering of ingress and egress network traffic to AWS resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) = 0 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has inbound and outbound rules.'\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) = 0\n then 'Default security group ' || group_id || ' has inbound rules.'\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has outbound rules.'\n else 'Default security group ' || group_id || ' has no inbound or outbound rules.'\n end reason\n \n , region, account_id\nfrom\n aws_vpc_security_group\nwhere\n group_name = 'default';\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(ip_permissions) = 0 + AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN jsonb_array_length(ip_permissions) > 0 + AND jsonb_array_length(ip_permissions_egress) > 0 THEN 'Default security group ' || group_id || ' has inbound and outbound rules.' + WHEN jsonb_array_length(ip_permissions) > 0 + AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'Default security group ' || group_id || ' has inbound rules.' + WHEN jsonb_array_length(ip_permissions) = 0 + AND jsonb_array_length(ip_permissions_egress) > 0 THEN 'Default security group ' || group_id || ' has outbound rules.' + ELSE 'Default security group ' || group_id || ' has no inbound or outbound rules.' + END reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + group_name = 'default'; Severity: low Tags: category: @@ -26,12 +51,12 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -44,5 +69,4 @@ Tags: - AWS/VPC soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: VPC default security group should not allow inbound and outbound traffic \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_eip_associated.yaml b/compliance/controls/aws/aws_vpc_eip_associated.yaml old mode 100755 new mode 100644 index b69718f4c..1bb23c3cf --- a/compliance/controls/aws/aws_vpc_eip_associated.yaml +++ b/compliance/controls/aws/aws_vpc_eip_associated.yaml @@ -1,13 +1,30 @@ +Description: This rule ensures Elastic IPs allocated to a AWS Virtual Private Cloud (AWS VPC) are attached to AWS Elastic Compute Cloud (AWS EC2) instances or in-use Elastic Network Interfaces. ID: aws_vpc_eip_associated -Title: "VPC EIPs should be associated with an EC2 instance or ENI" -Description: "This rule ensures Elastic IPs allocated to a AWS Virtual Private Cloud (AWS VPC) are attached to AWS Elastic Compute Cloud (AWS EC2) instances or in-use Elastic Network Interfaces." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':eip/' || allocation_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when association_id is null then 'alarm'\n else 'ok'\n end status,\n case\n when association_id is null then title || ' is not associated with any resource.'\n else title || ' is associated with a resource.'\n end reason\n \n , region, account_id\nfrom\n aws_vpc_eip;\n" - PrimaryTable: aws_vpc_eip ListOfTables: - aws_vpc_eip Parameters: [] + PrimaryTable: aws_vpc_eip + QueryToExecute: | + SELECT + 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':eip/' || allocation_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN association_id IS NULL THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN association_id IS NULL THEN title || ' is not associated with any resource.' + ELSE title || ' is associated with a resource.' + END reason, + region, + account_id + FROM + aws_vpc_eip; Severity: medium Tags: category: @@ -30,5 +47,4 @@ Tags: - AWS/VPC soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: VPC EIPs should be associated with an EC2 instance or ENI \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_endpoint_service_acceptance_required_enabled.yaml b/compliance/controls/aws/aws_vpc_endpoint_service_acceptance_required_enabled.yaml old mode 100755 new mode 100644 index 7b53f8acd..f5a29a289 --- a/compliance/controls/aws/aws_vpc_endpoint_service_acceptance_required_enabled.yaml +++ b/compliance/controls/aws/aws_vpc_endpoint_service_acceptance_required_enabled.yaml @@ -1,14 +1,28 @@ +Description: Ensure VPC endpoints connection requests to the service are accepted by the service owner. ID: aws_vpc_endpoint_service_acceptance_required_enabled -Title: "VPC endpoint services should have acceptance required enabled" -Description: "Ensure VPC endpoints connection requests to the service are accepted by the service owner." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n service_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when acceptance_required then 'ok'\n else 'alarm'\n end as status,\n case\n when acceptance_required then title || ' acceptance_required enabled.'\n else title || ' acceptance_required disabled.'\n end as reason\n \n \nfrom\n aws_vpc_endpoint_service;" - PrimaryTable: aws_vpc_endpoint_service ListOfTables: - aws_vpc_endpoint_service Parameters: [] + PrimaryTable: aws_vpc_endpoint_service + QueryToExecute: | + SELECT + service_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN acceptance_required THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN acceptance_required THEN title || ' acceptance_required enabled.' + ELSE title || ' acceptance_required disabled.' + END AS reason + FROM + aws_vpc_endpoint_service; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC endpoint services should have acceptance required enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_flow_logs_enabled.yaml b/compliance/controls/aws/aws_vpc_flow_logs_enabled.yaml old mode 100755 new mode 100644 index 088d0a9c3..b779f3622 --- a/compliance/controls/aws/aws_vpc_flow_logs_enabled.yaml +++ b/compliance/controls/aws/aws_vpc_flow_logs_enabled.yaml @@ -1,14 +1,35 @@ +Description: The VPC flow logs provide detailed records for information about the IP traffic going to and from network interfaces in your AWS Virtual Private Cloud (AWS VPC. ID: aws_vpc_flow_logs_enabled -Title: "VPC flow logs should be enabled" -Description: "The VPC flow logs provide detailed records for information about the IP traffic going to and from network interfaces in your AWS Virtual Private Cloud (AWS VPC." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n distinct v.arn as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when v.account_id <> v.owner_id then 'skip'\n when f.resource_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when v.account_id <> v.owner_id then vpc_id || ' is a shared VPC.'\n when f.resource_id is not null then vpc_id || ' flow logging enabled.'\n else vpc_id || ' flow logging disabled.'\n end as reason\n \n , v.region, v.account_id\nfrom\n aws_vpc as v\n left join aws_vpc_flow_log as f on v.vpc_id = f.resource_id;\n" - PrimaryTable: aws_vpc ListOfTables: - aws_vpc - aws_vpc_flow_log Parameters: [] + PrimaryTable: aws_vpc + QueryToExecute: | + SELECT DISTINCT + v.arn AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.account_id <> v.owner_id THEN 'skip' + WHEN f.resource_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.account_id <> v.owner_id THEN vpc_id || ' is a shared VPC.' + WHEN f.resource_id IS NOT NULL THEN vpc_id || ' flow logging enabled.' + ELSE vpc_id || ' flow logging disabled.' + END AS reason, + v.region, + v.account_id + FROM + aws_vpc AS v + LEFT JOIN aws_vpc_flow_log AS f + ON v.vpc_id = f.resource_id; Severity: low Tags: category: @@ -31,12 +52,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -51,5 +72,4 @@ Tags: - AWS/VPC soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: VPC flow logs should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_gateway_endpoint_restrict_public_access.yaml b/compliance/controls/aws/aws_vpc_gateway_endpoint_restrict_public_access.yaml old mode 100755 new mode 100644 index 19181e1bb..1e65ef185 --- a/compliance/controls/aws/aws_vpc_gateway_endpoint_restrict_public_access.yaml +++ b/compliance/controls/aws/aws_vpc_gateway_endpoint_restrict_public_access.yaml @@ -1,14 +1,49 @@ +Description: Manage access to resources in the AWS Cloud by ensuring VPC gateway endpoints cannot be publicly accessed. ID: aws_vpc_gateway_endpoint_restrict_public_access -Title: "VPC gateway endpoints should restrict public access" -Description: "Manage access to resources in the AWS Cloud by ensuring VPC gateway endpoints cannot be publicly accessed." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with wildcard_action_policies as (\n select\n vpc_endpoint_id,\n count(*) as statements_num\n from\n aws_vpc_endpoint,\n jsonb_array_elements(policy_std -> 'Statement') as s\n where\n s ->> 'Effect' = 'Allow'\n and s -> 'Condition' is null\n and (\n (s -> 'Principal' -> 'AWS') = '[\"*\"]'\n or s ->> 'Principal' = '*'\n )\n and s ->> 'Action' = '[\"*\"]'\n group by\n vpc_endpoint_id\n)\nselect\n e.vpc_endpoint_id as resource,\n e.og_account_id as og_account_id,\n e.og_resource_id as og_resource_id,\n case\n when e.vpc_endpoint_type <> 'Gateway' then 'skip'\n when p.vpc_endpoint_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when vpc_endpoint_type <> 'Gateway' then e.title || ' is of ' || e.vpc_endpoint_type || ' endpoint type.'\n when p.vpc_endpoint_id is null then e.title || ' does not allow public access.'\n else title || ' contains ' || coalesce(p.statements_num, 0) ||\n ' statements that allows public access.'\n end as reason\n \nfrom\n aws_vpc_endpoint as e\n left join wildcard_action_policies as p on p.vpc_endpoint_id = e.vpc_endpoint_id;" - PrimaryTable: aws_vpc_endpoint ListOfTables: - aws_vpc_endpoint Parameters: [] + PrimaryTable: aws_vpc_endpoint + QueryToExecute: | + WITH wildcard_action_policies AS ( + SELECT + vpc_endpoint_id, + COUNT(*) AS statements_num + FROM + aws_vpc_endpoint, + jsonb_array_elements(policy_std -> 'Statement') AS s + WHERE + s ->> 'Effect' = 'Allow' + AND s -> 'Condition' IS NULL + AND ( + (s -> 'Principal' -> 'AWS') = '[\"*\"]' + OR s ->> 'Principal' = '*' + ) + AND s ->> 'Action' = '[\"*\"]' + GROUP BY + vpc_endpoint_id + ) + SELECT + e.vpc_endpoint_id AS resource, + e.og_account_id AS og_account_id, + e.og_resource_id AS og_resource_id, + CASE + WHEN e.vpc_endpoint_type <> 'Gateway' THEN 'skip' + WHEN p.vpc_endpoint_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN vpc_endpoint_type <> 'Gateway' THEN e.title || ' is of ' || e.vpc_endpoint_type || ' endpoint type.' + WHEN p.vpc_endpoint_id IS NULL THEN e.title || ' does not allow public access.' + ELSE title || ' contains ' || COALESCE(p.statements_num, 0) || ' statements that allow public access.' + END AS reason + FROM + aws_vpc_endpoint AS e + LEFT JOIN wildcard_action_policies AS p ON p.vpc_endpoint_id = e.vpc_endpoint_id Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC gateway endpoints should restrict public access \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_igw_attached_to_authorized_vpc.yaml b/compliance/controls/aws/aws_vpc_igw_attached_to_authorized_vpc.yaml old mode 100755 new mode 100644 index 961b562e4..3ecb65e36 --- a/compliance/controls/aws/aws_vpc_igw_attached_to_authorized_vpc.yaml +++ b/compliance/controls/aws/aws_vpc_igw_attached_to_authorized_vpc.yaml @@ -1,33 +1,34 @@ +Description: Manage access to resources in the AWS Cloud by ensuring that internet gateways are only attached to authorized AWS Virtual Private Cloud (AWS VPC). ID: aws_vpc_igw_attached_to_authorized_vpc -Title: "VPC internet gateways should be attached to authorized vpc" -Description: "Manage access to resources in the AWS Cloud by ensuring that internet gateways are only attached to authorized AWS Virtual Private Cloud (AWS VPC)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_vpc_internet_gateway + Parameters: [] + PrimaryTable: aws_vpc_internet_gateway QueryToExecute: | - select - 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':internet-gateway/' || title as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when jsonb_array_length(attachments) = 0 then 'alarm' - else 'ok' - end as status, - case - when jsonb_array_length(attachments) = 0 then title || ' not attached to VPC.' - else title || ' attached to ' || split_part( - substring(attachments :: text, 3, length(attachments :: text) -6), + SELECT + 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':internet-gateway/' || title AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(attachments) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN jsonb_array_length(attachments) = 0 THEN title || ' not attached to VPC.' + ELSE title || ' attached to ' || split_part( + SUBSTRING(attachments::text, 3, LENGTH(attachments::text) - 6), '"VpcId": "', 2 ) || '.' - end as reason - - , region, account_id - from + END AS reason, + region, + account_id + FROM aws_vpc_internet_gateway; - PrimaryTable: aws_vpc_internet_gateway - ListOfTables: - - aws_vpc_internet_gateway - Parameters: [] Severity: high Tags: category: @@ -38,10 +39,10 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -54,5 +55,4 @@ Tags: - AWS/VPC soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: VPC internet gateways should be attached to authorized vpc \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_in_more_than_one_region.yaml b/compliance/controls/aws/aws_vpc_in_more_than_one_region.yaml old mode 100755 new mode 100644 index d47f60a64..63b0092fb --- a/compliance/controls/aws/aws_vpc_in_more_than_one_region.yaml +++ b/compliance/controls/aws/aws_vpc_in_more_than_one_region.yaml @@ -1,15 +1,49 @@ +Description: This control checks whether there are VPCs present in multiple regions. ID: aws_vpc_in_more_than_one_region -Title: "VPCs should exist in multiple regions" -Description: "This control checks whether there are VPCs present in multiple regions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vpc_region_list as (\n select\n distinct region, account_id\n from\n aws_vpc\n), vpc_count_in_account as (\n select\n count(*) as num,\n account_id\n from\n vpc_region_list\n group by account_id\n)\nselect\n arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when v.num > 1 then 'ok'\n when v.num = 1 then 'alarm'\n else 'alarm'\n end as status,\n case\n when v.num > 1 then 'VPCs exist in ' || v.num || ' regions.'\n when v.num = 1 then 'VPCs exist only in one region.'\n else 'VPC does not exist.'\n end as reason\n \nfrom\n aws_account as a\n left join vpc_count_in_account as v on v.account_id = a.account_id;" - PrimaryTable: aws_vpc ListOfTables: - aws_vpc - aws_account Parameters: [] + PrimaryTable: aws_vpc + QueryToExecute: | + WITH vpc_region_list AS ( + SELECT + DISTINCT region, + account_id + FROM + aws_vpc + ), + vpc_count_in_account AS ( + SELECT + COUNT(*) AS num, + account_id + FROM + vpc_region_list + GROUP BY + account_id + ) + SELECT + arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN v.num > 1 THEN 'ok' + WHEN v.num = 1 THEN 'alarm' + ELSE 'alarm' + END AS status, + CASE + WHEN v.num > 1 THEN 'VPCs exist in ' || v.num || ' regions.' + WHEN v.num = 1 THEN 'VPCs exist only in one region.' + ELSE 'VPC does not exist.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + vpc_count_in_account AS v ON v.account_id = a.account_id Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPCs should exist in multiple regions \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_network_acl_remote_administration.yaml b/compliance/controls/aws/aws_vpc_network_acl_remote_administration.yaml old mode 100755 new mode 100644 index be4e9ea25..a5d2724d1 --- a/compliance/controls/aws/aws_vpc_network_acl_remote_administration.yaml +++ b/compliance/controls/aws/aws_vpc_network_acl_remote_administration.yaml @@ -1,62 +1,64 @@ +Description: This control checks if default ports for SSH/RDP ingress traffic for network access control lists (NACLs) is unrestricted. The rule fails if a NACL inbound entry allows a source CIDR block of '0.0.0.0/0' or '::/0' for ports 22 or 3389. ID: aws_vpc_network_acl_remote_administration -Title: "Network ACLs should not allow ingress from 0.0.0.0/0 to port 22 or port 3389" -Description: "This control checks if default ports for SSH/RDP ingress traffic for network access control lists (NACLs) is unrestricted. The rule fails if a NACL inbound entry allows a source CIDR block of '0.0.0.0/0' or '::/0' for ports 22 or 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_vpc_network_acl + Parameters: [] + PrimaryTable: aws_vpc_network_acl QueryToExecute: | - with bad_rules as ( - select + WITH bad_rules AS ( + SELECT network_acl_id, - count(*) as num_bad_rules - from + COUNT(*) AS num_bad_rules + FROM aws_vpc_network_acl, - jsonb_array_elements(entries) as att - where - att ->> 'Egress' = 'false' -- as per aws egress = false indicates the ingress - and ( + jsonb_array_elements(entries) AS att + WHERE + att ->> 'Egress' = 'false' + AND ( att ->> 'CidrBlock' = '0.0.0.0/0' - or att ->> 'Ipv6CidrBlock' = '::/0' + OR att ->> 'Ipv6CidrBlock' = '::/0' ) - and att ->> 'RuleAction' = 'allow' - and ( + AND att ->> 'RuleAction' = 'allow' + AND ( ( - att ->> 'Protocol' = '-1' -- all traffic - and att ->> 'PortRange' is null + att ->> 'Protocol' = '-1' + AND att ->> 'PortRange' IS NULL + ) + OR ( + (att -> 'PortRange' ->> 'From')::int <= 22 + AND (att -> 'PortRange' ->> 'To')::int >= 22 + AND att ->> 'Protocol' IN('6', '17') ) - or ( - (att -> 'PortRange' ->> 'From') :: int <= 22 - and (att -> 'PortRange' ->> 'To') :: int >= 22 - and att ->> 'Protocol' in('6', '17') -- TCP or UDP + OR ( + (att -> 'PortRange' ->> 'From')::int <= 3389 + AND (att -> 'PortRange' ->> 'To')::int >= 3389 + AND att ->> 'Protocol' IN('6', '17') ) - or ( - (att -> 'PortRange' ->> 'From') :: int <= 3389 - and (att -> 'PortRange' ->> 'To') :: int >= 3389 - and att ->> 'Protocol' in('6', '17') -- TCP or UDP ) - ) - group by + GROUP BY network_acl_id ) - select - 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id as resource, - acl.og_account_id as og_account_id, - acl.og_resource_id as og_resource_id, - case - when bad_rules.network_acl_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.network_acl_id is null then acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - else acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' - end as reason - , acl.region, acl.account_id - from - aws_vpc_network_acl as acl - left join bad_rules on bad_rules.network_acl_id = acl.network_acl_id; - PrimaryTable: aws_vpc_network_acl - ListOfTables: - - aws_vpc_network_acl - Parameters: [] + SELECT + 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id AS resource, + acl.og_account_id AS og_account_id, + acl.og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason, + acl.region, + acl.account_id + FROM + aws_vpc_network_acl AS acl + LEFT JOIN bad_rules ON bad_rules.network_acl_id = acl.network_acl_id; Severity: high Tags: category: @@ -77,5 +79,4 @@ Tags: - aws service: - AWS/VPC -IntegrationType: - - aws_cloud_account +Title: Network ACLs should not allow ingress from 0.0.0.0/0 to port 22 or port 3389 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_network_acl_unused.yaml b/compliance/controls/aws/aws_vpc_network_acl_unused.yaml old mode 100755 new mode 100644 index 09df99b0e..e68f6c7ca --- a/compliance/controls/aws/aws_vpc_network_acl_unused.yaml +++ b/compliance/controls/aws/aws_vpc_network_acl_unused.yaml @@ -1,13 +1,30 @@ +Description: Ensure there are no unused network access control lists (network ACLs). The rule is compliant if each network ACL is associated with a subnet. The rule is non-compliant if a network ACL is not associated with a subnet. ID: aws_vpc_network_acl_unused -Title: "VPC network access control lists (network ACLs) should be associated with a subnet." -Description: "Ensure there are no unused network access control lists (network ACLs). The rule is compliant if each network ACL is associated with a subnet. The rule is non-compliant if a network ACL is not associated with a subnet." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n network_acl_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(associations) >= 1 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(associations) >= 1 then title || ' associated with subnet.'\n else title || ' not associated with subnet.'\n end reason\n \n , region, account_id\nfrom\n aws_vpc_network_acl;\n" - PrimaryTable: aws_vpc_network_acl ListOfTables: - aws_vpc_network_acl Parameters: [] + PrimaryTable: aws_vpc_network_acl + QueryToExecute: | + SELECT + network_acl_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(associations) >= 1 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(associations) >= 1 THEN title || ' associated with subnet.' + ELSE title || ' not associated with subnet.' + END AS reason, + region, + account_id + FROM + aws_vpc_network_acl; Severity: medium Tags: category: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/VPC -IntegrationType: - - aws_cloud_account +Title: VPC network access control lists (network ACLs) should be associated with a subnet. \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_not_in_use.yaml b/compliance/controls/aws/aws_vpc_not_in_use.yaml old mode 100755 new mode 100644 index ceb7ce288..e1001d758 --- a/compliance/controls/aws/aws_vpc_not_in_use.yaml +++ b/compliance/controls/aws/aws_vpc_not_in_use.yaml @@ -1,38 +1,38 @@ +Description: This control checks whether there are any unused VPCs. ID: aws_vpc_not_in_use -Title: "VPCs should be in use" -Description: "This control checks whether there are any unused VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with vpc_without_subnet as ( - select - distinct vpc_id - from - aws_vpc - where - vpc_id not in (select vpc_id from aws_vpc_subnet) - ) - select - arn as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when s.vpc_id is null then 'ok' - else 'alarm' - end as status, - case - when s.vpc_id is null then title || ' in use.' - else title || ' not in use.' - end as reason - from - aws_vpc as v - left join vpc_without_subnet as s on s.vpc_id = v.vpc_id; - PrimaryTable: aws_vpc ListOfTables: - aws_vpc - aws_vpc_subnet Parameters: [] + PrimaryTable: aws_vpc + QueryToExecute: | + WITH vpc_without_subnet AS ( + SELECT + DISTINCT vpc_id + FROM + aws_vpc + WHERE + vpc_id NOT IN (SELECT vpc_id FROM aws_vpc_subnet) + ) + SELECT + arn AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN s.vpc_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.vpc_id IS NULL THEN title || ' in use.' + ELSE title || ' not in use.' + END AS reason + FROM + aws_vpc AS v + LEFT JOIN vpc_without_subnet AS s ON s.vpc_id = v.vpc_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPCs should be in use \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_peering_connection_no_cross_account_access.yaml b/compliance/controls/aws/aws_vpc_peering_connection_no_cross_account_access.yaml old mode 100755 new mode 100644 index 072ef9e27..f7057fb6f --- a/compliance/controls/aws/aws_vpc_peering_connection_no_cross_account_access.yaml +++ b/compliance/controls/aws/aws_vpc_peering_connection_no_cross_account_access.yaml @@ -1,30 +1,30 @@ +Description: Ensure that all VPCs peering connection are not having cross account access. ID: aws_vpc_peering_connection_no_cross_account_access -Title: "VPCs peering connection should not be allowed in cross account" -Description: "Ensure that all VPCs peering connection are not having cross account access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when status_code <> 'active' then 'alarm' - when requester_owner_id <> accepter_owner_id then 'alarm' - else 'ok' - end as status, - case - when status_code <> 'active' then title || ' is not in active state.' - when requester_owner_id <> accepter_owner_id then title || ' have cross account access.' - else title || ' does not have cross account access.' - end as reason - from - aws_vpc_peering_connection; - PrimaryTable: aws_vpc_peering_connection ListOfTables: - aws_vpc_peering_connection Parameters: [] + PrimaryTable: aws_vpc_peering_connection + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN status_code <> 'active' THEN 'alarm' + WHEN requester_owner_id <> accepter_owner_id THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status_code <> 'active' THEN title || ' is not in active state.' + WHEN requester_owner_id <> accepter_owner_id THEN title || ' have cross account access.' + ELSE title || ' does not have cross account access.' + END AS reason + FROM + aws_vpc_peering_connection; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPCs peering connection should not be allowed in cross account \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_peering_connection_route_table_least_privilege.yaml b/compliance/controls/aws/aws_vpc_peering_connection_route_table_least_privilege.yaml old mode 100755 new mode 100644 index 5e0cb7243..8f0cedefb --- a/compliance/controls/aws/aws_vpc_peering_connection_route_table_least_privilege.yaml +++ b/compliance/controls/aws/aws_vpc_peering_connection_route_table_least_privilege.yaml @@ -1,46 +1,47 @@ +Description: Ensure that all VPCs peering connection route tables have least privilege. ID: aws_vpc_peering_connection_route_table_least_privilege -Title: "VPCs peering connection route tables should have least privilege" -Description: "Ensure that all VPCs peering connection route tables have least privilege." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with vpc_peering_routing_tables as ( - select - r ->> 'VpcPeeringConnectionId' as peering_connection_id - from - aws_vpc_route_table, - jsonb_array_elements(routes) as r - inner join aws_vpc_peering_connection as c on r ->> 'VpcPeeringConnectionId' = c.id - where - ( r ->> 'DestinationCidrBlock' = '0.0.0.0/0' - or r ->> 'DestinationCidrBlock' = '::/0' - or (r ->> 'DestinationCidrBlock')::cidr = c.accepter_cidr_block - or (r ->> 'DestinationCidrBlock')::cidr = c.requester_cidr_block - ) - group by - r ->> 'VpcPeeringConnectionId' - ) - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when t.peering_connection_id is not null then 'alarm' - else 'ok' - end as status, - case - when t.peering_connection_id is not null then c.title || ' does not have least privilege access.' - else c.title || ' have least privilege access.' - end as reason - from - aws_vpc_peering_connection as c - left join vpc_peering_routing_tables as t on t.peering_connection_id = c.id; - PrimaryTable: aws_vpc_peering_connection ListOfTables: - aws_vpc_route_table - aws_vpc_peering_connection Parameters: [] + PrimaryTable: aws_vpc_peering_connection + QueryToExecute: | + WITH vpc_peering_routing_tables AS ( + SELECT + r ->> 'VpcPeeringConnectionId' AS peering_connection_id + FROM + aws_vpc_route_table, + JSONB_ARRAY_ELEMENTS(routes) AS r + INNER JOIN aws_vpc_peering_connection AS c + ON r ->> 'VpcPeeringConnectionId' = c.id + WHERE + (r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + OR r ->> 'DestinationCidrBlock' = '::/0' + OR (r ->> 'DestinationCidrBlock')::CIDR = c.accepter_cidr_block + OR (r ->> 'DestinationCidrBlock')::CIDR = c.requester_cidr_block) + GROUP BY + r ->> 'VpcPeeringConnectionId' + ) + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN t.peering_connection_id IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN t.peering_connection_id IS NOT NULL THEN c.title || ' does not have least privilege access.' + ELSE c.title || ' have least privilege access.' + END AS reason + FROM + aws_vpc_peering_connection AS c + LEFT JOIN vpc_peering_routing_tables AS t + ON t.peering_connection_id = c.id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPCs peering connection route tables should have least privilege \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_route_table_restrict_public_access_to_igw.yaml b/compliance/controls/aws/aws_vpc_route_table_restrict_public_access_to_igw.yaml old mode 100755 new mode 100644 index 71fa56e56..dc6fd90e5 --- a/compliance/controls/aws/aws_vpc_route_table_restrict_public_access_to_igw.yaml +++ b/compliance/controls/aws/aws_vpc_route_table_restrict_public_access_to_igw.yaml @@ -1,13 +1,46 @@ +Description: Ensure that there are public routes in the route table to an Internet Gateway (IGW). The rule is non-compliant if a route to an IGW has a destination CIDR block of '0.0.0.0/0' or '::/0'. ID: aws_vpc_route_table_restrict_public_access_to_igw -Title: "VPC route table should restrict public access to IGW" -Description: "Ensure that there are public routes in the route table to an Internet Gateway (IGW). The rule is non-compliant if a route to an IGW has a destination CIDR block of '0.0.0.0/0' or '::/0'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with route_with_public_access as (\n select\n route_table_id,\n count(*) as num\n from\n aws_vpc_route_table,\n jsonb_array_elements(routes) as r\n where\n ( r ->> 'DestinationCidrBlock' = '0.0.0.0/0'\n or r ->> 'DestinationCidrBlock' = '::/0'\n )\n and r ->> 'GatewayId' like 'igw%'\n group by\n route_table_id\n)\nselect\n a.route_table_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.route_table_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.route_table_id is null then a.title || ' does not have public routes to an Internet Gateway (IGW)'\n else a.title || ' contains ' || b.num || ' rule(s) which have public routes to an Internet Gateway (IGW)'\n end as reason\n \n , region, account_id\nfrom\n aws_vpc_route_table as a\n left join route_with_public_access as b on b.route_table_id = a.route_table_id;\n" - PrimaryTable: aws_vpc_route_table ListOfTables: - aws_vpc_route_table Parameters: [] + PrimaryTable: aws_vpc_route_table + QueryToExecute: | + WITH route_with_public_access AS ( + SELECT + route_table_id, + COUNT(*) AS num + FROM + aws_vpc_route_table, + jsonb_array_elements(routes) AS r + WHERE + (r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + OR r ->> 'DestinationCidrBlock' = '::/0') + AND r ->> 'GatewayId' LIKE 'igw%' + GROUP BY + route_table_id + ) + SELECT + a.route_table_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.route_table_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.route_table_id IS NULL THEN a.title || ' does not have public routes to an Internet Gateway (IGW)' + ELSE a.title || ' contains ' || b.num || ' rule(s) which have public routes to an Internet Gateway (IGW)' + END AS reason, + region, + account_id + FROM + aws_vpc_route_table AS a + LEFT JOIN route_with_public_access AS b + ON b.route_table_id = a.route_table_id; Severity: high Tags: category: @@ -24,10 +57,10 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -38,5 +71,4 @@ Tags: - "true" service: - AWS/VPC -IntegrationType: - - aws_cloud_account +Title: VPC route table should restrict public access to IGW \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_allows_ingress_authorized_ports.yaml b/compliance/controls/aws/aws_vpc_security_group_allows_ingress_authorized_ports.yaml old mode 100755 new mode 100644 index f03767007..aa208558c --- a/compliance/controls/aws/aws_vpc_security_group_allows_ingress_authorized_ports.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_allows_ingress_authorized_ports.yaml @@ -1,14 +1,48 @@ +Description: This control checks whether the VPC security groups that are in use allow unrestricted incoming traffic. Optionally the rule checks whether the port numbers are listed in the authorizedTcpPorts parameter. The default values for authorizedTcpPorts are 80 and 443. ID: aws_vpc_security_group_allows_ingress_authorized_ports -Title: "VPC Security groups should only allow unrestricted incoming traffic for authorized ports" -Description: "This control checks whether the VPC security groups that are in use allow unrestricted incoming traffic. Optionally the rule checks whether the port numbers are listed in the authorizedTcpPorts parameter. The default values for authorizedTcpPorts are 80 and 443." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with ingress_unauthorized_ports as (\n select\n group_id,\n count(*)\n from\n aws_vpc_security_group_rule\n where\n type = 'ingress'\n and cidr_ipv4 = '0.0.0.0/0'\n and (from_port is null or from_port not in (80,443))\n group by\n group_id\n)\nselect\n sg.arn as resource,\n sg.og_account_id as og_account_id,\n sg.og_resource_id as og_resource_id,\n case\n when ingress_unauthorized_ports.count > 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when ingress_unauthorized_ports.count > 0 then sg.title || ' having unrestricted incoming traffic other than default ports from 0.0.0.0/0 '\n else sg.title || ' allows unrestricted incoming traffic for authorized default ports (80,443).'\n end as reason\n \n , sg.region, sg.account_id\nfrom\n aws_vpc_security_group as sg\n left join ingress_unauthorized_ports on ingress_unauthorized_ports.group_id = sg.group_id;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group - aws_vpc_security_group_rule Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_unauthorized_ports AS ( + SELECT + group_id, + COUNT(*) + FROM + aws_vpc_security_group_rule + WHERE + type = 'ingress' + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + from_port IS NULL + OR from_port NOT IN (80, 443) + ) + GROUP BY + group_id + ) + SELECT + sg.arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN ingress_unauthorized_ports.count > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ingress_unauthorized_ports.count > 0 THEN sg.title || ' having unrestricted incoming traffic other than default ports from 0.0.0.0/0 ' + ELSE sg.title || ' allows unrestricted incoming traffic for authorized default ports (80, 443).' + END AS reason, + sg.region, + sg.account_id + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_unauthorized_ports ON ingress_unauthorized_ports.group_id = sg.group_id Severity: high Tags: aws_foundational_security: @@ -23,5 +57,4 @@ Tags: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: VPC Security groups should only allow unrestricted incoming traffic for authorized ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_cassandra_ports.yaml b/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_cassandra_ports.yaml old mode 100755 new mode 100644 index 20b0c2c86..4e313e7da --- a/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_cassandra_ports.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_cassandra_ports.yaml @@ -1,15 +1,53 @@ +Description: This control checks whether the VPC security groups allow ingress from 0.0.0.0/0 or ::/0 to cassandra ports 7199 or 9160 or 8888. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 from ports 7199 or 9160 or 8888. ID: aws_vpc_security_group_allows_ingress_to_cassandra_ports -Title: "VPC security groups should restrict ingress from 0.0.0.0/0 or ::/0 to cassandra ports 7199 or 9160 or 8888" -Description: "This control checks whether the VPC security groups allow ingress from 0.0.0.0/0 or ::/0 to cassandra ports 7199 or 9160 or 8888. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 from ports 7199 or 9160 or 8888." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with ingress_ssh_rules as (\n select\n group_id,\n count(*) as num_ssh_rules\n from\n aws_vpc_security_group_rule\n where\n type = 'ingress'\n and cidr_ipv4 = '0.0.0.0/0'\n and (\n ( ip_protocol = '-1'\n and from_port is null\n )\n or (\n from_port >= 7199\n and to_port <= 7199\n ) or (\n from_port >= 9160\n and to_port <= 9160\n ) or (\n from_port >= 8888\n and to_port <= 8888\n )\n )\n group by\n group_id\n)\nselect\n arn as resource,\n sg.og_account_id as og_account_id,\n sg.og_resource_id as og_resource_id,\n case\n when ingress_ssh_rules.group_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when ingress_ssh_rules.group_id is null then sg.group_id || ' ingress restricted for cassandra ports from 0.0.0.0/0.'\n else sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for cassandra ports from 0.0.0.0/0.'\n end as reason \n \nfrom\n aws_vpc_security_group as sg\n left join ingress_ssh_rules on ingress_ssh_rules.group_id = sg.group_id;" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group_rule - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_ssh_rules AS ( + SELECT + group_id, + COUNT(*) AS num_ssh_rules + FROM + aws_vpc_security_group_rule + WHERE + type = 'ingress' + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' + AND from_port IS NULL) + OR (from_port >= 7199 + AND to_port <= 7199) + OR (from_port >= 9160 + AND to_port <= 9160) + OR (from_port >= 8888 + AND to_port <= 8888) + ) + GROUP BY + group_id + ) + + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN sg.group_id || ' ingress restricted for cassandra ports from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for cassandra ports from 0.0.0.0/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_ssh_rules ON ingress_ssh_rules.group_id = sg.group_id Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict ingress from 0.0.0.0/0 or ::/0 to cassandra ports 7199 or 9160 or 8888 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_memcached_port.yaml b/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_memcached_port.yaml old mode 100755 new mode 100644 index 50da870e5..63294b0e3 --- a/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_memcached_port.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_memcached_port.yaml @@ -1,51 +1,49 @@ +Description: This control checks whether the VPC security groups that are in use allow allow ingress from 0.0.0.0/0 or ::/0 to memcached port 11211. Optionally the rule checks whether the port numbers are listed in the authorizedTcpPorts parameter. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 from port 11211. ID: aws_vpc_security_group_allows_ingress_to_memcached_port -Title: "VPC security groups should restrict ingress from 0.0.0.0/0 or ::/0 to memcached port 11211" -Description: "This control checks whether the VPC security groups that are in use allow allow ingress from 0.0.0.0/0 or ::/0 to memcached port 11211. Optionally the rule checks whether the port numbers are listed in the authorizedTcpPorts parameter. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 from port 11211." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ingress_ssh_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_ssh_rules AS ( + SELECT group_id, - count(*) as num_ssh_rules - from + COUNT(*) AS num_ssh_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and cidr_ipv4 = '0.0.0.0/0' - and ( - ( ip_protocol = '-1' - and from_port is null - ) - or ( - from_port >= 11211 - and to_port <= 11211 - ) + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR ( + from_port >= 11211 + AND to_port <= 11211 + ) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when ingress_ssh_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when ingress_ssh_rules.group_id is null then sg.group_id || ' ingress restricted for memcached port from 0.0.0.0/0.' - else sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for memcached port from 0.0.0.0/0.' - end as reason - from - aws_vpc_security_group as sg - left join ingress_ssh_rules on ingress_ssh_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN sg.group_id || ' ingress restricted for memcached port from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for memcached port from 0.0.0.0/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_ssh_rules ON ingress_ssh_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict ingress from 0.0.0.0/0 or ::/0 to memcached port 11211 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_mongodb_ports.yaml b/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_mongodb_ports.yaml old mode 100755 new mode 100644 index f7d554bc5..2b2d1a6f7 --- a/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_mongodb_ports.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_mongodb_ports.yaml @@ -1,55 +1,48 @@ +Description: This control checks whether the VPC security groups that are in use allow ingress from 0.0.0.0/0 or ::/0 to mongoDB ports 27017 and 27018. Optionally the rule checks whether the port numbers are listed in the authorizedTcpPorts parameter. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 from ports 27017 and 27018. ID: aws_vpc_security_group_allows_ingress_to_mongodb_ports -Title: "VPC security groups should restrict ingress from 0.0.0.0/0 or ::/0 to mongoDB ports 27017 and 27018" -Description: "This control checks whether the VPC security groups that are in use allow ingress from 0.0.0.0/0 or ::/0 to mongoDB ports 27017 and 27018. Optionally the rule checks whether the port numbers are listed in the authorizedTcpPorts parameter. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 from ports 27017 and 27018." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ingress_ssh_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_ssh_rules AS ( + SELECT group_id, - count(*) as num_ssh_rules - from + COUNT(*) AS num_ssh_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and cidr_ipv4 = '0.0.0.0/0' - and ( - ( ip_protocol = '-1' - and from_port is null - ) - or ( - from_port >= 27017 - and to_port <= 27017 - ) - or ( - from_port >= 27018 - and to_port <= 27018 - ) + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR (from_port >= 27017 AND to_port <= 27017) + OR (from_port >= 27018 AND to_port <= 27018) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when ingress_ssh_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when ingress_ssh_rules.group_id is null then sg.group_id || ' ingress restricted for mongodb ports from 0.0.0.0/0.' - else sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for mongodb ports from 0.0.0.0/0.' - end as reason - from - aws_vpc_security_group as sg - left join ingress_ssh_rules on ingress_ssh_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN sg.group_id || ' ingress restricted for mongodb ports from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for mongodb ports from 0.0.0.0/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_ssh_rules + ON ingress_ssh_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict ingress from 0.0.0.0/0 or ::/0 to mongoDB ports 27017 and 27018 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_oracle_ports.yaml b/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_oracle_ports.yaml old mode 100755 new mode 100644 index 27a287666..41573c59f --- a/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_oracle_ports.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_allows_ingress_to_oracle_ports.yaml @@ -1,54 +1,53 @@ +Description: This control checks whether the VPC security groups that are in use allow ingress from 0.0.0.0/0 or ::/0 to oracle ports 1521 or 2483. Optionally the rule checks whether the port numbers are listed in the authorizedTcpPorts parameter. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 from ports 1521 or 2483. ID: aws_vpc_security_group_allows_ingress_to_oracle_ports -Title: "VPC security groups should restrict ingress from 0.0.0.0/0 or ::/0 to oracle ports 1521 or 2483" -Description: "This control checks whether the VPC security groups that are in use allow ingress from 0.0.0.0/0 or ::/0 to oracle ports 1521 or 2483. Optionally the rule checks whether the port numbers are listed in the authorizedTcpPorts parameter. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 from ports 1521 or 2483." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ingress_ssh_rules as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_ssh_rules AS ( + SELECT group_id, - count(*) as num_ssh_rules - from + COUNT(*) AS num_ssh_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and cidr_ipv4 = '0.0.0.0/0' - and ( - ( ip_protocol = '-1' - and from_port is null + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR ( + from_port >= 1521 + AND to_port <= 1521 ) - or ( - from_port >= 1521 - and to_port <= 1521 - ) or ( - from_port >= 2483 - and to_port <= 2483 + OR ( + from_port >= 2483 + AND to_port <= 2483 ) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when ingress_ssh_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when ingress_ssh_rules.group_id is null then sg.group_id || ' ingress restricted for oracle ports from 0.0.0.0/0.' - else sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for oracle ports from 0.0.0.0/0.' - end as reason - from - aws_vpc_security_group as sg - left join ingress_ssh_rules on ingress_ssh_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN sg.group_id || ' ingress restricted for oracle ports from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for oracle ports from 0.0.0.0/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_ssh_rules ON ingress_ssh_rules.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict ingress from 0.0.0.0/0 or ::/0 to oracle ports 1521 or 2483 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_associated_to_eni.yaml b/compliance/controls/aws/aws_vpc_security_group_associated_to_eni.yaml old mode 100755 new mode 100644 index a32c169aa..7149ffb2b --- a/compliance/controls/aws/aws_vpc_security_group_associated_to_eni.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_associated_to_eni.yaml @@ -1,14 +1,43 @@ +Description: This rule ensures the security groups are attached to an AWS Elastic Compute Cloud (AWS EC2) instance or to an ENI. This rule helps monitoring unused security groups in the inventory and the management of your environment. ID: aws_vpc_security_group_associated_to_eni -Title: "VPC security groups should be associated with at least one ENI" -Description: "This rule ensures the security groups are attached to an AWS Elastic Compute Cloud (AWS EC2) instance or to an ENI. This rule helps monitoring unused security groups in the inventory and the management of your environment." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with associated_sg as (\n select\n count(sg ->> 'GroupId'),\n sg ->> 'GroupId' as secgrp_id\n from\n aws_ec2_network_interface,\n jsonb_array_elements(groups) as sg\n group by sg ->> 'GroupId'\n)\nselect\n distinct s.arn as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when a.secgrp_id = s.group_id then 'ok'\n else 'alarm'\n end as status,\n case\n when a.secgrp_id = s.group_id then s.title || ' is associated with ' || a.count || ' ENI(s).'\n else s.title || ' not associated to any ENI.'\n end as reason\n \n , region, account_id\nfrom\n aws_vpc_security_group as s\n left join associated_sg as a on s.group_id = a.secgrp_id;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_ec2_network_interface - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH associated_sg AS ( + SELECT + COUNT(sg ->> 'GroupId'), + sg ->> 'GroupId' AS secgrp_id + FROM + aws_ec2_network_interface, + JSONB_ARRAY_ELEMENTS(groups) AS sg + GROUP BY + sg ->> 'GroupId' + ) + SELECT + DISTINCT s.arn AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN a.secgrp_id = s.group_id THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.secgrp_id = s.group_id THEN s.title || ' is associated with ' || a.count || ' ENI(s).' + ELSE s.title || ' not associated to any ENI.' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group AS s + LEFT JOIN + associated_sg AS a ON s.group_id = a.secgrp_id; Severity: low Tags: category: @@ -23,5 +52,4 @@ Tags: - AWS/VPC soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: VPC security groups should be associated with at least one ENI \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_not_uses_launch_wizard_sg.yaml b/compliance/controls/aws/aws_vpc_security_group_not_uses_launch_wizard_sg.yaml old mode 100755 new mode 100644 index 8f95c9abc..b7724253e --- a/compliance/controls/aws/aws_vpc_security_group_not_uses_launch_wizard_sg.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_not_uses_launch_wizard_sg.yaml @@ -1,41 +1,42 @@ +Description: Ensure the launch-wizard security group in your AWS account is not being used. ID: aws_vpc_security_group_not_uses_launch_wizard_sg -Title: "VPC security groups should restrict uses of 'launch-wizard' security groups." -Description: "Ensure the launch-wizard security group in your AWS account is not being used." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with associated_sg as ( - select - distinct (sg ->> 'GroupName') as sg_name - from - aws_ec2_network_interface, - jsonb_array_elements(groups) as sg - where - (sg ->> 'GroupName') like 'launch-wizard%' - ) - select - arn as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when a.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when a.sg_name is null then title || ' not in use.' - else title || ' in use.' - end as reason - from - aws_vpc_security_group as s - left join associated_sg as a on a.sg_name = s.group_name - where - group_name like 'launch-wizard%'; - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_ec2_network_interface - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH associated_sg AS ( + SELECT + DISTINCT (sg ->> 'GroupName') AS sg_name + FROM + aws_ec2_network_interface, + JSONB_ARRAY_ELEMENTS(groups) AS sg + WHERE + (sg ->> 'GroupName') LIKE 'launch-wizard%' + ) + SELECT + arn AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN a.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.sg_name IS NULL THEN title || ' not in use.' + ELSE title || ' in use.' + END AS reason + FROM + aws_vpc_security_group AS s + LEFT JOIN associated_sg AS a + ON a.sg_name = s.group_name + WHERE + group_name LIKE 'launch-wizard%'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict uses of 'launch-wizard' security groups. \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_remote_administration.yaml b/compliance/controls/aws/aws_vpc_security_group_remote_administration.yaml old mode 100755 new mode 100644 index d4e451876..a35aabaf3 --- a/compliance/controls/aws/aws_vpc_security_group_remote_administration.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_remote_administration.yaml @@ -1,14 +1,59 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_vpc_security_group_remote_administration -Title: "Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bad_rules as (\n select\n group_id,\n count(*) as num_bad_rules\n from\n aws_vpc_security_group_rule\n where\n type = 'ingress'\n and (\n cidr_ipv4 = '0.0.0.0/0'\n or cidr_ipv6 = '::/0'\n )\n and (\n ( ip_protocol = '-1' -- all traffic\n and from_port is null\n )\n or (\n from_port >= 22\n and to_port <= 22\n )\n or (\n from_port >= 3389\n and to_port <= 3389\n )\n )\n group by\n group_id\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when bad_rules.group_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n end as reason\n \n , sg.region, sg.account_id\nfrom\n aws_vpc_security_group as sg\n left join bad_rules on bad_rules.group_id = sg.group_id;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group - aws_vpc_security_group_rule Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT + group_id, + COUNT(*) AS num_bad_rules + FROM + aws_vpc_security_group_rule + WHERE + type = 'ingress' + AND ( + cidr_ipv4 = '0.0.0.0/0' + OR cidr_ipv6 = '::/0' + ) + AND ( + (ip_protocol = '-1' -- all traffic + AND from_port IS NULL) + OR ( + from_port >= 22 + AND to_port <= 22 + ) + OR ( + from_port >= 3389 + AND to_port <= 3389 + ) + ) + GROUP BY + group_id + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason, + sg.region, + sg.account_id + FROM + aws_vpc_security_group AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id Severity: high Tags: category: @@ -29,5 +74,4 @@ Tags: - aws service: - AWS/VPC -IntegrationType: - - aws_cloud_account +Title: Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_remote_administration_ipv4.yaml b/compliance/controls/aws/aws_vpc_security_group_remote_administration_ipv4.yaml old mode 100755 new mode 100644 index cd1115d8b..7b103d223 --- a/compliance/controls/aws/aws_vpc_security_group_remote_administration_ipv4.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_remote_administration_ipv4.yaml @@ -1,14 +1,54 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389, using either the TCP (6), UDP (17) or ALL (-1) protocols. ID: aws_vpc_security_group_remote_administration_ipv4 -Title: "Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389, using either the TCP (6), UDP (17) or ALL (-1) protocols." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bad_rules as (\n select\n group_id,\n count(*) as num_bad_rules\n from\n aws_vpc_security_group_rule\n where\n type = 'ingress'\n and (\n cidr_ipv4 = '0.0.0.0/0'\n )\n and (\n ( ip_protocol = '-1' -- all traffic\n and from_port is null\n )\n or (\n from_port >= 22\n and to_port <= 22\n )\n or (\n from_port >= 3389\n and to_port <= 3389\n )\n )\n group by\n group_id\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when bad_rules.group_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0.'\n else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0.'\n end as reason\n \n , sg.region, sg.account_id\nfrom\n aws_vpc_security_group as sg\n left join bad_rules on bad_rules.group_id = sg.group_id;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group - aws_vpc_security_group_rule Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT + group_id, + COUNT(*) AS num_bad_rules + FROM + aws_vpc_security_group_rule + WHERE + type = 'ingress' + AND ( + cidr_ipv4 = '0.0.0.0/0' + ) + AND ( + (ip_protocol = '-1' + AND from_port IS NULL) + OR (from_port >= 22 + AND to_port <= 22) + OR (from_port >= 3389 + AND to_port <= 3389) + ) + GROUP BY + group_id + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from 0.0.0.0/0.' + END AS reason, + sg.region, + sg.account_id + FROM + aws_vpc_security_group AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id; Severity: critical Tags: category: @@ -29,5 +69,4 @@ Tags: - aws service: - AWS/VPC -IntegrationType: - - aws_cloud_account +Title: Ensure no security groups allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_remote_administration_ipv6.yaml b/compliance/controls/aws/aws_vpc_security_group_remote_administration_ipv6.yaml old mode 100755 new mode 100644 index 53bcc0444..eefa8f73f --- a/compliance/controls/aws/aws_vpc_security_group_remote_administration_ipv6.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_remote_administration_ipv6.yaml @@ -1,14 +1,58 @@ +Description: Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_vpc_security_group_remote_administration_ipv6 -Title: "Ensure no security groups allow ingress from ::/0 to remote server administration ports" -Description: "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bad_rules as (\n select\n group_id,\n count(*) as num_bad_rules\n from\n aws_vpc_security_group_rule\n where\n type = 'ingress'\n and (\n cidr_ipv6 = '::/0'\n )\n and (\n ( ip_protocol = '-1' -- all traffic\n and from_port is null\n )\n or (\n from_port >= 22\n and to_port <= 22\n )\n or (\n from_port >= 3389\n and to_port <= 3389\n )\n )\n group by\n group_id\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when bad_rules.group_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to port 22 or 3389 from ::/0.'\n else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from ::/0.'\n end as reason\n \n , sg.region, sg.account_id\nfrom\n aws_vpc_security_group as sg\n left join bad_rules on bad_rules.group_id = sg.group_id;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group - aws_vpc_security_group_rule Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH bad_rules AS ( + SELECT + group_id, + COUNT(*) AS num_bad_rules + FROM + aws_vpc_security_group_rule + WHERE + type = 'ingress' + AND ( + cidr_ipv6 = '::/0' + ) + AND ( + (ip_protocol = '-1' -- all traffic + AND from_port IS NULL) + OR ( + from_port >= 22 + AND to_port <= 22 + ) + OR ( + from_port >= 3389 + AND to_port <= 3389 + ) + ) + GROUP BY + group_id + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to port 22 or 3389 from ::/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to port 22 or 3389 from ::/0.' + END AS reason, + sg.region, + sg.account_id + FROM + aws_vpc_security_group AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id Severity: critical Tags: category: @@ -29,5 +73,4 @@ Tags: - aws service: - AWS/VPC -IntegrationType: - - aws_cloud_account +Title: Ensure no security groups allow ingress from ::/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_common_ports_all.yaml b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_common_ports_all.yaml old mode 100755 new mode 100644 index fb7a586ee..a7acdd732 --- a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_common_ports_all.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_common_ports_all.yaml @@ -1,14 +1,53 @@ +Description: Manage access to resources in the AWS Cloud by ensuring common ports are restricted on AWS Elastic Compute Cloud (AWS EC2) security groups. ID: aws_vpc_security_group_restrict_ingress_common_ports_all -Title: "VPC security groups should restrict ingress access on ports 20, 21, 22, 3306, 3389, 4333 from 0.0.0.0/0" -Description: "Manage access to resources in the AWS Cloud by ensuring common ports are restricted on AWS Elastic Compute Cloud (AWS EC2) security groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with ingress_ssh_rules as (\n select\n group_id,\n count(*) as num_ssh_rules\n from\n aws_vpc_security_group_rule\n where\n type = 'ingress'\n and cidr_ipv4 = '0.0.0.0/0'\n and (\n ( ip_protocol = '-1'\n and from_port is null\n )\n or (\n from_port >= 22\n and to_port <= 22\n )\n or (\n from_port >= 3389\n and to_port <= 3389\n )\n or (\n from_port >= 21\n and to_port <= 21\n )\n or (\n from_port >= 20\n and to_port <= 20\n )\n or (\n from_port >= 3306\n and to_port <= 3306\n )\n or (\n from_port >= 4333\n and to_port <= 4333\n )\n )\n group by\n group_id\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when ingress_ssh_rules.group_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when ingress_ssh_rules.group_id is null then sg.group_id || ' ingress restricted for ports 20, 21, 22, 3306, 3389, 4333 from 0.0.0.0/0.'\n else sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access on ports 20, 21, 22, 3306, 3389, 4333 from 0.0.0.0/0.'\n end as reason\n \n , region, account_id\nfrom\n aws_vpc_security_group as sg\n left join ingress_ssh_rules on ingress_ssh_rules.group_id = sg.group_id;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group - aws_vpc_security_group_rule Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_ssh_rules AS ( + SELECT + group_id, + COUNT(*) AS num_ssh_rules + FROM + aws_vpc_security_group_rule + WHERE + type = 'ingress' + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR (from_port >= 22 AND to_port <= 22) + OR (from_port >= 3389 AND to_port <= 3389) + OR (from_port >= 21 AND to_port <= 21) + OR (from_port >= 20 AND to_port <= 20) + OR (from_port >= 3306 AND to_port <= 3306) + OR (from_port >= 4333 AND to_port <= 4333) + ) + GROUP BY + group_id + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN sg.group_id || ' ingress restricted for ports 20, 21, 22, 3306, 3389, 4333 from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access on ports 20, 21, 22, 3306, 3389, 4333 from 0.0.0.0/0.' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_ssh_rules ON ingress_ssh_rules.group_id = sg.group_id; Severity: high Tags: audit_manager_control_tower: @@ -29,12 +68,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -45,5 +84,4 @@ Tags: - AWS/VPC soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict ingress access on ports 20, 21, 22, 3306, 3389, 4333 from 0.0.0.0/0 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_kafka_port.yaml b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_kafka_port.yaml old mode 100755 new mode 100644 index f96b12a93..976529d85 --- a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_kafka_port.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_kafka_port.yaml @@ -1,54 +1,53 @@ +Description: AWS VPC security groups can help in managing network access by providing stateful filtering of ingress and egress network traffic to AWS resources. ID: aws_vpc_security_group_restrict_ingress_kafka_port -Title: "VPC security groups should restrict ingress Kafka port access from 0.0.0.0/0" -Description: "AWS VPC security groups can help in managing network access by providing stateful filtering of ingress and egress network traffic to AWS resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ingress_kafka_port as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_kafka_port AS ( + SELECT group_id, - count(*) as num_ssh_rules - from + COUNT(*) AS num_ssh_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and ( + AND ( cidr_ipv4 = '0.0.0.0/0' - or cidr_ipv6 = '::/0' + OR cidr_ipv6 = '::/0' ) - and ( - ( ip_protocol = '-1' - and from_port is null - ) - or ( - from_port >= 9092 - and to_port <= 9092 - ) + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR ( + from_port >= 9092 + AND to_port <= 9092 + ) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when k.group_id is null then 'ok' - else 'alarm' - end as status, - case - when k.group_id is null then sg.group_id || ' ingress restricted for kafka port from 0.0.0.0/0.' - else sg.group_id || ' contains ' || k.num_ssh_rules || ' ingress rule(s) allowing kafka port from 0.0.0.0/0.' - end as reason - from - aws_vpc_security_group as sg - left join ingress_kafka_port as k on k.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN k.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN k.group_id IS NULL THEN sg.group_id || ' ingress restricted for kafka port from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || k.num_ssh_rules || ' ingress rule(s) allowing kafka port from 0.0.0.0/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_kafka_port AS k + ON k.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict ingress Kafka port access from 0.0.0.0/0 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_kibana_port.yaml b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_kibana_port.yaml old mode 100755 new mode 100644 index 8fbf64479..dcc6ffe64 --- a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_kibana_port.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_kibana_port.yaml @@ -1,58 +1,51 @@ +Description: AWS VPC security groups can help in managing network access by providing stateful filtering of ingress and egress network traffic to AWS resources. ID: aws_vpc_security_group_restrict_ingress_kibana_port -Title: "VPC security groups should restrict ingress kibana port access from 0.0.0.0/0" -Description: "AWS VPC security groups can help in managing network access by providing stateful filtering of ingress and egress network traffic to AWS resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ingress_kibana_port as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_kibana_port AS ( + SELECT group_id, - count(*) as num_ssh_rules - from + COUNT(*) AS num_ssh_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and ( + AND ( cidr_ipv4 = '0.0.0.0/0' - or cidr_ipv6 = '::/0' + OR cidr_ipv6 = '::/0' ) - and ( - ( ip_protocol = '-1' - and from_port is null - ) - or ( - from_port >= 9200 - and to_port <= 9200 - ) - or ( - from_port >= 5601 - and to_port <= 5601 - ) + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR (from_port >= 9200 AND to_port <= 9200) + OR (from_port >= 5601 AND to_port <= 5601) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when k.group_id is null then 'ok' - else 'alarm' - end as status, - case - when k.group_id is null then sg.group_id || ' ingress restricted for kibana port from 0.0.0.0/0.' - else sg.group_id || ' contains ' || k.num_ssh_rules || ' ingress rule(s) allowing kibana port from 0.0.0.0/0.' - end as reason - from - aws_vpc_security_group as sg - left join ingress_kibana_port as k on k.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN k.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN k.group_id IS NULL THEN sg.group_id || ' ingress restricted for kibana port from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || k.num_ssh_rules || ' ingress rule(s) allowing kibana port from 0.0.0.0/0.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_kibana_port AS k + ON k.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict ingress kibana port access from 0.0.0.0/0 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_rdp_all.yaml b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_rdp_all.yaml old mode 100755 new mode 100644 index 9119eea91..3f75df1c3 --- a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_rdp_all.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_rdp_all.yaml @@ -1,14 +1,49 @@ +Description: Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to port 3389. ID: aws_vpc_security_group_restrict_ingress_rdp_all -Title: "Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389" -Description: "Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with ingress_rdp_rules as (\n select\n group_id,\n count(*) as num_rdp_rules\n from\n aws_vpc_security_group_rule\n where\n type = 'ingress'\n and cidr_ipv4 = '0.0.0.0/0'\n and (\n ( ip_protocol = '-1'\n and from_port is null\n )\n or (\n from_port >= 3389\n and to_port <= 3389\n )\n )\n group by\n group_id\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when ingress_rdp_rules.group_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when ingress_rdp_rules.group_id is null then sg.group_id || ' ingress restricted for RDP from 0.0.0.0/0.'\n else sg.group_id || ' contains ' || ingress_rdp_rules.num_rdp_rules || ' ingress rule(s) allowing RDP from 0.0.0.0/0.'\n end as reason\n \n , sg.region, sg.account_id\nfrom\n aws_vpc_security_group as sg\n left join ingress_rdp_rules on ingress_rdp_rules.group_id = sg.group_id;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group - aws_vpc_security_group_rule Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_rdp_rules AS ( + SELECT + group_id, + COUNT(*) AS num_rdp_rules + FROM + aws_vpc_security_group_rule + WHERE + type = 'ingress' + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR (from_port >= 3389 AND to_port <= 3389) + ) + GROUP BY + group_id + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ingress_rdp_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_rdp_rules.group_id IS NULL THEN CONCAT(sg.group_id, ' ingress restricted for RDP from 0.0.0.0/0.') + ELSE CONCAT(sg.group_id, ' contains ', ingress_rdp_rules.num_rdp_rules, ' ingress rule(s) allowing RDP from 0.0.0.0/0.') + END AS reason, + sg.region, + sg.account_id + FROM + aws_vpc_security_group AS sg + LEFT JOIN + ingress_rdp_rules ON ingress_rdp_rules.group_id = sg.group_id Severity: high Tags: category: @@ -29,5 +64,4 @@ Tags: - aws service: - AWS/VPC -IntegrationType: - - aws_cloud_account +Title: Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_redis_port.yaml b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_redis_port.yaml old mode 100755 new mode 100644 index 9ad0c28a3..f92024e5c --- a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_redis_port.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_redis_port.yaml @@ -1,54 +1,49 @@ +Description: AWS VPC security groups can help in managing network access by providing stateful filtering of ingress and egress network traffic to AWS resources. ID: aws_vpc_security_group_restrict_ingress_redis_port -Title: "VPC security groups should restrict ingress redis access from 0.0.0.0/0" -Description: "AWS VPC security groups can help in managing network access by providing stateful filtering of ingress and egress network traffic to AWS resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with ingress_redis_port as ( - select + ListOfTables: + - aws_vpc_security_group_rule + - aws_vpc_security_group + Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_redis_port AS ( + SELECT group_id, - count(*) as num_redis_rules - from + COUNT(*) AS num_redis_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and - (cidr_ipv4 = '0.0.0.0/0' - or cidr_ipv6 = '::/0') - and - ( - ( ip_protocol = '-1' - and from_port is null - ) - or ( - from_port >= 6379 - and to_port <= 6379 - ) + AND ( + cidr_ipv4 = '0.0.0.0/0' + OR cidr_ipv6 = '::/0' + ) + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR (from_port >= 6379 AND to_port <= 6379) ) - group by + GROUP BY group_id ) - select - arn as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when ingress_redis_port.group_id is null then 'ok' - else 'alarm' - end as status, - case - when ingress_redis_port.group_id is null then sg.group_id || ' restricted ingress from 0.0.0.0/0 or ::/0 to Redis port 6379.' - else sg.group_id || ' contains ' || ingress_redis_port.num_redis_rules || ' ingress rule(s) from 0.0.0.0/0 or ::/0 to Redis port 6379.' - end as reason - from - aws_vpc_security_group as sg - left join ingress_redis_port on ingress_redis_port.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group_rule - - aws_vpc_security_group - Parameters: [] + SELECT + arn AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN ingress_redis_port.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_redis_port.group_id IS NULL THEN sg.group_id || ' restricted ingress from 0.0.0.0/0 or ::/0 to Redis port 6379.' + ELSE sg.group_id || ' contains ' || ingress_redis_port.num_redis_rules || ' ingress rule(s) from 0.0.0.0/0 or ::/0 to Redis port 6379.' + END AS reason + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_redis_port ON ingress_redis_port.group_id = sg.group_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict ingress redis access from 0.0.0.0/0 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_ssh_all.yaml b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_ssh_all.yaml old mode 100755 new mode 100644 index 2ee313bef..93cc8e167 --- a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_ssh_all.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_ssh_all.yaml @@ -1,14 +1,50 @@ +Description: AWS Elastic Compute Cloud (AWS EC2) Security Groups can help manage network access by providing stateful filtering of ingress and egress network traffic to AWS resources. ID: aws_vpc_security_group_restrict_ingress_ssh_all -Title: "VPC security groups should restrict ingress SSH access from 0.0.0.0/0" -Description: "AWS Elastic Compute Cloud (AWS EC2) Security Groups can help manage network access by providing stateful filtering of ingress and egress network traffic to AWS resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with ingress_ssh_rules as (\n select\n group_id,\n count(*) as num_ssh_rules\n from\n aws_vpc_security_group_rule\n where\n type = 'ingress'\n and cidr_ipv4 = '0.0.0.0/0'\n and (\n ( ip_protocol = '-1'\n and from_port is null\n )\n or (\n from_port >= 22\n and to_port <= 22\n )\n )\n group by\n group_id\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when ingress_ssh_rules.group_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when ingress_ssh_rules.group_id is null then sg.group_id || ' ingress restricted for SSH from 0.0.0.0/0.'\n else sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing SSH from 0.0.0.0/0.'\n end as reason\n \n , region, account_id\nfrom\n aws_vpc_security_group as sg\n left join ingress_ssh_rules on ingress_ssh_rules.group_id = sg.group_id;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group - aws_vpc_security_group_rule Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_ssh_rules AS ( + SELECT + group_id, + COUNT(*) AS num_ssh_rules + FROM + aws_vpc_security_group_rule + WHERE + type = 'ingress' + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR (from_port >= 22 AND to_port <= 22) + ) + GROUP BY + group_id + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_ssh_rules.group_id IS NULL + THEN sg.group_id || ' ingress restricted for SSH from 0.0.0.0/0.' + ELSE + sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing SSH from 0.0.0.0/0.' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_ssh_rules ON ingress_ssh_rules.group_id = sg.group_id Severity: high Tags: audit_manager_control_tower: @@ -31,12 +67,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -49,5 +85,4 @@ Tags: - AWS/VPC soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict ingress SSH access from 0.0.0.0/0 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_tcp_udp_all.yaml b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_tcp_udp_all.yaml old mode 100755 new mode 100644 index a1fa4db65..7921bc3f6 --- a/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_tcp_udp_all.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_restrict_ingress_tcp_udp_all.yaml @@ -1,49 +1,51 @@ +Description: Manage access to resources in the AWS Cloud by ensuring common ports are restricted on AWS Elastic Compute Cloud (AWS EC2) Security Groups. ID: aws_vpc_security_group_restrict_ingress_tcp_udp_all -Title: "VPC security groups should restrict ingress TCP and UDP access from 0.0.0.0/0" -Description: "Manage access to resources in the AWS Cloud by ensuring common ports are restricted on AWS Elastic Compute Cloud (AWS EC2) Security Groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_vpc_security_group + - aws_vpc_security_group_rule + Parameters: [] + PrimaryTable: aws_vpc_security_group QueryToExecute: | - with bad_rules as ( - select + WITH bad_rules AS ( + SELECT group_id, - count(*) as num_bad_rules - from + COUNT(*) AS num_bad_rules + FROM aws_vpc_security_group_rule - where + WHERE type = 'ingress' - and cidr_ipv4 = '0.0.0.0/0' - and ( - ip_protocol in ('tcp', 'udp') - or ( + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + ip_protocol IN ('tcp', 'udp') + OR ( ip_protocol = '-1' - and from_port is null + AND from_port IS NULL ) ) - group by + GROUP BY group_id ) - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when bad_rules.group_id is null then 'ok' - else 'alarm' - end as status, - case - when bad_rules.group_id is null then sg.group_id || ' does not allow ingress to TCP or UDP ports from 0.0.0.0/0.' - else sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to TCP or UDP ports from 0.0.0.0/0.' - end as reason - , region, account_id - from - aws_vpc_security_group as sg - left join bad_rules on bad_rules.group_id = sg.group_id; - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group - - aws_vpc_security_group_rule - Parameters: [] + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN bad_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.group_id IS NULL THEN sg.group_id || ' does not allow ingress to TCP or UDP ports from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) that allow ingress to TCP or UDP ports from 0.0.0.0/0.' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group AS sg + LEFT JOIN bad_rules ON bad_rules.group_id = sg.group_id; Severity: high Tags: category: @@ -62,12 +64,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -80,5 +82,4 @@ Tags: - AWS/VPC soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: VPC security groups should restrict ingress TCP and UDP access from 0.0.0.0/0 \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_restricted_common_ports.yaml b/compliance/controls/aws/aws_vpc_security_group_restricted_common_ports.yaml old mode 100755 new mode 100644 index 94743f8a5..291520d5c --- a/compliance/controls/aws/aws_vpc_security_group_restricted_common_ports.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_restricted_common_ports.yaml @@ -1,14 +1,65 @@ +Description: This control checks whether unrestricted incoming traffic for the security groups is accessible to the specified ports that have the highest risk. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 for those ports. ID: aws_vpc_security_group_restricted_common_ports -Title: "Security groups should not allow unrestricted access to ports with high risk" -Description: "This control checks whether unrestricted incoming traffic for the security groups is accessible to the specified ports that have the highest risk. This control passes when none of the rules in a security group allow ingress traffic from 0.0.0.0/0 for those ports." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with ingress_ssh_rules as (\n select\n group_id,\n count(*) as num_ssh_rules\n from\n aws_vpc_security_group_rule\n where\n type = 'ingress'\n and cidr_ipv4 = '0.0.0.0/0'\n and (\n ( ip_protocol = '-1'\n and from_port is null\n )\n or (\n from_port >= 22\n and to_port <= 22\n )\n or (\n from_port >= 3389\n and to_port <= 3389\n )\n or (\n from_port >= 21\n and to_port <= 21\n )\n or (\n from_port >= 20\n and to_port <= 20\n )\n or (\n from_port >= 3306\n and to_port <= 3306\n )\n or (\n from_port >= 4333\n and to_port <= 4333\n )\n or (\n from_port >= 23\n and to_port <= 23\n )\n or (\n from_port >= 25\n and to_port <= 25\n )\n or (\n from_port >= 445\n and to_port <= 445\n )\n or (\n from_port >= 110\n and to_port <= 110\n )\n or (\n from_port >= 135\n and to_port <= 135\n )\n or (\n from_port >= 143\n and to_port <= 143\n )\n or (\n from_port >= 1433\n and to_port <= 1433\n )\n or (\n from_port >= 5432\n and to_port <= 5432\n )\n or (\n from_port >= 5500\n and to_port <= 5500\n )\n or (\n from_port >= 5601\n and to_port <= 5601\n )\n or (\n from_port >= 9200\n and to_port <= 9300\n )\n or (\n from_port >= 8080\n and to_port <= 8080\n )\n )\n group by\n group_id\n)\nselect\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when ingress_ssh_rules.group_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when ingress_ssh_rules.group_id is null then sg.group_id || ' ingress restricted for common ports from 0.0.0.0/0..'\n else sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for common ports from 0.0.0.0/0.'\n end as reason\n \n , sg.region, sg.account_id\nfrom\n aws_vpc_security_group as sg\n left join ingress_ssh_rules on ingress_ssh_rules.group_id = sg.group_id;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group - aws_vpc_security_group_rule Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH ingress_ssh_rules AS ( + SELECT + group_id, + COUNT(*) AS num_ssh_rules + FROM + aws_vpc_security_group_rule + WHERE + type = 'ingress' + AND cidr_ipv4 = '0.0.0.0/0' + AND ( + (ip_protocol = '-1' AND from_port IS NULL) + OR (from_port >= 22 AND to_port <= 22) + OR (from_port >= 3389 AND to_port <= 3389) + OR (from_port >= 21 AND to_port <= 21) + OR (from_port >= 20 AND to_port <= 20) + OR (from_port >= 3306 AND to_port <= 3306) + OR (from_port >= 4333 AND to_port <= 4333) + OR (from_port >= 23 AND to_port <= 23) + OR (from_port >= 25 AND to_port <= 25) + OR (from_port >= 445 AND to_port <= 445) + OR (from_port >= 110 AND to_port <= 110) + OR (from_port >= 135 AND to_port <= 135) + OR (from_port >= 143 AND to_port <= 143) + OR (from_port >= 1433 AND to_port <= 1433) + OR (from_port >= 5432 AND to_port <= 5432) + OR (from_port >= 5500 AND to_port <= 5500) + OR (from_port >= 5601 AND to_port <= 5601) + OR (from_port >= 9200 AND to_port <= 9300) + OR (from_port >= 8080 AND to_port <= 8080) + ) + GROUP BY + group_id + ) + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ingress_ssh_rules.group_id IS NULL THEN sg.group_id || ' ingress restricted for common ports from 0.0.0.0/0.' + ELSE sg.group_id || ' contains ' || ingress_ssh_rules.num_ssh_rules || ' ingress rule(s) allowing access for common ports from 0.0.0.0/0.' + END AS reason, + sg.region, + sg.account_id + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_ssh_rules ON ingress_ssh_rules.group_id = sg.group_id Severity: medium Tags: aws_foundational_security: @@ -23,5 +74,4 @@ Tags: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: Security groups should not allow unrestricted access to ports with high risk \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_security_group_unused.yaml b/compliance/controls/aws/aws_vpc_security_group_unused.yaml old mode 100755 new mode 100644 index 3a510b799..fcc309874 --- a/compliance/controls/aws/aws_vpc_security_group_unused.yaml +++ b/compliance/controls/aws/aws_vpc_security_group_unused.yaml @@ -1,15 +1,51 @@ +Description: This AWS control checks that security groups are attached to AWS Elastic Compute Cloud (AWS EC2) instances or to an elastic network interface. The control will fail if the security group is not associated with an AWS EC2 instance or an elastic network interface. ID: aws_vpc_security_group_unused -Title: "Unused EC2 security groups should be removed" -Description: "This AWS control checks that security groups are attached to AWS Elastic Compute Cloud (AWS EC2) instances or to an elastic network interface. The control will fail if the security group is not associated with an AWS EC2 instance or an elastic network interface." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with associated_sg as (\n select\n sg ->> 'GroupId' as secgrp_id\n from\n aws_ec2_network_interface,\n jsonb_array_elements(groups) as sg\n group by sg ->> 'GroupId'\n union\n select\n sg ->> 'GroupId' as secgrp_id\n from\n aws_ec2_instance,\n jsonb_array_elements(security_groups) as sg\n group by sg ->> 'GroupId'\n)\nselect\n distinct s.arn as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when a.secgrp_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.secgrp_id is not null then s.title || ' is in use.'\n else s.title || ' not in use.'\n end as reason\n \n , s.region, s.account_id\nfrom\n aws_vpc_security_group as s\n left join associated_sg as a on s.group_id = a.secgrp_id;\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_ec2_instance - aws_ec2_network_interface - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + WITH associated_sg AS ( + SELECT + sg ->> 'GroupId' AS secgrp_id + FROM + aws_ec2_network_interface, + jsonb_array_elements(groups) AS sg + GROUP BY + sg ->> 'GroupId' + UNION + SELECT + sg ->> 'GroupId' AS secgrp_id + FROM + aws_ec2_instance, + jsonb_array_elements(security_groups) AS sg + GROUP BY + sg ->> 'GroupId' + ) + SELECT + DISTINCT s.arn AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN a.secgrp_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.secgrp_id IS NOT NULL THEN s.title || ' is in use.' + ELSE s.title || ' not in use.' + END AS reason, + s.region, + s.account_id + FROM + aws_vpc_security_group AS s + LEFT JOIN associated_sg AS a + ON s.group_id = a.secgrp_id; Severity: medium Tags: aws_foundational_security: @@ -24,5 +60,4 @@ Tags: - aws service: - AWS/EC2 -IntegrationType: - - aws_cloud_account +Title: Unused EC2 security groups should be removed \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_subnet_auto_assign_public_ip_disabled.yaml b/compliance/controls/aws/aws_vpc_subnet_auto_assign_public_ip_disabled.yaml old mode 100755 new mode 100644 index c377a252b..1adbff72b --- a/compliance/controls/aws/aws_vpc_subnet_auto_assign_public_ip_disabled.yaml +++ b/compliance/controls/aws/aws_vpc_subnet_auto_assign_public_ip_disabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure that AWS Virtual Private Cloud (AWS VPC) subnets are assigned a public IP address. The control is compliant if AWS VPC does not have subnets that are assigned a public IP address. The control is non-compliant if AWS VPC has subnets that are assigned a public IP address. ID: aws_vpc_subnet_auto_assign_public_ip_disabled -Title: "VPC subnet auto assign public IP should be disabled" -Description: "Ensure that AWS Virtual Private Cloud (AWS VPC) subnets are assigned a public IP address. The control is compliant if AWS VPC does not have subnets that are assigned a public IP address. The control is non-compliant if AWS VPC has subnets that are assigned a public IP address." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n subnet_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when map_public_ip_on_launch = 'false' then 'ok'\n else 'alarm'\n end as status,\n case\n when map_public_ip_on_launch = 'false' then title || ' auto assign public IP disabled.'\n else title || ' auto assign public IP enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_vpc_subnet;\n" - PrimaryTable: aws_vpc_subnet ListOfTables: - aws_vpc_subnet Parameters: [] + PrimaryTable: aws_vpc_subnet + QueryToExecute: | + SELECT + subnet_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN map_public_ip_on_launch = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN map_public_ip_on_launch = 'false' THEN title || ' auto assign public IP disabled.' + ELSE title || ' auto assign public IP enabled.' + END AS reason, + region, + account_id + FROM + aws_vpc_subnet; Severity: high Tags: category: @@ -26,10 +43,10 @@ Tags: - "true" hipaa_final_omnibus_security_rule_2013: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" plugin: @@ -38,5 +55,4 @@ Tags: - "true" service: - AWS/VPC -IntegrationType: - - aws_cloud_account +Title: VPC subnet auto assign public IP should be disabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_vpc_vpn_tunnel_up.yaml b/compliance/controls/aws/aws_vpc_vpn_tunnel_up.yaml old mode 100755 new mode 100644 index a651a19f3..a4047330f --- a/compliance/controls/aws/aws_vpc_vpn_tunnel_up.yaml +++ b/compliance/controls/aws/aws_vpc_vpn_tunnel_up.yaml @@ -1,13 +1,45 @@ +Description: Redundant Site-to-Site VPN tunnels can be implemented to achieve resilience requirements. ID: aws_vpc_vpn_tunnel_up -Title: "Both VPN tunnels provided by AWS Site-to-Site VPN should be in UP status" -Description: "Redundant Site-to-Site VPN tunnels can be implemented to achieve resilience requirements." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with filter_data as (\n select\n arn,\n count(t ->> 'Status')\n from\n aws_vpc_vpn_connection,\n jsonb_array_elements(vgw_telemetry) as t\n where t ->> 'Status' = 'UP'\n group by arn\n)\nselect\n a.arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.count is null or b.count < 2 then 'alarm'\n else 'ok'\n end as status,\n case\n when b.count is null then a.title || ' has both tunnels offline.'\n when b.count = 1 then a.title || ' has one tunnel offline.'\n else a.title || ' has both tunnels online.'\n end as reason\n \n , region, account_id\nfrom\n aws_vpc_vpn_connection as a\n left join filter_data as b on a.arn = b.arn;\n" - PrimaryTable: aws_vpc_vpn_connection ListOfTables: - aws_vpc_vpn_connection Parameters: [] + PrimaryTable: aws_vpc_vpn_connection + QueryToExecute: | + WITH filter_data AS ( + SELECT + arn, + COUNT(t ->> 'Status') + FROM + aws_vpc_vpn_connection, + jsonb_array_elements(vgw_telemetry) AS t + WHERE + t ->> 'Status' = 'UP' + GROUP BY + arn + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.count IS NULL OR b.count < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.count IS NULL THEN a.title || ' has both tunnels offline.' + WHEN b.count = 1 THEN a.title || ' has one tunnel offline.' + ELSE a.title || ' has both tunnels online.' + END AS reason, + region, + account_id + FROM + aws_vpc_vpn_connection AS a + LEFT JOIN + filter_data AS b ON a.arn = b.arn; Severity: medium Tags: category: @@ -34,5 +66,4 @@ Tags: - aws service: - AWS/VPC -IntegrationType: - - aws_cloud_account +Title: Both VPN tunnels provided by AWS Site-to-Site VPN should be in UP status \ No newline at end of file diff --git a/compliance/controls/aws/aws_waf_regional_rule_condition_attached.yaml b/compliance/controls/aws/aws_waf_regional_rule_condition_attached.yaml old mode 100755 new mode 100644 index 15b194391..34c7fb7c3 --- a/compliance/controls/aws/aws_waf_regional_rule_condition_attached.yaml +++ b/compliance/controls/aws/aws_waf_regional_rule_condition_attached.yaml @@ -1,28 +1,30 @@ +Description: This control checks whether WAF regional rule contains any conditions. The control fails if no conditions are present within a rule. ID: aws_waf_regional_rule_condition_attached -Title: "WAF regional rule should have at least one condition" -Description: "This control checks whether WAF regional rule contains any conditions. The control fails if no conditions are present within a rule." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - rule_id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when predicates is null or jsonb_array_length(predicates) = 0 then 'alarm' - else 'ok' - end as status, - case - when predicates is null or jsonb_array_length(predicates) = 0 then title || ' has no attached conditions.' - else title || ' has ' || jsonb_array_length(predicates) || ' condition(s) attached.' - end as reason - , region, account_id - from - aws_wafregional_rule; - PrimaryTable: aws_wafregional_rule ListOfTables: - aws_wafregional_rule Parameters: [] + PrimaryTable: aws_wafregional_rule + QueryToExecute: | + SELECT + rule_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN predicates IS NULL OR jsonb_array_length(predicates) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN predicates IS NULL OR jsonb_array_length(predicates) = 0 THEN title || ' has no attached conditions.' + ELSE title || ' has ' || jsonb_array_length(predicates) || ' condition(s) attached.' + END AS reason, + region, + account_id + FROM + aws_wafregional_rule; Severity: medium Tags: aws_foundational_security: @@ -37,5 +39,4 @@ Tags: - aws service: - AWS/WAF -IntegrationType: - - aws_cloud_account +Title: WAF regional rule should have at least one condition \ No newline at end of file diff --git a/compliance/controls/aws/aws_waf_regional_rule_group_rule_attached.yaml b/compliance/controls/aws/aws_waf_regional_rule_group_rule_attached.yaml old mode 100755 new mode 100644 index 61ec67036..aca506239 --- a/compliance/controls/aws/aws_waf_regional_rule_group_rule_attached.yaml +++ b/compliance/controls/aws/aws_waf_regional_rule_group_rule_attached.yaml @@ -1,13 +1,30 @@ +Description: This control checks if WAF regional rule groups contain any rules. The rule is non-compliant if there are no rules present within a WAF regional rule group. ID: aws_waf_regional_rule_group_rule_attached -Title: "WAF regional rule group should have at least one rule attached" -Description: "This control checks if WAF regional rule groups contain any rules. The rule is non-compliant if there are no rules present within a WAF regional rule group." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when activated_rules is null or jsonb_array_length(activated_rules) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when activated_rules is null or jsonb_array_length(activated_rules) = 0 then title || ' has no attached rules.'\n else title || ' has ' || jsonb_array_length(activated_rules) || ' rule(s) attached.'\n end as reason\n \n , region, account_id\nfrom\n aws_wafregional_rule_group;\n" - PrimaryTable: aws_wafregional_rule_group ListOfTables: - aws_wafregional_rule_group Parameters: [] + PrimaryTable: aws_wafregional_rule_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN activated_rules IS NULL OR jsonb_array_length(activated_rules) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN activated_rules IS NULL OR jsonb_array_length(activated_rules) = 0 THEN title || ' has no attached rules.' + ELSE title || ' has ' || jsonb_array_length(activated_rules) || ' rule(s) attached.' + END AS reason, + region, + account_id + FROM + aws_wafregional_rule_group; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/WAF -IntegrationType: - - aws_cloud_account +Title: WAF regional rule group should have at least one rule attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_waf_regional_web_acl_rule_attached.yaml b/compliance/controls/aws/aws_waf_regional_web_acl_rule_attached.yaml old mode 100755 new mode 100644 index 43fc5f635..6da497f0c --- a/compliance/controls/aws/aws_waf_regional_web_acl_rule_attached.yaml +++ b/compliance/controls/aws/aws_waf_regional_web_acl_rule_attached.yaml @@ -1,13 +1,30 @@ +Description: This control checks if a WAF regional Web ACL contains any WAF rules or rule groups. The rule is non-compliant if there are no WAF rules or rule groups present within a Web ACL. ID: aws_waf_regional_web_acl_rule_attached -Title: "WAF regional web ACL should have at least one rule or rule group attached" -Description: "This control checks if a WAF regional Web ACL contains any WAF rules or rule groups. The rule is non-compliant if there are no WAF rules or rule groups present within a Web ACL." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when rules is null or jsonb_array_length(rules) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when rules is null or jsonb_array_length(rules) = 0 then title || ' has no attached rules.'\n else title || ' has ' || jsonb_array_length(rules) || ' rule(s) attached.'\n end as reason\n \n , region, account_id\nfrom\n aws_wafregional_web_acl;\n" - PrimaryTable: aws_wafregional_web_acl ListOfTables: - aws_wafregional_web_acl Parameters: [] + PrimaryTable: aws_wafregional_web_acl + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN title || ' has no attached rules.' + ELSE title || ' has ' || jsonb_array_length(rules) || ' rule(s) attached.' + END AS reason, + region, + account_id + FROM + aws_wafregional_web_acl; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/WAF -IntegrationType: - - aws_cloud_account +Title: WAF regional web ACL should have at least one rule or rule group attached \ No newline at end of file diff --git a/compliance/controls/aws/aws_waf_rule_condition_attached.yaml b/compliance/controls/aws/aws_waf_rule_condition_attached.yaml old mode 100755 new mode 100644 index 85a2a8556..e68f29584 --- a/compliance/controls/aws/aws_waf_rule_condition_attached.yaml +++ b/compliance/controls/aws/aws_waf_rule_condition_attached.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether an AWS WAF global rule contains any conditions. The control fails if no conditions are present within a rule. ID: aws_waf_rule_condition_attached -Title: "WAF global rule should have at least one condition" -Description: "This control checks whether an AWS WAF global rule contains any conditions. The control fails if no conditions are present within a rule." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n rule_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when predicates is null or jsonb_array_length(predicates) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when predicates is null or jsonb_array_length(predicates) = 0 then title || ' has no attached conditions.'\n else title || ' has ' || jsonb_array_length(predicates) || ' attached conditions.'\n end as reason\n \n , region, account_id\nfrom\n aws_waf_rule;\n" - PrimaryTable: aws_waf_rule ListOfTables: - aws_waf_rule Parameters: [] + PrimaryTable: aws_waf_rule + QueryToExecute: | + SELECT + rule_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN predicates IS NULL OR jsonb_array_length(predicates) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN predicates IS NULL OR jsonb_array_length(predicates) = 0 THEN title || ' has no attached conditions.' + ELSE title || ' has ' || jsonb_array_length(predicates) || ' attached conditions.' + END AS reason, + region, + account_id + FROM + aws_waf_rule; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/WAF -IntegrationType: - - aws_cloud_account +Title: WAF global rule should have at least one condition \ No newline at end of file diff --git a/compliance/controls/aws/aws_waf_rule_group_rule_attached.yaml b/compliance/controls/aws/aws_waf_rule_group_rule_attached.yaml old mode 100755 new mode 100644 index 8659b5ad7..89cd759b3 --- a/compliance/controls/aws/aws_waf_rule_group_rule_attached.yaml +++ b/compliance/controls/aws/aws_waf_rule_group_rule_attached.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether WAF global rule group has at least one rule. The control fails if no rules are present within a rule group. ID: aws_waf_rule_group_rule_attached -Title: "WAF global rule group should have at least one rule" -Description: "This control checks whether WAF global rule group has at least one rule. The control fails if no rules are present within a rule group." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when activated_rules is null or jsonb_array_length(activated_rules) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when activated_rules is null or jsonb_array_length(activated_rules) = 0 then title || ' has no attached rules.'\n else title || ' has ' || jsonb_array_length(activated_rules) || ' rule(s) attached.'\n end as reason\n \n , region, account_id\nfrom\n aws_waf_rule_group;\n" - PrimaryTable: aws_waf_rule_group ListOfTables: - aws_waf_rule_group Parameters: [] + PrimaryTable: aws_waf_rule_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN activated_rules IS NULL OR jsonb_array_length(activated_rules) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN activated_rules IS NULL OR jsonb_array_length(activated_rules) = 0 THEN title || ' has no attached rules.' + ELSE title || ' has ' || jsonb_array_length(activated_rules) || ' rule(s) attached.' + END AS reason, + region, + account_id + FROM + aws_waf_rule_group; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/WAF -IntegrationType: - - aws_cloud_account +Title: WAF global rule group should have at least one rule \ No newline at end of file diff --git a/compliance/controls/aws/aws_waf_web_acl_logging_enabled.yaml b/compliance/controls/aws/aws_waf_web_acl_logging_enabled.yaml old mode 100755 new mode 100644 index d5ddab4af..bda041b5f --- a/compliance/controls/aws/aws_waf_web_acl_logging_enabled.yaml +++ b/compliance/controls/aws/aws_waf_web_acl_logging_enabled.yaml @@ -1,13 +1,30 @@ +Description: To help with logging and monitoring within your environment, enable AWS WAF logging on regional and global web ACLs. ID: aws_waf_web_acl_logging_enabled -Title: "WAF web ACL logging should be enabled" -Description: "To help with logging and monitoring within your environment, enable AWS WAF logging on regional and global web ACLs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when logging_configuration is null then 'alarm'\n else 'ok'\n end as status,\n case\n when logging_configuration is null then title || ' logging disabled.'\n else title || ' logging enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_waf_web_acl;\n" - PrimaryTable: aws_waf_web_acl ListOfTables: - aws_waf_web_acl Parameters: [] + PrimaryTable: aws_waf_web_acl + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logging_configuration IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN logging_configuration IS NULL THEN title || ' logging disabled.' + ELSE title || ' logging enabled.' + END AS reason, + region, + account_id + FROM + aws_waf_web_acl; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/WAF -IntegrationType: - - aws_cloud_account +Title: WAF web ACL logging should be enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_waf_web_acl_resource_associated.yaml b/compliance/controls/aws/aws_waf_web_acl_resource_associated.yaml old mode 100755 new mode 100644 index 5ab8b35a9..bb985039e --- a/compliance/controls/aws/aws_waf_web_acl_resource_associated.yaml +++ b/compliance/controls/aws/aws_waf_web_acl_resource_associated.yaml @@ -1,13 +1,30 @@ +Description: This control checks if the web ACL is associated with an Application Load Balancer, API Gateway stage, or CloudFront distributions. ID: aws_waf_web_acl_resource_associated -Title: "WAF web ACL should be associated with an Application Load Balancer, API Gateway stage, or CloudFront distributions" -Description: "This control checks if the web ACL is associated with an Application Load Balancer, API Gateway stage, or CloudFront distributions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when jsonb_array_length(resources) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when jsonb_array_length(resources) > 0 then title || ' associated with ' || jsonb_array_length(resources) || ' AWS resource(s).'\n else title || ' not assoicated with AWS resource.'\n end as reason\n \n , region, account_id\nfrom\n aws_wafregional_web_acl;\n" - PrimaryTable: aws_wafregional_web_acl ListOfTables: - aws_wafregional_web_acl Parameters: [] + PrimaryTable: aws_wafregional_web_acl + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(resources) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(resources) > 0 THEN title || ' associated with ' || jsonb_array_length(resources) || ' AWS resource(s).' + ELSE title || ' not associated with AWS resource.' + END AS reason, + region, + account_id + FROM + aws_wafregional_web_acl; Severity: medium Tags: category: @@ -20,5 +37,4 @@ Tags: - aws service: - AWS/WAF -IntegrationType: - - aws_cloud_account +Title: WAF web ACL should be associated with an Application Load Balancer, API Gateway stage, or CloudFront distributions \ No newline at end of file diff --git a/compliance/controls/aws/aws_waf_web_acl_rule_attached.yaml b/compliance/controls/aws/aws_waf_web_acl_rule_attached.yaml old mode 100755 new mode 100644 index 27945655f..1d417b252 --- a/compliance/controls/aws/aws_waf_web_acl_rule_attached.yaml +++ b/compliance/controls/aws/aws_waf_web_acl_rule_attached.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether WAF global web ACL contains at least one WAF rule or WAF rule group. The control fails if a web ACL does not contain any WAF rules or rule groups. ID: aws_waf_web_acl_rule_attached -Title: "WAF global web ACL should have at least one rule or rule group" -Description: "This control checks whether WAF global web ACL contains at least one WAF rule or WAF rule group. The control fails if a web ACL does not contain any WAF rules or rule groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when rules is null or jsonb_array_length(rules) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when rules is null or jsonb_array_length(rules) = 0 then title || ' has no attached rules.'\n else title || ' has ' || jsonb_array_length(rules) || ' rule(s) attached.'\n end as reason\n \n , region, account_id\nfrom\n aws_waf_web_acl;\n" - PrimaryTable: aws_waf_web_acl ListOfTables: - aws_waf_web_acl Parameters: [] + PrimaryTable: aws_waf_web_acl + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN title || ' has no attached rules.' + ELSE title || ' has ' || jsonb_array_length(rules) || ' rule(s) attached.' + END AS reason, + region, + account_id + FROM + aws_waf_web_acl; Severity: medium Tags: aws_foundational_security: @@ -22,5 +39,4 @@ Tags: - aws service: - AWS/WAF -IntegrationType: - - aws_cloud_account +Title: WAF global web ACL should have at least one rule or rule group \ No newline at end of file diff --git a/compliance/controls/aws/aws_wafv2_rule_group_logging_enabled.yaml b/compliance/controls/aws/aws_wafv2_rule_group_logging_enabled.yaml old mode 100755 new mode 100644 index 0814a1cdb..e01cd0276 --- a/compliance/controls/aws/aws_wafv2_rule_group_logging_enabled.yaml +++ b/compliance/controls/aws/aws_wafv2_rule_group_logging_enabled.yaml @@ -1,28 +1,28 @@ +Description: This control checks whether an AWS WAF rule or rule group has Amazon CloudWatch metrics enabled. The control fails if the rule or rule group doesn't have CloudWatch metrics enabled. ID: aws_wafv2_rule_group_logging_enabled -Title: "AWS WAF rules should have CloudWatch metrics enabled" -Description: "This control checks whether an AWS WAF rule or rule group has Amazon CloudWatch metrics enabled. The control fails if the rule or rule group doesn't have CloudWatch metrics enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - arn as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when (visibility_config ->> 'CloudWatchMetricsEnabled')::bool then 'ok' - else 'alarm' - end as status, - case - when (visibility_config ->> 'CloudWatchMetricsEnabled')::bool then title || ' logging enabled.' - else title || ' logging disabled.' - end as reason - from - aws_wafv2_rule_group; - PrimaryTable: aws_wafv2_rule_group ListOfTables: - aws_wafv2_rule_group Parameters: [] + PrimaryTable: aws_wafv2_rule_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN (visibility_config ->> 'CloudWatchMetricsEnabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (visibility_config ->> 'CloudWatchMetricsEnabled')::bool THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason + FROM + aws_wafv2_rule_group; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: AWS WAF rules should have CloudWatch metrics enabled \ No newline at end of file diff --git a/compliance/controls/aws/aws_wafv2_web_acl_logging_enabled.yaml b/compliance/controls/aws/aws_wafv2_web_acl_logging_enabled.yaml old mode 100755 new mode 100644 index 1320cda45..28e0cfa9e --- a/compliance/controls/aws/aws_wafv2_web_acl_logging_enabled.yaml +++ b/compliance/controls/aws/aws_wafv2_web_acl_logging_enabled.yaml @@ -1,13 +1,30 @@ +Description: To help with logging and monitoring within your environment, enable AWS WAF (V2) logging on regional and global web ACLs. ID: aws_wafv2_web_acl_logging_enabled -Title: "Logging should be enabled on AWS WAFv2 regional and global web access control list (ACLs)" -Description: "To help with logging and monitoring within your environment, enable AWS WAF (V2) logging on regional and global web ACLs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when logging_configuration is null then 'alarm'\n else 'ok'\n end as status,\n case\n when logging_configuration is null then title || ' logging disabled.'\n else title || ' logging enabled.'\n end as reason\n \n , region, account_id\nfrom\n aws_wafv2_web_acl;\n" - PrimaryTable: aws_wafv2_web_acl ListOfTables: - aws_wafv2_web_acl Parameters: [] + PrimaryTable: aws_wafv2_web_acl + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN logging_configuration IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN logging_configuration IS NULL THEN title || ' logging disabled.' + ELSE title || ' logging enabled.' + END AS reason, + region, + account_id + FROM + aws_wafv2_web_acl; Severity: medium Tags: category: @@ -30,12 +47,12 @@ Tags: - "true" hipaa_security_rule_2003: - "true" - nist_800_171_rev_2: - - "true" nist_800_53_rev_4: - "true" nist_800_53_rev_5: - "true" + nist_800_171_rev_2: + - "true" nist_csf: - "true" pci_dss_v321: @@ -48,5 +65,4 @@ Tags: - AWS/WAFv2 soc_2: - "true" -IntegrationType: - - aws_cloud_account +Title: Logging should be enabled on AWS WAFv2 regional and global web access control list (ACLs) \ No newline at end of file diff --git a/compliance/controls/aws/aws_wafv2_web_acl_rule_attached.yaml b/compliance/controls/aws/aws_wafv2_web_acl_rule_attached.yaml old mode 100755 new mode 100644 index f41033713..0924cf3a4 --- a/compliance/controls/aws/aws_wafv2_web_acl_rule_attached.yaml +++ b/compliance/controls/aws/aws_wafv2_web_acl_rule_attached.yaml @@ -1,13 +1,45 @@ +Description: This control checks whether a WAFV2 web access control list (web ACL) contains at least one WAF rule or WAF rule group. The control fails if a web ACL does not contain any WAF rules or rule groups. ID: aws_wafv2_web_acl_rule_attached -Title: "A WAFV2 web ACL should have at least one rule or rule group" -Description: "This control checks whether a WAFV2 web access control list (web ACL) contains at least one WAF rule or WAF rule group. The control fails if a web ACL does not contain any WAF rules or rule groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with rule_group_count as (\n select\n arn,\n count(*) as rule_group_count\n from\n aws_wafv2_web_acl,\n jsonb_array_elements(rules) as r\n where\n r -> 'Statement' -> 'RuleGroupReferenceStatement' ->> 'ARN' is not null\n group by\n arn\n)\nselect\n a.arn as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when rules is null or jsonb_array_length(rules) = 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when rules is null or jsonb_array_length(rules) = 0 then title || ' has no attached rules.'\n else title || ' has ' || c.rule_group_count || ' rule group(s) and ' || (jsonb_array_length(rules) - c.rule_group_count) || ' rule(s) attached.'\n end as reason\n \n , region, account_id\nfrom\n aws_wafv2_web_acl as a\n left join rule_group_count as c on c.arn = a.arn;\n" - PrimaryTable: aws_wafv2_web_acl ListOfTables: - aws_wafv2_web_acl Parameters: [] + PrimaryTable: aws_wafv2_web_acl + QueryToExecute: | + WITH rule_group_count AS ( + SELECT + arn, + COUNT(*) AS rule_group_count + FROM + aws_wafv2_web_acl, + jsonb_array_elements(rules) AS r + WHERE + r -> 'Statement' -> 'RuleGroupReferenceStatement' ->> 'ARN' IS NOT NULL + GROUP BY + arn + ) + SELECT + a.arn AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN rules IS NULL OR jsonb_array_length(rules) = 0 THEN title || ' has no attached rules.' + ELSE title || ' has ' || c.rule_group_count || ' rule group(s) and ' || (jsonb_array_length(rules) - c.rule_group_count) || ' rule(s) attached.' + END AS reason, + region, + account_id + FROM + aws_wafv2_web_acl AS a + LEFT JOIN rule_group_count AS c + ON + c.arn = a.arn; Severity: medium Tags: aws_foundational_security: @@ -22,5 +54,4 @@ Tags: - aws service: - AWS/WAF -IntegrationType: - - aws_cloud_account +Title: A WAFV2 web ACL should have at least one rule or rule group \ No newline at end of file diff --git a/compliance/controls/aws/aws_workspaces_workspace_volume_encryption_enabled.yaml b/compliance/controls/aws/aws_workspaces_workspace_volume_encryption_enabled.yaml old mode 100755 new mode 100644 index 3736a6d4f..b7deaaecb --- a/compliance/controls/aws/aws_workspaces_workspace_volume_encryption_enabled.yaml +++ b/compliance/controls/aws/aws_workspaces_workspace_volume_encryption_enabled.yaml @@ -1,14 +1,33 @@ +Description: To help protect data at rest, ensure encryption is enabled for your WorkSpaces root and user volumes. ID: aws_workspaces_workspace_volume_encryption_enabled -Title: "WorkSpaces root and user volume encryption should be enabled" -Description: "To help protect data at rest, ensure encryption is enabled for your WorkSpaces root and user volumes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when user_volume_encryption_enabled and root_volume_encryption_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when user_volume_encryption_enabled and root_volume_encryption_enabled then title || ' user and root volume encryption enabled.'\n else\n case\n when not user_volume_encryption_enabled and not root_volume_encryption_enabled then title || ' user and root volume encryption disabled.'\n when not root_volume_encryption_enabled then title || ' root volume encryption disabled.'\n else title || ' user volume encryption disabled.'\n end\n end as reason\n \n \nfrom\n aws_workspaces_workspace;" - PrimaryTable: aws_workspaces_workspace ListOfTables: - aws_workspaces_workspace Parameters: [] + PrimaryTable: aws_workspaces_workspace + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN user_volume_encryption_enabled AND root_volume_encryption_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN user_volume_encryption_enabled AND root_volume_encryption_enabled THEN title || ' user and root volume encryption enabled.' + ELSE + CASE + WHEN NOT user_volume_encryption_enabled AND NOT root_volume_encryption_enabled THEN title || ' user and root volume encryption disabled.' + WHEN NOT root_volume_encryption_enabled THEN title || ' root volume encryption disabled.' + ELSE title || ' user volume encryption disabled.' + END + END AS reason + FROM + aws_workspaces_workspace; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: WorkSpaces root and user volume encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_ad_guest_user_reviewed_monthly.yaml b/compliance/controls/azure/azure_ad_guest_user_reviewed_monthly.yaml old mode 100755 new mode 100644 index 9fb0a1f43..5fc2607c4 --- a/compliance/controls/azure/azure_ad_guest_user_reviewed_monthly.yaml +++ b/compliance/controls/azure/azure_ad_guest_user_reviewed_monthly.yaml @@ -1,14 +1,35 @@ +Description: Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Guest users should be review on a monthly basis to ensure that inactive and unneeded accounts are removed. ID: azure_ad_guest_user_reviewed_monthly -Title: "Ensure guest users are reviewed on a monthly basis" -Description: "Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Guest users should be review on a monthly basis to ensure that inactive and unneeded accounts are removed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n u.display_name as resource,\n u.og_account_id as og_account_id,\n u.og_resource_id as og_resource_id,\n case\n when not account_enabled then 'alarm'\n when u.created_date_time::timestamp <= (current_date - interval '30' day) then 'alarm'\n else 'ok'\n end as status,\n case\n when not account_enabled then 'Guest user ''' || u.display_name || ''' inactive.'\n else 'Guest user ''' || u.display_name || ''' was created ' || extract(day from current_timestamp - u.created_date_time::timestamp) || ' days ago.'\n end as reason,\n t.tenant_id\n \nfrom\n azuread_user as u\n left join azure_tenant as t on t.tenant_id = u.tenant_id\nwhere\n u.user_type = 'Guest';\n" - PrimaryTable: azuread_user ListOfTables: - azure_tenant - azuread_user Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + SELECT + u.display_name AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN NOT account_enabled THEN 'alarm' + WHEN u.created_date_time::timestamp <= (current_date - interval '30' day) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT account_enabled THEN 'Guest user ''' || u.display_name || ''' inactive.' + ELSE 'Guest user ''' || u.display_name || ''' was created ' || EXTRACT(day FROM current_timestamp - u.created_date_time::timestamp) || ' days ago.' + END AS reason, + t.tenant_id + FROM + azuread_user AS u + LEFT JOIN + azure_tenant AS t ON t.tenant_id = u.tenant_id + WHERE + u.user_type = 'Guest'; Severity: medium Tags: category: @@ -29,5 +50,4 @@ Tags: - azure service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Ensure guest users are reviewed on a monthly basis \ No newline at end of file diff --git a/compliance/controls/azure/azure_apimanagement_service_client_certificate_enabled.yaml b/compliance/controls/azure/azure_apimanagement_service_client_certificate_enabled.yaml old mode 100755 new mode 100644 index 756bacf09..8e24ed43e --- a/compliance/controls/azure/azure_apimanagement_service_client_certificate_enabled.yaml +++ b/compliance/controls/azure/azure_apimanagement_service_client_certificate_enabled.yaml @@ -1,30 +1,30 @@ +Description: Ensure API Management client certificate is enabled. This control is non-compliant if API Management client certificate is disabled. ID: azure_apimanagement_service_client_certificate_enabled -Title: "API Management client certificate should be enabled" -Description: "Ensure API Management client certificate is enabled. This control is non-compliant if API Management client certificate is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when enable_client_certificate then 'ok' - else 'alarm' - end as status, - case - when enable_client_certificate then a.name || ' client certificate enabled.' - else a.name || ' client certificate disabled.' - end as reason - from - azure_api_management a, - azure_subscription sub; - PrimaryTable: azure_api_management ListOfTables: - azure_api_management - azure_subscription Parameters: [] + PrimaryTable: azure_api_management + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN enable_client_certificate THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_client_certificate THEN a.name || ' client certificate enabled.' + ELSE a.name || ' client certificate disabled.' + END AS reason + FROM + azure_api_management a, + azure_subscription sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: API Management client certificate should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_apimanagement_service_with_virtual_network.yaml b/compliance/controls/azure/azure_apimanagement_service_with_virtual_network.yaml old mode 100755 new mode 100644 index 9d4182215..6cdcd5bb1 --- a/compliance/controls/azure/azure_apimanagement_service_with_virtual_network.yaml +++ b/compliance/controls/azure/azure_apimanagement_service_with_virtual_network.yaml @@ -1,19 +1,33 @@ +Description: Azure Virtual Network deployment provides enhanced security, isolation and allows you to place your API Management service in a non-internet routable network that you control access to. These networks can then be connected to your on-premises networks using various VPN technologies, which enables access to your backend services within the network and/or on-premises. The developer portal and API gateway, can be configured to be accessible either from the Internet or only within the virtual network. ID: azure_apimanagement_service_with_virtual_network -Title: "API Management services should use a virtual network" -Description: "Azure Virtual Network deployment provides enhanced security, isolation and allows you to place your API Management service in a non-internet routable network that you control access to. These networks can then be connected to your on-premises networks using various VPN technologies, which enables access to your backend services within the network and/or on-premises. The developer portal and API gateway, can be configured to be accessible either from the Internet or only within the virtual network." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when virtual_network_type != 'None' then 'ok'\n else 'alarm'\n end as status,\n a.name || ' Virtual network is set to ' || virtual_network_type as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_api_management a,\n azure_subscription sub;\n" - PrimaryTable: azure_api_management ListOfTables: - azure_api_management - azure_subscription Parameters: [] + PrimaryTable: azure_api_management + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN virtual_network_type != 'None' THEN 'ok' + ELSE 'alarm' + END AS status, + a.name || ' Virtual network is set to ' || virtual_network_type AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_api_management a, + azure_subscription sub; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/APIManagement -IntegrationType: - - azure_subscription +Title: API Management services should use a virtual network \ No newline at end of file diff --git a/compliance/controls/azure/azure_app_configuration_encryption_enabled.yaml b/compliance/controls/azure/azure_app_configuration_encryption_enabled.yaml old mode 100755 new mode 100644 index a2b333354..ef9f5d49c --- a/compliance/controls/azure/azure_app_configuration_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_app_configuration_encryption_enabled.yaml @@ -1,30 +1,30 @@ +Description: Enabling App Configuration encryption helps protect and safeguard your data to meet your organizational security and compliance commitments. ID: azure_app_configuration_encryption_enabled -Title: "App Configuration encryption should be enabled" -Description: "Enabling App Configuration encryption helps protect and safeguard your data to meet your organizational security and compliance commitments." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when encryption -> 'keyVaultProperties' ->> 'keyIdentifier' is not null then 'ok' - else 'alarm' - end as status, - case - when encryption -> 'keyVaultProperties' ->> 'keyIdentifier' is not null then a.name || 'encryption enabled.' - else a.name || ' encryption disabled.' - end as reason - from - azure_app_configuration as a, - azure_subscription as sub; - PrimaryTable: azure_app_configuration ListOfTables: - azure_app_configuration - azure_subscription Parameters: [] + PrimaryTable: azure_app_configuration + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN encryption -> 'keyVaultProperties' ->> 'keyIdentifier' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption -> 'keyVaultProperties' ->> 'keyIdentifier' IS NOT NULL THEN a.name || ' encryption enabled.' + ELSE a.name || ' encryption disabled.' + END AS reason + FROM + azure_app_configuration AS a, + azure_subscription AS sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: App Configuration encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_app_configuration_private_link_used.yaml b/compliance/controls/azure/azure_app_configuration_private_link_used.yaml old mode 100755 new mode 100644 index 7ce176e27..138d6e8ed --- a/compliance/controls/azure/azure_app_configuration_private_link_used.yaml +++ b/compliance/controls/azure/azure_app_configuration_private_link_used.yaml @@ -1,19 +1,40 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your app configuration instances instead of the entire service, you'll also be protected against data leakage risks. ID: azure_app_configuration_private_link_used -Title: "App Configuration should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your app configuration instances instead of the entire service, you'll also be protected against data leakage risks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n -- Only applicable to standard tier\n when sku_name = 'free' then 'skip'\n -- All networks, including the internet and private endpoints, can access this resource\n -- Checking if all network enabled and no private endpoint then it's public access\n when public_network_access = 'Enabled' and private_endpoint_connections is null then 'alarm'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then 'ok'\n else 'alarm'\n end as status,\n case\n when sku_name = 'free' then a.name || ' is of ' || sku_name || ' tier.'\n when public_network_access = 'Enabled' and private_endpoint_connections is null then ' using public networks.'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then a.name || ' using private link.'\n else a.name || ' not using private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_configuration as a,\n azure_subscription as sub;\n" - PrimaryTable: azure_app_configuration ListOfTables: - azure_app_configuration - azure_subscription Parameters: [] + PrimaryTable: azure_app_configuration + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_name = 'free' THEN 'skip' + WHEN public_network_access = 'Enabled' AND private_endpoint_connections IS NULL THEN 'alarm' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_name = 'free' THEN a.name || ' is of ' || sku_name || ' tier.' + WHEN public_network_access = 'Enabled' AND private_endpoint_connections IS NULL THEN ' using public networks.' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN a.name || ' using private link.' + ELSE a.name || ' not using private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_configuration AS a, + azure_subscription AS sub; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppConfiguration -IntegrationType: - - azure_subscription +Title: App Configuration should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_app_configuration_sku_standard.yaml b/compliance/controls/azure/azure_app_configuration_sku_standard.yaml old mode 100755 new mode 100644 index d026378a9..bf432d430 --- a/compliance/controls/azure/azure_app_configuration_sku_standard.yaml +++ b/compliance/controls/azure/azure_app_configuration_sku_standard.yaml @@ -1,27 +1,27 @@ +Description: Ensure that App Configuration uses standard SKU tier. This control is non-compliant if App Configuration does not use standard SKU. ID: azure_app_configuration_sku_standard -Title: "App Configuration should use standard SKU" -Description: "Ensure that App Configuration uses standard SKU tier. This control is non-compliant if App Configuration does not use standard SKU." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when sku_name = 'standard' then 'ok' - else 'alarm' - end as status, - a.name || ' has ' || sku_name || ' SKU tier.' as reason - from - azure_app_configuration as a, - azure_subscription as sub; - PrimaryTable: azure_app_configuration ListOfTables: - azure_app_configuration - azure_subscription Parameters: [] + PrimaryTable: azure_app_configuration + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_name = 'standard' THEN 'ok' + ELSE 'alarm' + END AS status, + a.name || ' has ' || sku_name || ' SKU tier.' AS reason + FROM + azure_app_configuration AS a, + azure_subscription AS sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: App Configuration should use standard SKU \ No newline at end of file diff --git a/compliance/controls/azure/azure_app_service_environment_internal_encryption_enabled.yaml b/compliance/controls/azure/azure_app_service_environment_internal_encryption_enabled.yaml old mode 100755 new mode 100644 index 764278bfc..1abfaf1c1 --- a/compliance/controls/azure/azure_app_service_environment_internal_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_app_service_environment_internal_encryption_enabled.yaml @@ -1,19 +1,49 @@ +Description: Setting InternalEncryption to true encrypts the pagefile, worker disks, and internal network traffic between the front ends and workers in an App Service Environment. ID: azure_app_service_environment_internal_encryption_enabled -Title: "App Service Environment should enable internal encryption" -Description: "Setting InternalEncryption to true encrypts the pagefile, worker disks, and internal network traffic between the front ends and workers in an App Service Environment." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with app_service_environment as (\n select\n distinct id as id\n from\n azure_app_service_environment,\n jsonb_array_elements(cluster_settings ) as s\n where\n s ->> 'name' = 'InternalEncryption'\n and s ->> 'value' = 'true'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is not null then a.title || ' internal encryption enabled.'\n else a.name || ' internal encryption disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_environment as a\n left join app_service_environment as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_environment ListOfTables: - azure_app_service_environment - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_environment + QueryToExecute: | + WITH app_service_environment AS ( + SELECT + DISTINCT id AS id + FROM + azure_app_service_environment, + jsonb_array_elements(cluster_settings) AS s + WHERE + s ->> 'name' = 'InternalEncryption' + AND s ->> 'value' = 'true' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NOT NULL THEN a.title || ' internal encryption enabled.' + ELSE a.name || ' internal encryption disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_environment AS a + LEFT JOIN app_service_environment AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service Environment should enable internal encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_application_gateway_waf_enabled.yaml b/compliance/controls/azure/azure_application_gateway_waf_enabled.yaml old mode 100755 new mode 100644 index e69f0b6d6..b7c0283ca --- a/compliance/controls/azure/azure_application_gateway_waf_enabled.yaml +++ b/compliance/controls/azure/azure_application_gateway_waf_enabled.yaml @@ -1,19 +1,39 @@ +Description: Deploy Azure Web Application Firewall (WAF) in front of public facing web applications for additional inspection of incoming traffic. Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities such as SQL injections, Cross-Site Scripting, local and remote file executions. You can also restrict access to your web applications by countries, IP address ranges, and other http(s) parameters via custom rules. ID: azure_application_gateway_waf_enabled -Title: "Web Application Firewall (WAF) should be enabled for Application Gateway" -Description: "Deploy Azure Web Application Firewall (WAF) in front of public facing web applications for additional inspection of incoming traffic. Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities such as SQL injections, Cross-Site Scripting, local and remote file executions. You can also restrict access to your web applications by countries, IP address ranges, and other http(s) parameters via custom rules." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n ag.id resource,\n ag.og_account_id as og_account_id,\n ag.og_resource_id as og_resource_id,\n case\n when web_application_firewall_configuration is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when web_application_firewall_configuration is not null then ag.name || ' WAF enabled.'\n else ag.name || ' WAF disabled.'\n end as reason\n \n , ag.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_application_gateway as ag\n join azure_subscription as sub on sub.subscription_id = ag.subscription_id;\n" - PrimaryTable: azure_application_gateway ListOfTables: - azure_application_gateway - azure_subscription Parameters: [] + PrimaryTable: azure_application_gateway + QueryToExecute: | + SELECT + ag.id AS resource, + ag.og_account_id AS og_account_id, + ag.og_resource_id AS og_resource_id, + CASE + WHEN web_application_firewall_configuration IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN web_application_firewall_configuration IS NOT NULL THEN ag.name || ' WAF enabled.' + ELSE ag.name || ' WAF disabled.' + END AS reason, + ag.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_application_gateway AS ag + JOIN + azure_subscription AS sub + ON + sub.subscription_id = ag.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Web Application Firewall (WAF) should be enabled for Application Gateway \ No newline at end of file diff --git a/compliance/controls/azure/azure_application_gateway_waf_uses_specified_mode.yaml b/compliance/controls/azure/azure_application_gateway_waf_uses_specified_mode.yaml old mode 100755 new mode 100644 index 97026cf71..2f574daeb --- a/compliance/controls/azure/azure_application_gateway_waf_uses_specified_mode.yaml +++ b/compliance/controls/azure/azure_application_gateway_waf_uses_specified_mode.yaml @@ -1,15 +1,32 @@ +Description: Mandates the use of 'Detection' or 'Prevention' mode to be active on all Web Application Firewall policies for Application Gateway. ID: azure_application_gateway_waf_uses_specified_mode -Title: "Web Application Firewall (WAF) should use the specified mode for Application Gateway" -Description: "Mandates the use of 'Detection' or 'Prevention' mode to be active on all Web Application Firewall policies for Application Gateway." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n ag.id as resource,\n ag.og_account_id as og_account_id,\n ag.og_resource_id as og_resource_id,\n case\n when (web_application_firewall_configuration::json -> 'PolicySettings' ->> 'mode') in ('Prevention','Detection') then 'ok'\n else 'alarm'\n end as status,\n case\n when (web_application_firewall_configuration::json -> 'PolicySettings' ->> 'mode') in ('Prevention','Detection') then ag.name || ' WAF mode is set to ' || (web_application_firewall_configuration::json -> 'PolicySettings' ->> 'mode') || '.'\n else ag.name || ' WAF mode is not set to Prevention or Detection mode.' \n end as reason\nfrom\n azure_application_gateway as ag\n join azure_subscription as sub on sub.subscription_id = ag.subscription_id;" - PrimaryTable: azure_application_gateway ListOfTables: - azure_application_gateway - azure_subscription Parameters: [] + PrimaryTable: azure_application_gateway + QueryToExecute: | + SELECT + ag.id AS resource, + ag.og_account_id AS og_account_id, + ag.og_resource_id AS og_resource_id, + CASE + WHEN (web_application_firewall_configuration::json -> 'PolicySettings' ->> 'mode') IN ('Prevention', 'Detection') THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (web_application_firewall_configuration::json -> 'PolicySettings' ->> 'mode') IN ('Prevention', 'Detection') THEN ag.name || ' WAF mode is set to ' || (web_application_firewall_configuration::json -> 'PolicySettings' ->> 'mode') || '.' + ELSE ag.name || ' WAF mode is not set to Prevention or Detection mode.' + END AS reason + FROM + azure_application_gateway AS ag + JOIN + azure_subscription AS sub + ON sub.subscription_id = ag.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Web Application Firewall (WAF) should use the specified mode for Application Gateway \ No newline at end of file diff --git a/compliance/controls/azure/azure_application_insights_block_log_ingestion_and_querying_from_public.yaml b/compliance/controls/azure/azure_application_insights_block_log_ingestion_and_querying_from_public.yaml old mode 100755 new mode 100644 index 71ae429d8..2174f3c97 --- a/compliance/controls/azure/azure_application_insights_block_log_ingestion_and_querying_from_public.yaml +++ b/compliance/controls/azure/azure_application_insights_block_log_ingestion_and_querying_from_public.yaml @@ -1,30 +1,34 @@ +Description: Improve Application Insights security by blocking log ingestion and querying from public networks. Only private-link connected networks will be able to ingest and query logs of this component. Learn more at https://aka.ms/AzMonPrivateLink#configure-application-insights. ID: azure_application_insights_block_log_ingestion_and_querying_from_public -Title: "Application Insights components should block log ingestion and querying from public networks" -Description: "Improve Application Insights security by blocking log ingestion and querying from public networks. Only private-link connected networks will be able to ingest and query logs of this component. Learn more at https://aka.ms/AzMonPrivateLink#configure-application-insights." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when type = 'microsoft.insights/components' and public_network_access_for_ingestion = 'Enabled' and public_network_access_for_query = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when type = 'microsoft.insights/components' and public_network_access_for_ingestion = 'Enabled' and public_network_access_for_query = 'Enabled' then a.name || ' allows log ingestion and querying from public network.' - else a.name || ' does not allow log ingestion and querying from public network.' - end as reason - from - azure_application_insight as a - left join azure_subscription sub on sub.subscription_id = a.subscription_id; - PrimaryTable: azure_application_insight ListOfTables: - azure_application_insight - azure_subscription Parameters: [] + PrimaryTable: azure_application_insight + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN type = 'microsoft.insights/components' + AND public_network_access_for_ingestion = 'Enabled' + AND public_network_access_for_query = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN type = 'microsoft.insights/components' + AND public_network_access_for_ingestion = 'Enabled' + AND public_network_access_for_query = 'Enabled' THEN a.name || ' allows log ingestion and querying from public network.' + ELSE a.name || ' does not allow log ingestion and querying from public network.' + END AS reason + FROM + azure_application_insight AS a + LEFT JOIN azure_subscription sub ON sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Application Insights components should block log ingestion and querying from public networks \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_api_app_client_certificates_on.yaml b/compliance/controls/azure/azure_appservice_api_app_client_certificates_on.yaml old mode 100755 new mode 100644 index 8202c35b9..70a86b4d6 --- a/compliance/controls/azure/azure_appservice_api_app_client_certificates_on.yaml +++ b/compliance/controls/azure/azure_appservice_api_app_client_certificates_on.yaml @@ -1,14 +1,51 @@ +Description: Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app. ID: azure_appservice_api_app_client_certificates_on -Title: "App Service apps should have Client Certificates (Incoming client certificates) enabled" -Description: "Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_api_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like '%api'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when client_cert_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when client_cert_enabled then a.name || ' client certificate enabled.'\n else a.name || ' client certificate disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_api_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_api_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE '%api' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN client_cert_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN client_cert_enabled THEN a.name || ' client certificate enabled.' + ELSE a.name || ' client certificate disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_api_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +54,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service apps should have Client Certificates (Incoming client certificates) enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_api_app_cors_no_star.yaml b/compliance/controls/azure/azure_appservice_api_app_cors_no_star.yaml old mode 100755 new mode 100644 index 32d05603a..8e3286cc0 --- a/compliance/controls/azure/azure_appservice_api_app_cors_no_star.yaml +++ b/compliance/controls/azure/azure_appservice_api_app_cors_no_star.yaml @@ -1,14 +1,51 @@ +Description: Cross-Origin Resource Sharing (CORS) should not allow all domains to access your app. Allow only required domains to interact with your app. ID: azure_appservice_api_app_cors_no_star -Title: "App Service apps should not have CORS configured to allow every resource to access your apps" -Description: "Cross-Origin Resource Sharing (CORS) should not allow all domains to access your app. Allow only required domains to interact with your app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_api_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like '%api'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '[\"*\"]' then 'alarm'\n else 'ok'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '[\"*\"]' then a.name || ' CORS allow all domains to access the application.'\n else a.name || ' CORS does not all domains to access the application.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_api_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_api_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE '%api' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '[\"*\"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '[\"*\"]' THEN a.name || ' CORS allow all domains to access the application.' + ELSE a.name || ' CORS does not allow all domains to access the application.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_api_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: hipaa_hitrust_v92: @@ -17,5 +54,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service apps should not have CORS configured to allow every resource to access your apps \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_api_app_ftps_enabled.yaml b/compliance/controls/azure/azure_appservice_api_app_ftps_enabled.yaml old mode 100755 new mode 100644 index 31d2376f3..8afc9d3c2 --- a/compliance/controls/azure/azure_appservice_api_app_ftps_enabled.yaml +++ b/compliance/controls/azure/azure_appservice_api_app_ftps_enabled.yaml @@ -1,19 +1,56 @@ +Description: Enable FTPS enforcement for enhanced security. ID: azure_appservice_api_app_ftps_enabled -Title: "FTPS only should be required in your API App" -Description: "Enable FTPS enforcement for enhanced security." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_api_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like '%api'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then a.name || ' FTPS disabled.'\n else a.name || ' FTPS enabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_api_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_api_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE '%api' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN a.name || ' FTPS disabled.' + ELSE a.name || ' FTPS enabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_api_app AS b + ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: FTPS only should be required in your API App \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_api_app_latest_tls_version.yaml b/compliance/controls/azure/azure_appservice_api_app_latest_tls_version.yaml old mode 100755 new mode 100644 index 9e5997fcc..957bcf163 --- a/compliance/controls/azure/azure_appservice_api_app_latest_tls_version.yaml +++ b/compliance/controls/azure/azure_appservice_api_app_latest_tls_version.yaml @@ -1,14 +1,53 @@ +Description: Periodically, newer versions are released for TLS either due to security flaws, include + additional functionality, and enhance speed. Upgrade to the latest TLS version for App Service apps + to take advantage of security fixes, if any, and/or new functionalities of the latest version. ID: azure_appservice_api_app_latest_tls_version -Title: "App Service apps should use the latest TLS version" -Description: "Periodically, newer versions are released for TLS either due to security flaws, include additional functionality, and enhance speed. Upgrade to the latest TLS version for App Service apps to take advantage of security fixes, if any, and/or new functionalities of the latest version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_api_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like '%api'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then 'alarm'\n else 'ok'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then a.name || ' not using the latest version of TLS encryption.'\n else a.name || ' using the latest version of TLS encryption.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_api_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_api_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE '%api' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN a.name || ' not using the latest version of TLS encryption.' + ELSE a.name || ' using the latest version of TLS encryption.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_api_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +56,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service apps should use the latest TLS version \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_api_app_remote_debugging_disabled.yaml b/compliance/controls/azure/azure_appservice_api_app_remote_debugging_disabled.yaml old mode 100755 new mode 100644 index 4cca8a3bb..c968e11b3 --- a/compliance/controls/azure/azure_appservice_api_app_remote_debugging_disabled.yaml +++ b/compliance/controls/azure/azure_appservice_api_app_remote_debugging_disabled.yaml @@ -1,14 +1,36 @@ +Description: Remote debugging requires inbound ports to be opened on an App Service app. Remote debugging should be turned off. ID: azure_appservice_api_app_remote_debugging_disabled -Title: "App Service apps should have remote debugging turned off" -Description: "Remote debugging requires inbound ports to be opened on an App Service app. Remote debugging should be turned off." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when kind <> 'api' then 'skip'\n when configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' then 'ok'\n else 'alarm'\n end as status,\n case\n when kind <> 'api' then name || ' is of ' || kind || ' type.'\n when configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' then name || ' remote debugging disabled.'\n else name || ' remote debugging enabled.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN kind <> 'api' THEN 'skip' + WHEN configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN kind <> 'api' THEN name || ' is of ' || kind || ' type.' + WHEN configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' THEN name || ' remote debugging disabled.' + ELSE name || ' remote debugging enabled.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +39,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service apps should have remote debugging turned off \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_api_app_use_https.yaml b/compliance/controls/azure/azure_appservice_api_app_use_https.yaml old mode 100755 new mode 100644 index 59f3c6246..2e143a160 --- a/compliance/controls/azure/azure_appservice_api_app_use_https.yaml +++ b/compliance/controls/azure/azure_appservice_api_app_use_https.yaml @@ -1,14 +1,51 @@ +Description: Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks. ID: azure_appservice_api_app_use_https -Title: "App Service API apps should only be accessible over HTTPS" -Description: "Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_api_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like '%api'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when not https_only then 'alarm'\n else 'ok'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when not https_only then a.name || ' does not redirect all HTTP traffic to HTTPS.'\n else a.name || ' redirects all HTTP traffic to HTTPS.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_api_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_api_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + unnest(regexp_split_to_array(kind, ',')) elem + WHERE + elem LIKE '%api' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN NOT https_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN NOT https_only THEN a.name || ' does not redirect all HTTP traffic to HTTPS.' + ELSE a.name || ' redirects all HTTP traffic to HTTPS.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_api_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: hipaa_hitrust_v92: @@ -19,5 +56,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service API apps should only be accessible over HTTPS \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_api_app_uses_managed_identity.yaml b/compliance/controls/azure/azure_appservice_api_app_uses_managed_identity.yaml old mode 100755 new mode 100644 index 07e626f76..afa1d30fa --- a/compliance/controls/azure/azure_appservice_api_app_uses_managed_identity.yaml +++ b/compliance/controls/azure/azure_appservice_api_app_uses_managed_identity.yaml @@ -1,14 +1,55 @@ +Description: Use a managed identity for enhanced authentication security. ID: azure_appservice_api_app_uses_managed_identity -Title: "Managed identity should be used in your API App" -Description: "Use a managed identity for enhanced authentication security." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_api_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like '%api'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when\n configuration -> 'properties' ->> 'xManagedServiceIdentityId' is not null\n or configuration -> 'properties' ->> 'managedServiceIdentityId' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when\n configuration -> 'properties' ->> 'xManagedServiceIdentityId' is not null\n or configuration -> 'properties' ->> 'managedServiceIdentityId' is not null\n then a.name || ' uses managed identity.'\n else a.name || ' not uses managed identity'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_api_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_api_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE + elem LIKE '%api' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN + configuration -> 'properties' ->> 'xManagedServiceIdentityId' IS NOT NULL + OR configuration -> 'properties' ->> 'managedServiceIdentityId' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN + configuration -> 'properties' ->> 'xManagedServiceIdentityId' IS NOT NULL + OR configuration -> 'properties' ->> 'managedServiceIdentityId' IS NOT NULL THEN a.name || ' uses managed identity.' + ELSE a.name || ' not uses managed identity' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_api_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +58,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Managed identity should be used in your API App \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_authentication_enabled.yaml b/compliance/controls/azure/azure_appservice_authentication_enabled.yaml old mode 100755 new mode 100644 index 6320923ef..914ae16b1 --- a/compliance/controls/azure/azure_appservice_authentication_enabled.yaml +++ b/compliance/controls/azure/azure_appservice_authentication_enabled.yaml @@ -1,14 +1,34 @@ +Description: Azure App Service authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented. ID: azure_appservice_authentication_enabled -Title: "Ensure App Service authentication is set up for apps in Azure App Service" -Description: "Azure App Service authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then 'alarm'\n else 'ok'\n end as status,\n case\n when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then name || ' authentication not set.'\n else name || ' authentication set.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::boolean THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::boolean THEN name || ' authentication not set.' + ELSE name || ' authentication set.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure App Service authentication is set up for apps in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_ftp_deployment_disabled.yaml b/compliance/controls/azure/azure_appservice_ftp_deployment_disabled.yaml old mode 100755 new mode 100644 index 26eb45e2d..05c79ab7c --- a/compliance/controls/azure/azure_appservice_ftp_deployment_disabled.yaml +++ b/compliance/controls/azure/azure_appservice_ftp_deployment_disabled.yaml @@ -1,15 +1,61 @@ +Description: By default, Azure Functions, Web, and API Services can be deployed over FTP. + If FTP is required for an essential deployment workflow, FTPS should be required + for FTP login for all App Service Apps and Functions. ID: azure_appservice_ftp_deployment_disabled -Title: "Ensure FTP deployments are Disabled" -Description: "By default, Azure Functions, Web, and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n fa.id as resource,\n fa.og_account_id as og_account_id,\n fa.og_resource_id as og_resource_id,\n 'azure_app_service_function_app' as og_table_name,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n , fa.resource_group as resource_group\n , sub.display_name as subscription\n from\n azure_app_service_function_app fa,\n azure_subscription sub\n where\n sub.subscription_id = fa.subscription_id\nunion\n select\n wa.id as resource,\n wa.og_account_id as og_account_id,\n wa.og_resource_id as og_resource_id,\n 'azure_app_service_web_app' as og_table_name,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n , wa.resource_group as resource_group\n , sub.display_name as subscription\n from\n azure_app_service_web_app as wa,\n azure_subscription as sub\n where\n sub.subscription_id = wa.subscription_id;\n" - PrimaryTable: "" ListOfTables: - azure_app_service_function_app - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + fa.id AS resource, + fa.og_account_id AS og_account_id, + fa.og_resource_id AS og_resource_id, + 'azure_app_service_function_app' AS og_table_name, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason, + fa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app fa, + azure_subscription sub + WHERE + sub.subscription_id = fa.subscription_id + + UNION + + SELECT + wa.id AS resource, + wa.og_account_id AS og_account_id, + wa.og_resource_id AS og_resource_id, + 'azure_app_service_web_app' AS og_table_name, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason, + wa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS wa, + azure_subscription AS sub + WHERE + sub.subscription_id = wa.subscription_id; Severity: medium Tags: category: @@ -30,5 +76,4 @@ Tags: - azure service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure FTP deployments are Disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_authentication_on.yaml b/compliance/controls/azure/azure_appservice_function_app_authentication_on.yaml old mode 100755 new mode 100644 index 829a8d962..48367f4d1 --- a/compliance/controls/azure/azure_appservice_function_app_authentication_on.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_authentication_on.yaml @@ -1,32 +1,32 @@ +Description: Azure App Service authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented. ID: azure_appservice_function_app_authentication_on -Title: "Ensure App Service authentication is set up for function apps in Azure App Service" -Description: "Azure App Service authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - fa.id as resource, - fa.og_account_id as og_account_id, - fa.og_resource_id as og_resource_id, - case - when auth_settings -> 'properties' ->> 'enabled' = 'true' then 'ok' - else 'alarm' - end as status, - case - when auth_settings -> 'properties' ->> 'enabled' = 'true' then name || ' authentication enabled.' - else name || ' authentication disabled.' - end as reason - from - azure_app_service_function_app fa, - azure_subscription sub - where - sub.subscription_id = fa.subscription_id; - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + SELECT + fa.id AS resource, + fa.og_account_id AS og_account_id, + fa.og_resource_id AS og_resource_id, + CASE + WHEN auth_settings -> 'properties' ->> 'enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auth_settings -> 'properties' ->> 'enabled' = 'true' THEN name || ' authentication enabled.' + ELSE name || ' authentication disabled.' + END AS reason + FROM + azure_app_service_function_app fa, + azure_subscription sub + WHERE + sub.subscription_id = fa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Ensure App Service authentication is set up for function apps in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_client_certificates_on.yaml b/compliance/controls/azure/azure_appservice_function_app_client_certificates_on.yaml old mode 100755 new mode 100644 index 6e86e8fbe..93e732194 --- a/compliance/controls/azure/azure_appservice_function_app_client_certificates_on.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_client_certificates_on.yaml @@ -1,19 +1,38 @@ +Description: Client certificates allow for the app to request a certificate for incoming requests. Only clients with valid certificates will be able to reach the app. ID: azure_appservice_function_app_client_certificates_on -Title: "Function apps should have 'Client Certificates (Incoming client certificates)' enabled" -Description: "Client certificates allow for the app to request a certificate for incoming requests. Only clients with valid certificates will be able to reach the app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when client_cert_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when client_cert_enabled then app.name || ' client certificate enabled.'\n else app.name || ' client certificate disabled.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_function_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN client_cert_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN client_cert_enabled THEN app.name || ' client certificate enabled.' + ELSE app.name || ' client certificate disabled.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Function apps should have 'Client Certificates (Incoming client certificates)' enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_cors_no_star.yaml b/compliance/controls/azure/azure_appservice_function_app_cors_no_star.yaml old mode 100755 new mode 100644 index 9079a8456..f3ccfce2c --- a/compliance/controls/azure/azure_appservice_function_app_cors_no_star.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_cors_no_star.yaml @@ -1,14 +1,35 @@ +Description: Cross-Origin Resource Sharing (CORS) should not allow all domains to access your Function app. Allow only required domains to interact with your Function app. ID: azure_appservice_function_app_cors_no_star -Title: "Function apps should not have CORS configured to allow every resource to access your apps" -Description: "Cross-Origin Resource Sharing (CORS) should not allow all domains to access your Function app. Allow only required domains to interact with your Function app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n b.id as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '[\"*\"]' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '[\"*\"]'\n then b.name || ' CORS allow all domains to access the application.'\n else b.name || ' CORS does not all domains to access the application.'\n end as reason\n \n , b.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_function_app as b,\n azure_subscription as sub\nwhere\n sub.subscription_id = b.subscription_id;\n" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + SELECT + b.id AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '["*"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '["*"]' + THEN b.name || ' CORS allow all domains to access the application.' + ELSE b.name || ' CORS does not allow all domains to access the application.' + END AS reason, + b.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app AS b, + azure_subscription AS sub + WHERE + sub.subscription_id = b.subscription_id; Severity: high Tags: hipaa_hitrust_v92: @@ -17,5 +38,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Function apps should not have CORS configured to allow every resource to access your apps \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_ftps_enabled.yaml b/compliance/controls/azure/azure_appservice_function_app_ftps_enabled.yaml old mode 100755 new mode 100644 index cd40fddbc..aec545cc4 --- a/compliance/controls/azure/azure_appservice_function_app_ftps_enabled.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_ftps_enabled.yaml @@ -1,19 +1,55 @@ +Description: Enable FTPS enforcement for enhanced security. ID: azure_appservice_function_app_ftps_enabled -Title: "FTPS only should be required in your Function App" -Description: "Enable FTPS enforcement for enhanced security." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_function_app as (\n select\n id\n from\n azure_app_service_function_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'functionapp%'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then a.name || ' FTPS disabled.'\n else a.name || ' FTPS enabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_function_app as a\n left join all_function_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + WITH all_function_app AS ( + SELECT + id + FROM + azure_app_service_function_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE + elem LIKE 'functionapp%' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN a.name || ' FTPS disabled.' + ELSE a.name || ' FTPS enabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app AS a + LEFT JOIN all_function_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: FTPS only should be required in your Function App \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_latest_http_version.yaml b/compliance/controls/azure/azure_appservice_function_app_latest_http_version.yaml old mode 100755 new mode 100644 index 90e775f7f..3c27c4c94 --- a/compliance/controls/azure/azure_appservice_function_app_latest_http_version.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_latest_http_version.yaml @@ -1,19 +1,63 @@ +Description: Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version. Currently, this policy only applies to Linux web apps. ID: azure_appservice_function_app_latest_http_version -Title: "Ensure that 'HTTP Version' is the latest, if used to run the Function app" -Description: "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version. Currently, this policy only applies to Linux web apps." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_function_app as (\n select\n id\n from\n azure_app_service_function_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'functionapp%'\n )\n and\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem = 'linux'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' ->> 'http20Enabled' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is not a linux function app.'\n when configuration -> 'properties' ->> 'http20Enabled' = 'true' then a.name || ' using the latest HTTP version.'\n else a.name || ' not using latest HTTP version.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_function_app as a\n left join all_function_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + WITH all_function_app AS ( + SELECT + id + FROM + azure_app_service_function_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE + elem LIKE 'functionapp%' + ) + AND + EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE + elem = 'linux' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'http20Enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is not a linux function app.' + WHEN configuration -> 'properties' ->> 'http20Enabled' = 'true' THEN a.name || ' using the latest HTTP version.' + ELSE a.name || ' not using latest HTTP version.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app AS a + LEFT JOIN all_function_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure that 'HTTP Version' is the latest, if used to run the Function app \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_latest_java_version.yaml b/compliance/controls/azure/azure_appservice_function_app_latest_java_version.yaml old mode 100755 new mode 100644 index a74aacda3..47b42ca46 --- a/compliance/controls/azure/azure_appservice_function_app_latest_java_version.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_latest_java_version.yaml @@ -1,19 +1,66 @@ +Description: Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for Function apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. Currently, this policy only applies to Linux web apps. ID: azure_appservice_function_app_latest_java_version -Title: "Ensure that 'Java version' is the latest, if used as a part of the Function app" -Description: "Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for Function apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. Currently, this policy only applies to Linux web apps." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_function_app as (\n select\n id\n from\n azure_app_service_function_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'functionapp%'\n )\n and\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem = 'linux'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' ->> 'linuxFxVersion' not like 'Java%' then 'ok'\n when configuration -> 'properties' ->> 'linuxFxVersion' like '%11' then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is not of linux kind.'\n when configuration -> 'properties' ->> 'linuxFxVersion' not like 'Java%' then a.name || ' not using JAVA version.'\n when configuration -> 'properties' ->> 'linuxFxVersion' like '%11' then a.name || ' using the latest JAVA version.'\n else a.name || ' not using latest JAVA version.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_function_app as a\n left join all_function_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + WITH all_function_app AS ( + SELECT + id + FROM + azure_app_service_function_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE 'functionapp%' + ) + AND + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem = 'linux' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'Java%' THEN 'ok' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' LIKE '%11' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is not of linux kind.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'Java%' THEN a.name || ' not using JAVA version.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' LIKE '%11' THEN a.name || ' using the latest JAVA version.' + ELSE a.name || ' not using latest JAVA version.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app AS a + LEFT JOIN all_function_app AS b + ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure that 'Java version' is the latest, if used as a part of the Function app \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_latest_python_version.yaml b/compliance/controls/azure/azure_appservice_function_app_latest_python_version.yaml old mode 100755 new mode 100644 index 55ae4bca3..569159d70 --- a/compliance/controls/azure/azure_appservice_function_app_latest_python_version.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_latest_python_version.yaml @@ -1,19 +1,65 @@ +Description: Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest Python version for Function apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. Currently, this policy only applies to Linux web apps. ID: azure_appservice_function_app_latest_python_version -Title: "Ensure that 'Python version' is the latest, if used as a part of the Function app" -Description: "Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest Python version for Function apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. Currently, this policy only applies to Linux web apps." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_function_app as (\n select\n id\n from\n azure_app_service_function_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'functionapp%'\n )\n and\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem = 'linux'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' ->> 'linuxFxVersion' not like 'Python%' then 'ok'\n when configuration -> 'properties' ->> 'linuxFxVersion' = 'Python|3.9' then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when configuration -> 'properties' ->> 'linuxFxVersion' not like 'Python%' then a.name || ' not using python version.'\n when configuration -> 'properties' ->> 'linuxFxVersion' = 'Python|3.9' then a.name || ' using the latest python version.'\n else a.name || ' not using latest python version.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_function_app as a\n left join all_function_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + WITH all_function_app AS ( + SELECT + id + FROM + azure_app_service_function_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE + elem LIKE 'functionapp%' + ) + AND + EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE + elem = 'linux' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'Python%' THEN 'ok' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' = 'Python|3.9' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'Python%' THEN a.name || ' not using python version.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' = 'Python|3.9' THEN a.name || ' using the latest python version.' + ELSE a.name || ' not using latest python version.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app AS a + LEFT JOIN all_function_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure that 'Python version' is the latest, if used as a part of the Function app \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_latest_tls_version.yaml b/compliance/controls/azure/azure_appservice_function_app_latest_tls_version.yaml old mode 100755 new mode 100644 index 2193587ac..75e9ccf7e --- a/compliance/controls/azure/azure_appservice_function_app_latest_tls_version.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_latest_tls_version.yaml @@ -1,14 +1,34 @@ +Description: Periodically, newer versions are released for TLS either due to security flaws, include additional functionality, and enhance speed. Upgrade to the latest TLS version for Function apps to take advantage of security fixes, if any, and/or new functionalities of the latest version. ID: azure_appservice_function_app_latest_tls_version -Title: "Function apps should use the latest TLS version" -Description: "Periodically, newer versions are released for TLS either due to security flaws, include additional functionality, and enhance speed. Upgrade to the latest TLS version for Function apps to take advantage of security fixes, if any, and/or new functionalities of the latest version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then name || ' not using the latest version of TLS encryption.'\n else name || ' using the latest version of TLS encryption.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_function_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN name || ' not using the latest version of TLS encryption.' + ELSE name || ' using the latest version of TLS encryption.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +37,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Function apps should use the latest TLS version \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_only_https_accessible.yaml b/compliance/controls/azure/azure_appservice_function_app_only_https_accessible.yaml old mode 100755 new mode 100644 index 1034b5b0e..7d0db39b8 --- a/compliance/controls/azure/azure_appservice_function_app_only_https_accessible.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_only_https_accessible.yaml @@ -1,14 +1,34 @@ +Description: Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks. ID: azure_appservice_function_app_only_https_accessible -Title: "Function apps should only be accessible over HTTPS" -Description: "Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when https_only then 'ok'\n else 'alarm'\n end as status,\n case\n when https_only then name || ' https-only accessible enabled.'\n else name || ' https-only accessible disabled.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_function_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN https_only THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN https_only THEN name || ' https-only accessible enabled.' + ELSE name || ' https-only accessible disabled.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -19,5 +39,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Function apps should only be accessible over HTTPS \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_remote_debugging_disabled.yaml b/compliance/controls/azure/azure_appservice_function_app_remote_debugging_disabled.yaml old mode 100755 new mode 100644 index b81c18563..21f4bc793 --- a/compliance/controls/azure/azure_appservice_function_app_remote_debugging_disabled.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_remote_debugging_disabled.yaml @@ -1,14 +1,34 @@ +Description: Remote debugging requires inbound ports to be opened on function apps. Remote debugging should be turned off. ID: azure_appservice_function_app_remote_debugging_disabled -Title: "Function apps should have remote debugging turned off" -Description: "Remote debugging requires inbound ports to be opened on function apps. Remote debugging should be turned off." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' then 'ok'\n else 'alarm'\n end as status,\n case\n when configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' then name || ' remote debugging disabled.'\n else name || ' remote debugging enabled.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_function_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' THEN name || ' remote debugging disabled.' + ELSE name || ' remote debugging enabled.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +37,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Function apps should have remote debugging turned off \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_restrict_public_acces.yaml b/compliance/controls/azure/azure_appservice_function_app_restrict_public_acces.yaml old mode 100755 new mode 100644 index 33428392b..1d4b58554 --- a/compliance/controls/azure/azure_appservice_function_app_restrict_public_acces.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_restrict_public_acces.yaml @@ -1,15 +1,43 @@ +Description: Anonymous public read access to function app in Azure App Service is a convenient way to share data but might present security risks. To prevent data breaches caused by undesired anonymous access, Microsoft recommends preventing public access to a function app unless your scenario requires it. ID: azure_appservice_function_app_restrict_public_acces -Title: "App Service function apps public access should be restricted" -Description: "Anonymous public read access to function app in Azure App Service is a convenient way to share data but might present security risks. To prevent data breaches caused by undesired anonymous access, Microsoft recommends preventing public access to a function app unless your scenario requires it." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "```sql\nwith public_function_app as (\n select\n id\n from\n azure_app_service_function_app,\n jsonb_array_elements(configuration -> 'properties' -> 'ipSecurityRestrictions') as r\n where\n r ->> 'ipAddress' = 'Any'\n and r ->> 'action' = 'Allow'\n)\nselect\n fa.id as resource,\n fa.og_account_id as og_account_id,\n fa.og_resource_id as og_resource_id,\n case\n when p.id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when p.id is null then name || ' not publicly accessible.'\n else name || ' publicly accessible.'\n end as reason\n \n \n \nfrom\n azure_app_service_function_app fa\n left join public_function_app as p on p.id = fa.id,\n azure_subscription sub\nwhere\n sub.subscription_id = fa.subscription_id;\n```" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + WITH public_function_app AS ( + SELECT + id + FROM + azure_app_service_function_app, + jsonb_array_elements(configuration -> 'properties' -> 'ipSecurityRestrictions') AS r + WHERE + r ->> 'ipAddress' = 'Any' + AND r ->> 'action' = 'Allow' + ) + SELECT + fa.id AS resource, + fa.og_account_id AS og_account_id, + fa.og_resource_id AS og_resource_id, + CASE + WHEN p.id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.id IS NULL THEN name || ' not publicly accessible.' + ELSE name || ' publicly accessible.' + END AS reason + FROM + azure_app_service_function_app fa + LEFT JOIN public_function_app AS p ON p.id = fa.id, + azure_subscription sub + WHERE + sub.subscription_id = fa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: App Service function apps public access should be restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_function_app_uses_managed_identity.yaml b/compliance/controls/azure/azure_appservice_function_app_uses_managed_identity.yaml old mode 100755 new mode 100644 index ee73c0c23..677f2cec1 --- a/compliance/controls/azure/azure_appservice_function_app_uses_managed_identity.yaml +++ b/compliance/controls/azure/azure_appservice_function_app_uses_managed_identity.yaml @@ -1,14 +1,56 @@ +Description: Use a managed identity for enhanced authentication security. ID: azure_appservice_function_app_uses_managed_identity -Title: "Function apps should use managed identity" -Description: "Use a managed identity for enhanced authentication security." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_function_app as (\n select\n id\n from\n azure_app_service_function_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'functionapp%'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when\n configuration -> 'properties' ->> 'xManagedServiceIdentityId' is not null\n or configuration -> 'properties' ->> 'managedServiceIdentityId' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when\n configuration -> 'properties' ->> 'xManagedServiceIdentityId' is not null\n or configuration -> 'properties' ->> 'managedServiceIdentityId' is not null\n then a.name || ' uses managed identity.'\n else a.name || ' not uses managed identity'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_function_app as a\n left join all_function_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_function_app ListOfTables: - azure_app_service_function_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_function_app + QueryToExecute: | + WITH all_function_app AS ( + SELECT + id + FROM + azure_app_service_function_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE 'functionapp%' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN + configuration -> 'properties' ->> 'xManagedServiceIdentityId' IS NOT NULL + OR configuration -> 'properties' ->> 'managedServiceIdentityId' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN + configuration -> 'properties' ->> 'xManagedServiceIdentityId' IS NOT NULL + OR configuration -> 'properties' ->> 'managedServiceIdentityId' IS NOT NULL + THEN a.name || ' uses managed identity.' + ELSE a.name || ' not uses managed identity' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_function_app AS a + LEFT JOIN all_function_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +59,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Function apps should use managed identity \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_plan_minimum_sku.yaml b/compliance/controls/azure/azure_appservice_plan_minimum_sku.yaml old mode 100755 new mode 100644 index 11710a6ef..4f21842f0 --- a/compliance/controls/azure/azure_appservice_plan_minimum_sku.yaml +++ b/compliance/controls/azure/azure_appservice_plan_minimum_sku.yaml @@ -1,30 +1,29 @@ +Description: The Free, Shared, and Basic plans are suitable for constrained testing and development purposes. This control is considered non-compliant when free, shared, or basic SKUs are utilized. ID: azure_appservice_plan_minimum_sku -Title: "Appservice plan should not use free, shared or basic SKU" -Description: "The Free, Shared, and Basic plans are suitable for constrained testing and development purposes. This control is considered non-compliant when free, shared, or basic SKUs are utilized." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - -- The below basic plans are used for development and testing purposes. - when sku_name in ('F1', 'D1', 'B1', 'B2', 'B3') then 'alarm' - else 'ok' - end as status, - a.name || ' is of ' || sku_family || ' SKU family.' as reason - from - azure_app_service_plan as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_app_service_plan ListOfTables: - azure_app_service_plan - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_plan + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_name IN ('F1', 'D1', 'B1', 'B2', 'B3') THEN 'alarm' + ELSE 'ok' + END AS status, + a.name || ' is of ' || sku_family || ' SKU family.' AS reason + FROM + azure_app_service_plan AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Appservice plan should not use free, shared or basic SKU \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_always_on.yaml b/compliance/controls/azure/azure_appservice_web_app_always_on.yaml old mode 100755 new mode 100644 index 0bef37360..d578532be --- a/compliance/controls/azure/azure_appservice_web_app_always_on.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_always_on.yaml @@ -1,32 +1,32 @@ +Description: This control ensures that a web app is configured with settings to keep it consistently active. Always On feature of Azure App Service, keeps the host process running. This allows your site to be more responsive to requests after significant idle periods. ID: azure_appservice_web_app_always_on -Title: "Web apps should be configured to always be on" -Description: "This control ensures that a web app is configured with settings to keep it consistently active. Always On feature of Azure App Service, keeps the host process running. This allows your site to be more responsive to requests after significant idle periods." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when configuration -> 'properties' ->> 'alwaysOn' = 'true' then 'ok' - else 'alarm' - end as status, - case - when configuration -> 'properties' ->> 'alwaysOn' = 'true' then a.name || ' alwaysOn is enabled.' - else a.name || ' alwaysOn is disabled.' - end as reason - from - azure_app_service_web_app as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' ->> 'alwaysOn' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'alwaysOn' = 'true' THEN a.name || ' alwaysOn is enabled.' + ELSE a.name || ' alwaysOn is disabled.' + END AS reason + FROM + azure_app_service_web_app AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Web apps should be configured to always be on \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_client_certificates_on.yaml b/compliance/controls/azure/azure_appservice_web_app_client_certificates_on.yaml old mode 100755 new mode 100644 index 8470ee938..53f96b18a --- a/compliance/controls/azure/azure_appservice_web_app_client_certificates_on.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_client_certificates_on.yaml @@ -1,14 +1,51 @@ +Description: Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app. ID: azure_appservice_web_app_client_certificates_on -Title: "App Service apps should have 'Client Certificates (Incoming client certificates)' enabled" -Description: "Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_web_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'app%'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when client_cert_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when client_cert_enabled then a.name || ' client certificate enabled.'\n else a.name || ' client certificate disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_web_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_web_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE 'app%' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN client_cert_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN client_cert_enabled THEN a.name || ' client certificate enabled.' + ELSE a.name || ' client certificate disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_web_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +54,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service apps should have 'Client Certificates (Incoming client certificates)' enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_cors_no_star.yaml b/compliance/controls/azure/azure_appservice_web_app_cors_no_star.yaml old mode 100755 new mode 100644 index 48ed808b7..cce10bdae --- a/compliance/controls/azure/azure_appservice_web_app_cors_no_star.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_cors_no_star.yaml @@ -1,19 +1,40 @@ +Description: Cross-Origin Resource Sharing (CORS) should not allow all domains to access your web application. Allow only required domains to interact with your web app. ID: azure_appservice_web_app_cors_no_star -Title: "App Service apps should not have CORS configured to allow every resource to access your apps" -Description: "Cross-Origin Resource Sharing (CORS) should not allow all domains to access your web application. Allow only required domains to interact with your web app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '[\"*\"]' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '[\"*\"]'\n then a.name || ' CORS allow all domains to access the application.'\n else a.name || ' CORS does not all domains to access the application.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '["*"]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' -> 'cors' -> 'allowedOrigins' @> '["*"]' + THEN a.name || ' CORS allow all domains to access the application.' + ELSE a.name || ' CORS does not allow all domains to access the application.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service apps should not have CORS configured to allow every resource to access your apps \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_diagnostic_logs_enabled.yaml b/compliance/controls/azure/azure_appservice_web_app_diagnostic_logs_enabled.yaml old mode 100755 new mode 100644 index 15d257be5..0e18651c4 --- a/compliance/controls/azure/azure_appservice_web_app_diagnostic_logs_enabled.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_diagnostic_logs_enabled.yaml @@ -1,14 +1,40 @@ +Description: Audit enabling of resource logs on the app. This enables you to recreate activity trails for investigation purposes if a security incident occurs or your network is compromised. ID: azure_appservice_web_app_diagnostic_logs_enabled -Title: "App Service apps should have resource logs enabled" -Description: "Audit enabling of resource logs on the app. This enables you to recreate activity trails for investigation purposes if a security incident occurs or your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when (a.configuration-> 'properties' -> 'detailedErrorLoggingEnabled')::bool\n and (a.configuration -> 'properties' -> 'httpLoggingEnabled')::bool\n and (a.configuration-> 'properties' -> 'requestTracingEnabled')::bool\n then 'ok'\n else 'alarm'\n end as status,\n case\n when (a.configuration-> 'properties' -> 'detailedErrorLoggingEnabled')::bool\n and (a.configuration -> 'properties' -> 'httpLoggingEnabled')::bool\n and (a.configuration-> 'properties' -> 'requestTracingEnabled')::bool\n then a.name || ' diagnostic logs enabled.'\n else a.title || ' diagnostic logs disabled.'\n -- concat_ws(', ',\n -- case when not ((a.configuration-> 'properties' -> 'detailedErrorLoggingEnabled')::bool) then 'detailed_Error_Logging_Enabled' end,\n -- case when not ((a.configuration -> 'properties' -> 'httpLoggingEnabled')::bool) then 'http_logging_enabled' end,\n -- case when not ((a.configuration-> 'properties' -> 'requestTracingEnabled')::bool) then 'request_tracing_enabled' end\n -- ) || '.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN (a.configuration-> 'properties' -> 'detailedErrorLoggingEnabled')::bool + AND (a.configuration -> 'properties' -> 'httpLoggingEnabled')::bool + AND (a.configuration-> 'properties' -> 'requestTracingEnabled')::bool + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (a.configuration-> 'properties' -> 'detailedErrorLoggingEnabled')::bool + AND (a.configuration -> 'properties' -> 'httpLoggingEnabled')::bool + AND (a.configuration-> 'properties' -> 'requestTracingEnabled')::bool + THEN a.name || ' diagnostic logs enabled.' + ELSE a.title || ' diagnostic logs disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +43,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service apps should have resource logs enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_failed_request_tracing_enabled.yaml b/compliance/controls/azure/azure_appservice_web_app_failed_request_tracing_enabled.yaml old mode 100755 new mode 100644 index cab8e98b5..c79d629be --- a/compliance/controls/azure/azure_appservice_web_app_failed_request_tracing_enabled.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_failed_request_tracing_enabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure that Web app enables failed request tracing. This control is non-compliant if Web app failed request tracing is disabled. ID: azure_appservice_web_app_failed_request_tracing_enabled -Title: "Web app failed request tracing should be enabled" -Description: "Ensure that Web app enables failed request tracing. This control is non-compliant if Web app failed request tracing is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when diagnostic_logs_configuration -> 'properties' -> 'failedRequestsTracing' ->> 'enabled' = 'true' then 'ok' - else 'alarm' - end as status, - case - when diagnostic_logs_configuration -> 'properties' -> 'failedRequestsTracing' ->> 'enabled' = 'true' then a.name || ' failed requests tracing enabled.' - else a.name || ' failed requests tracing disabled.' - end as reason - from - azure_app_service_web_app as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN diagnostic_logs_configuration -> 'properties' -> 'failedRequestsTracing' ->> 'enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN diagnostic_logs_configuration -> 'properties' -> 'failedRequestsTracing' ->> 'enabled' = 'true' THEN a.name || ' failed requests tracing enabled.' + ELSE a.name || ' failed requests tracing disabled.' + END AS reason + FROM + azure_app_service_web_app AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Web app failed request tracing should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_ftps_enabled.yaml b/compliance/controls/azure/azure_appservice_web_app_ftps_enabled.yaml old mode 100755 new mode 100644 index e6ed5f156..f2ed9e1bf --- a/compliance/controls/azure/azure_appservice_web_app_ftps_enabled.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_ftps_enabled.yaml @@ -1,19 +1,55 @@ +Description: Enable FTPS enforcement for enhanced security. ID: azure_appservice_web_app_ftps_enabled -Title: "FTPS should be required in your Web App" -Description: "Enable FTPS enforcement for enhanced security." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_web_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'app%'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then a.name || ' FTPS disabled.'\n else a.name || ' FTPS enabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_web_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_web_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE + elem LIKE 'app%' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN a.name || ' FTPS disabled.' + ELSE a.name || ' FTPS enabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_web_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: FTPS should be required in your Web App \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_health_check_enabled.yaml b/compliance/controls/azure/azure_appservice_web_app_health_check_enabled.yaml old mode 100755 new mode 100644 index dff84636b..fda0a82d5 --- a/compliance/controls/azure/azure_appservice_web_app_health_check_enabled.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_health_check_enabled.yaml @@ -1,32 +1,32 @@ +Description: Health check increases your application's availability by rerouting requests away from unhealthy instances and replacing instances if they remain unhealthy. ID: azure_appservice_web_app_health_check_enabled -Title: "Web apps should have health check enabled" -Description: "Health check increases your application's availability by rerouting requests away from unhealthy instances and replacing instances if they remain unhealthy." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when configuration -> 'properties' ->> 'healthCheckPath' is not null then 'ok' - else 'alarm' - end as status, - case - when configuration -> 'properties' ->> 'healthCheckPath' is not null then a.name || ' health check enabled.' - else a.name || ' health check disabled.' - end as reason - from - azure_app_service_web_app as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' ->> 'healthCheckPath' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'healthCheckPath' IS NOT NULL THEN a.name || ' health check enabled.' + ELSE a.name || ' health check disabled.' + END AS reason + FROM + azure_app_service_web_app AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Web apps should have health check enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_http_logs_enabled.yaml b/compliance/controls/azure/azure_appservice_web_app_http_logs_enabled.yaml old mode 100755 new mode 100644 index cb39a5af2..694901fb2 --- a/compliance/controls/azure/azure_appservice_web_app_http_logs_enabled.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_http_logs_enabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure that Web app HTTP logs is enabled. This control is non-compliant if Web app HTTP logs is disabled. ID: azure_appservice_web_app_http_logs_enabled -Title: "Web app HTTP logs should be enabled" -Description: "Ensure that Web app HTTP logs is enabled. This control is non-compliant if Web app HTTP logs is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when configuration -> 'properties' ->> 'httpLoggingEnabled' = 'true' then 'ok' - else 'alarm' - end as status, - case - when configuration -> 'properties' ->> 'httpLoggingEnabled' = 'true' then a.name || ' HTTP logs enabled.' - else a.name || ' HTTP logs disabled.' - end as reason - from - azure_app_service_web_app as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' ->> 'httpLoggingEnabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'httpLoggingEnabled' = 'true' THEN a.name || ' HTTP logs enabled.' + ELSE a.name || ' HTTP logs disabled.' + END AS reason + FROM + azure_app_service_web_app AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Web app HTTP logs should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_incoming_client_cert_on.yaml b/compliance/controls/azure/azure_appservice_web_app_incoming_client_cert_on.yaml old mode 100755 new mode 100644 index 6d355a328..54f75f4d9 --- a/compliance/controls/azure/azure_appservice_web_app_incoming_client_cert_on.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_incoming_client_cert_on.yaml @@ -1,14 +1,34 @@ +Description: Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app. ID: azure_appservice_web_app_incoming_client_cert_on -Title: "Ensure the web app has 'Client Certificates (Incoming client certificates)' set to 'On'" -Description: "Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when not client_cert_enabled then 'alarm'\n else 'ok'\n end as status,\n case\n when not client_cert_enabled then name || ' incoming client certificates set to off.'\n else name || ' incoming client certificates set to on.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT client_cert_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT client_cert_enabled THEN name || ' incoming client certificates set to off.' + ELSE name || ' incoming client certificates set to on.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure the web app has 'Client Certificates (Incoming client certificates)' set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_latest_dotnet_framework_version.yaml b/compliance/controls/azure/azure_appservice_web_app_latest_dotnet_framework_version.yaml old mode 100755 new mode 100644 index 4d72dbf76..d134471d1 --- a/compliance/controls/azure/azure_appservice_web_app_latest_dotnet_framework_version.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_latest_dotnet_framework_version.yaml @@ -1,51 +1,51 @@ +Description: Periodically, newer versions are released for Net Framework software either due to security flaws or to include additional functionality. Using the latest Net Framework for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. ID: azure_appservice_web_app_latest_dotnet_framework_version -Title: "Web app should use the latest 'Net Framework' version" -Description: "Periodically, newer versions are released for Net Framework software either due to security flaws or to include additional functionality. Using the latest Net Framework for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_app_service_web_app + - azure_subscription + Parameters: [] + PrimaryTable: azure_app_service_web_app QueryToExecute: | - with all_linux_web_app as ( - select + WITH all_linux_web_app AS ( + SELECT id - from + FROM azure_app_service_web_app - where - exists ( - select - from - unnest(regexp_split_to_array(kind, ',')) elem - where + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE elem = 'linux' ) ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.id is null and configuration -> 'properties' ->> 'netFrameworkVersion' in ('v6.0', 'v7.0') then 'ok' - when b.id is not null and configuration -> 'properties' ->> 'linuxFxVersion' not like 'DOTNETCORE|%' then 'ok' - when b.id is not null and configuration -> 'properties' ->> 'linuxFxVersion' in ('DOTNETCORE|6.0', 'DOTNETCORE|7.0') then 'ok' - else 'alarm' - end as status, - case - when b.id is null and configuration -> 'properties' ->> 'netFrameworkVersion' in ('v6.0', 'v7.0') then a.name || ' using latest dotnet framework version.' - when b.id is not null and configuration -> 'properties' ->> 'linuxFxVersion' not like 'DOTNETCORE|%' then a.name || ' not using dotnet framework.' - when b.id is not null and configuration -> 'properties' ->> 'linuxFxVersion' in ('DOTNETCORE|6.0', 'DOTNETCORE|7.0') then a.name || ' using latest dotnet vframework ersion.' - else a.name || ' not using latest dotnet framework version.' - end as reason - from - azure_app_service_web_app as a - left join all_linux_web_app as b on a.id = b.id, - azure_subscription as sub - where + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL AND configuration -> 'properties' ->> 'netFrameworkVersion' IN ('v6.0', 'v7.0') THEN 'ok' + WHEN b.id IS NOT NULL AND configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'DOTNETCORE|%' THEN 'ok' + WHEN b.id IS NOT NULL AND configuration -> 'properties' ->> 'linuxFxVersion' IN ('DOTNETCORE|6.0', 'DOTNETCORE|7.0') THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL AND configuration -> 'properties' ->> 'netFrameworkVersion' IN ('v6.0', 'v7.0') THEN a.name || ' using latest dotnet framework version.' + WHEN b.id IS NOT NULL AND configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'DOTNETCORE|%' THEN a.name || ' not using dotnet framework.' + WHEN b.id IS NOT NULL AND configuration -> 'properties' ->> 'linuxFxVersion' IN ('DOTNETCORE|6.0', 'DOTNETCORE|7.0') THEN a.name || ' using latest dotnet framework version.' + ELSE a.name || ' not using latest dotnet framework version.' + END AS reason + FROM + azure_app_service_web_app AS a + LEFT JOIN all_linux_web_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE sub.subscription_id = a.subscription_id; - PrimaryTable: azure_app_service_web_app - ListOfTables: - - azure_app_service_web_app - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Web app should use the latest 'Net Framework' version \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_latest_http_version.yaml b/compliance/controls/azure/azure_appservice_web_app_latest_http_version.yaml old mode 100755 new mode 100644 index c42c00692..c3e31bbef --- a/compliance/controls/azure/azure_appservice_web_app_latest_http_version.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_latest_http_version.yaml @@ -1,14 +1,34 @@ +Description: Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version. Currently, this policy only applies to Linux web apps. ID: azure_appservice_web_app_latest_http_version -Title: "Ensure that 'HTTP Version' is the latest, if used to run the Web app" -Description: "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version. Currently, this policy only applies to Linux web apps." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then 'alarm'\n else 'ok'\n end as status,\n case\n when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then name || ' HTTP version not latest.'\n else name || ' HTTP version is latest.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::boolean THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::boolean THEN name || ' HTTP version not latest.' + ELSE name || ' HTTP version is latest.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure that 'HTTP Version' is the latest, if used to run the Web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_latest_java_version.yaml b/compliance/controls/azure/azure_appservice_web_app_latest_java_version.yaml old mode 100755 new mode 100644 index 641162a8d..8cdf3e760 --- a/compliance/controls/azure/azure_appservice_web_app_latest_java_version.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_latest_java_version.yaml @@ -1,19 +1,65 @@ +Description: Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. Currently, this policy only applies to Linux web apps. ID: azure_appservice_web_app_latest_java_version -Title: "Ensure that 'Java version' is the latest, if used as a part of the Web app" -Description: "Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. Currently, this policy only applies to Linux web apps." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_web_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'app%'\n )\n and\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem = 'linux'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' ->> 'linuxFxVersion' not like 'JAVA%' then 'ok'\n when configuration -> 'properties' ->> 'linuxFxVersion' like '%11' then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when configuration -> 'properties' ->> 'linuxFxVersion' not like 'JAVA%' then a.name || ' not using JAVA version.'\n when configuration -> 'properties' ->> 'linuxFxVersion' like '%11' then a.name || ' using the latest JAVA version.'\n else a.name || ' not using latest JAVA version.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_web_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_web_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE 'app%' + ) + AND + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem = 'linux' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'JAVA%' THEN 'ok' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' LIKE '%11' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'JAVA%' THEN a.name || ' not using JAVA version.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' LIKE '%11' THEN a.name || ' using the latest JAVA version.' + ELSE a.name || ' not using latest JAVA version.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_web_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure that 'Java version' is the latest, if used as a part of the Web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_latest_php_version.yaml b/compliance/controls/azure/azure_appservice_web_app_latest_php_version.yaml old mode 100755 new mode 100644 index 27bf19ae3..9734e0efe --- a/compliance/controls/azure/azure_appservice_web_app_latest_php_version.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_latest_php_version.yaml @@ -1,19 +1,64 @@ +Description: Periodically, newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. Currently, this policy only applies to Linux web apps. ID: azure_appservice_web_app_latest_php_version -Title: "Ensure that 'PHP version' is the latest, if used as a part of the WEB app" -Description: "Periodically, newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. Currently, this policy only applies to Linux web apps." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_web_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'app%'\n )\n and\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem = 'linux'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' ->> 'linuxFxVersion' not like 'PHP%' then 'ok'\n when configuration -> 'properties' ->> 'linuxFxVersion' = 'PHP|8.0' then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when configuration -> 'properties' ->> 'linuxFxVersion' not like 'PHP%' then a.name || ' not using php version.'\n when configuration -> 'properties' ->> 'linuxFxVersion' = 'PHP|8.0' then a.name || ' using the latest php version.'\n else a.name || ' not using latest php version.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_web_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_web_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE + elem LIKE 'app%' + ) + AND EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE + elem = 'linux' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'PHP%' THEN 'ok' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' = 'PHP|8.0' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'PHP%' THEN a.name || ' not using php version.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' = 'PHP|8.0' THEN a.name || ' using the latest php version.' + ELSE a.name || ' not using latest php version.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_web_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure that 'PHP version' is the latest, if used as a part of the WEB app \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_latest_python_version.yaml b/compliance/controls/azure/azure_appservice_web_app_latest_python_version.yaml old mode 100755 new mode 100644 index a61d2470d..ca93c3e81 --- a/compliance/controls/azure/azure_appservice_web_app_latest_python_version.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_latest_python_version.yaml @@ -1,19 +1,65 @@ +Description: Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. Currently, this policy only applies to Linux web apps. ID: azure_appservice_web_app_latest_python_version -Title: "Ensure that 'Python version' is the latest, if used as a part of the Web app" -Description: "Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the latest version. Currently, this policy only applies to Linux web apps." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_web_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'app%'\n )\n and\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem = 'linux'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when configuration -> 'properties' ->> 'linuxFxVersion' not like 'PYTHON%' then 'ok'\n when configuration -> 'properties' ->> 'linuxFxVersion' = 'PYTHON|3.9' then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is not of linux kind.'\n when configuration -> 'properties' ->> 'linuxFxVersion' not like 'PYTHON%' then a.name || ' not using python version.'\n when configuration -> 'properties' ->> 'linuxFxVersion' = 'PYTHON|3.9' then a.name || ' using the latest python version.'\n else a.name || ' not using latest python version.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_web_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_web_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE 'app%' + ) + AND + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem = 'linux' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'PYTHON%' THEN 'ok' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' = 'PYTHON|3.9' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is not of linux kind.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'PYTHON%' THEN a.name || ' not using python version.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' = 'PYTHON|3.9' THEN a.name || ' using the latest python version.' + ELSE a.name || ' not using latest python version.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_web_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure that 'Python version' is the latest, if used as a part of the Web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_latest_tls_version.yaml b/compliance/controls/azure/azure_appservice_web_app_latest_tls_version.yaml old mode 100755 new mode 100644 index aa77d5d67..7d3111894 --- a/compliance/controls/azure/azure_appservice_web_app_latest_tls_version.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_latest_tls_version.yaml @@ -1,14 +1,34 @@ +Description: Upgrade to the latest TLS version. ID: azure_appservice_web_app_latest_tls_version -Title: "Latest TLS version should be used in your Web App" -Description: "Upgrade to the latest TLS version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then name || ' not using the latest version of TLS encryption.'\n else name || ' using the latest version of TLS encryption.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN name || ' not using the latest version of TLS encryption.' + ELSE name || ' using the latest version of TLS encryption.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Latest TLS version should be used in your Web App \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_register_with_active_directory_enabled.yaml b/compliance/controls/azure/azure_appservice_web_app_register_with_active_directory_enabled.yaml old mode 100755 new mode 100644 index b00f60537..6add314a9 --- a/compliance/controls/azure/azure_appservice_web_app_register_with_active_directory_enabled.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_register_with_active_directory_enabled.yaml @@ -1,14 +1,34 @@ +Description: Managed service identity in App Service provides more security by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in App Service, the app will connect to other Azure services securely without the need for usernames and passwords. ID: azure_appservice_web_app_register_with_active_directory_enabled -Title: "Ensure that Register with Azure Active Directory is enabled on App Service" -Description: "Managed service identity in App Service provides more security by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in App Service, the app will connect to other Azure services securely without the need for usernames and passwords." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when identity = '{}' then 'alarm'\n else 'ok'\n end as status,\n case\n when identity = '{}' then name || ' register with azure active directory disabled.'\n else name || ' register with azure active directory enabled.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN identity = '{}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity = '{}' THEN name || ' register with azure active directory disabled.' + ELSE name || ' register with azure active directory enabled.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Ensure that Register with Azure Active Directory is enabled on App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_remote_debugging_disabled.yaml b/compliance/controls/azure/azure_appservice_web_app_remote_debugging_disabled.yaml old mode 100755 new mode 100644 index f72e83845..8961159fe --- a/compliance/controls/azure/azure_appservice_web_app_remote_debugging_disabled.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_remote_debugging_disabled.yaml @@ -1,14 +1,36 @@ +Description: Remote debugging requires inbound ports to be opened on a web application. Remote debugging should be turned off. ID: azure_appservice_web_app_remote_debugging_disabled -Title: "Remote debugging should be turned off for Web Applications" -Description: "Remote debugging requires inbound ports to be opened on a web application. Remote debugging should be turned off." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when kind = 'api' then 'skip'\n when configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' then 'ok'\n else 'alarm'\n end as status,\n case\n when kind = 'api' then name || ' is of ' || kind || ' type.'\n when configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' then name || ' remote debugging disabled.'\n else name || ' remote debugging enabled.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN kind = 'api' THEN 'skip' + WHEN configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN kind = 'api' THEN name || ' is of ' || kind || ' type.' + WHEN configuration -> 'properties' ->> 'remoteDebuggingEnabled' = 'false' THEN name || ' remote debugging disabled.' + ELSE name || ' remote debugging enabled.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +39,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Remote debugging should be turned off for Web Applications \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_slot_use_https.yaml b/compliance/controls/azure/azure_appservice_web_app_slot_use_https.yaml old mode 100755 new mode 100644 index 4643e4abb..5dc4577da --- a/compliance/controls/azure/azure_appservice_web_app_slot_use_https.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_slot_use_https.yaml @@ -1,32 +1,32 @@ +Description: Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks. ID: azure_appservice_web_app_slot_use_https -Title: "Web app slot should only be accessible over HTTPS" -Description: "Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when https_only then 'ok' - else 'alarm' - end as status, - case - when https_only then name || ' https-only accessible enabled.' - else name || ' https-only accessible disabled.' - end as reason - from - azure_app_service_web_app_slot as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_app_service_web_app_slot ListOfTables: - azure_app_service_web_app_slot - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app_slot + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN https_only THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN https_only THEN name || ' https-only accessible enabled.' + ELSE name || ' https-only accessible disabled.' + END AS reason + FROM + azure_app_service_web_app_slot AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Web app slot should only be accessible over HTTPS \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_use_https.yaml b/compliance/controls/azure/azure_appservice_web_app_use_https.yaml old mode 100755 new mode 100644 index 69c2a3409..8af6d6943 --- a/compliance/controls/azure/azure_appservice_web_app_use_https.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_use_https.yaml @@ -1,14 +1,34 @@ +Description: Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks. ID: azure_appservice_web_app_use_https -Title: "Web Application should only be accessible over HTTPS" -Description: "Use of HTTPS ensures server/service authentication and protects data in transit from network layer eavesdropping attacks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n app.og_account_id as og_account_id,\n app.og_resource_id as og_resource_id,\n case\n when not https_only then 'alarm'\n else 'ok'\n end as status,\n case\n when not https_only then name || ' does not redirect all HTTP traffic to HTTPS.'\n else name || ' redirects all HTTP traffic to HTTPS.'\n end as reason\n \n , app.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT https_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT https_only THEN name || ' does not redirect all HTTP traffic to HTTPS.' + ELSE name || ' redirects all HTTP traffic to HTTPS.' + END AS reason, + app.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: Web Application should only be accessible over HTTPS \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_use_virtual_service_endpoint.yaml b/compliance/controls/azure/azure_appservice_web_app_use_virtual_service_endpoint.yaml old mode 100755 new mode 100644 index 3282fb5fe..c0ff74d4d --- a/compliance/controls/azure/azure_appservice_web_app_use_virtual_service_endpoint.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_use_virtual_service_endpoint.yaml @@ -1,19 +1,38 @@ +Description: Use virtual network service endpoints to restrict access to your app from selected subnets from an Azure virtual network. To learn more about App Service service endpoints, visit https://aks.ms/appservice-vnet-service-endpoint. ID: azure_appservice_web_app_use_virtual_service_endpoint -Title: "App Service apps should use a virtual network service endpoint" -Description: "Use virtual network service endpoints to restrict access to your app from selected subnets from an Azure virtual network. To learn more about App Service service endpoints, visit https://aks.ms/appservice-vnet-service-endpoint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when vnet_connection -> 'properties' -> 'vnetResourceId' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when vnet_connection -> 'properties' -> 'vnetResourceId' is not null then a.name || ' configured with virtual network service endpoint.'\n else a.name || ' not configured with virtual network service endpoint.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN vnet_connection -> 'properties' -> 'vnetResourceId' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN vnet_connection -> 'properties' -> 'vnetResourceId' IS NOT NULL THEN a.name || ' configured with virtual network service endpoint.' + ELSE a.name || ' not configured with virtual network service endpoint.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service apps should use a virtual network service endpoint \ No newline at end of file diff --git a/compliance/controls/azure/azure_appservice_web_app_uses_managed_identity.yaml b/compliance/controls/azure/azure_appservice_web_app_uses_managed_identity.yaml old mode 100755 new mode 100644 index 471ba5036..353ca3319 --- a/compliance/controls/azure/azure_appservice_web_app_uses_managed_identity.yaml +++ b/compliance/controls/azure/azure_appservice_web_app_uses_managed_identity.yaml @@ -1,14 +1,56 @@ +Description: Use a managed identity for enhanced authentication security. ID: azure_appservice_web_app_uses_managed_identity -Title: "App Service apps should use managed identity" -Description: "Use a managed identity for enhanced authentication security." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_web_app as (\n select\n id\n from\n azure_app_service_web_app\n where\n exists (\n select\n from\n unnest(regexp_split_to_array(kind, ',')) elem\n where\n elem like 'app%'\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is null then 'skip'\n when\n configuration -> 'properties' ->> 'xManagedServiceIdentityId' is not null\n or configuration -> 'properties' ->> 'managedServiceIdentityId' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.id is null then a.title || ' is ' || a.kind || ' kind.'\n when\n configuration -> 'properties' ->> 'xManagedServiceIdentityId' is not null\n or configuration -> 'properties' ->> 'managedServiceIdentityId' is not null\n then a.name || ' uses managed identity.'\n else a.name || ' not uses managed identity'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_app_service_web_app as a\n left join all_web_app as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_web_app AS ( + SELECT + id + FROM + azure_app_service_web_app + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE 'app%' + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN + configuration -> 'properties' ->> 'xManagedServiceIdentityId' IS NOT NULL + OR configuration -> 'properties' ->> 'managedServiceIdentityId' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN + configuration -> 'properties' ->> 'xManagedServiceIdentityId' IS NOT NULL + OR configuration -> 'properties' ->> 'managedServiceIdentityId' IS NOT NULL + THEN a.name || ' uses managed identity.' + ELSE a.name || ' not uses managed identity' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS a + LEFT JOIN all_web_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: hipaa_hitrust_v92: @@ -17,5 +59,4 @@ Tags: - "true" service: - Azure/AppService -IntegrationType: - - azure_subscription +Title: App Service apps should use managed identity \ No newline at end of file diff --git a/compliance/controls/azure/azure_arc_compute_machine_linux_log_analytics_agent_installed.yaml b/compliance/controls/azure/azure_arc_compute_machine_linux_log_analytics_agent_installed.yaml old mode 100755 new mode 100644 index 1ab7c4d53..64694046e --- a/compliance/controls/azure/azure_arc_compute_machine_linux_log_analytics_agent_installed.yaml +++ b/compliance/controls/azure/azure_arc_compute_machine_linux_log_analytics_agent_installed.yaml @@ -1,19 +1,54 @@ +Description: This policy audits Linux Azure Arc machines if the Log Analytics extension is not installed. ID: azure_arc_compute_machine_linux_log_analytics_agent_installed -Title: "Log Analytics extension should be installed on your Linux Azure Arc machines" -Description: "This policy audits Linux Azure Arc machines if the Log Analytics extension is not installed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with compute_machine as(\n select\n id,\n name,\n subscription_id,\n resource_group\n from\n azure_hybrid_compute_machine,\n jsonb_array_elements(extensions) as e\n where\n e ->> 'name' = 'OMSAgentForLinux'\n and e ->> 'provisioningState' = 'Succeeded'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_name <> 'linux' then 'skip'\n when m.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_name <> 'linux' then a.name || ' is of ' || a.os_name || ' operating system.'\n when m.id is not null then a.name || ' log analytics extension installed.'\n else a.name || ' log analytics extension not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\nazure_hybrid_compute_machine as a\nleft join compute_machine as m on m.id = a.id,\nazure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_hybrid_compute_machine ListOfTables: - azure_hybrid_compute_machine - azure_subscription Parameters: [] + PrimaryTable: azure_hybrid_compute_machine + QueryToExecute: | + WITH compute_machine AS ( + SELECT + id, + name, + subscription_id, + resource_group + FROM + azure_hybrid_compute_machine, + jsonb_array_elements(extensions) AS e + WHERE + e ->> 'name' = 'OMSAgentForLinux' + AND e ->> 'provisioningState' = 'Succeeded' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_name <> 'linux' THEN 'skip' + WHEN m.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_name <> 'linux' THEN a.name || ' is of ' || a.os_name || ' operating system.' + WHEN m.id IS NOT NULL THEN a.name || ' log analytics extension installed.' + ELSE a.name || ' log analytics extension not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_hybrid_compute_machine AS a + LEFT JOIN compute_machine AS m ON m.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Log Analytics extension should be installed on your Linux Azure Arc machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_arc_compute_machine_windows_log_analytics_agent_installed.yaml b/compliance/controls/azure/azure_arc_compute_machine_windows_log_analytics_agent_installed.yaml old mode 100755 new mode 100644 index f78de8844..28e97e807 --- a/compliance/controls/azure/azure_arc_compute_machine_windows_log_analytics_agent_installed.yaml +++ b/compliance/controls/azure/azure_arc_compute_machine_windows_log_analytics_agent_installed.yaml @@ -1,19 +1,55 @@ +Description: This policy audits Windows Azure Arc machines if the Log Analytics agent is not installed. ID: azure_arc_compute_machine_windows_log_analytics_agent_installed -Title: "Log Analytics extension should be installed on your Windows Azure Arc machines" -Description: "This policy audits Windows Azure Arc machines if the Log Analytics agent is not installed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with compute_machine as(\n select\n id,\n name,\n subscription_id,\n resource_group\n from\n azure_hybrid_compute_machine,\n jsonb_array_elements(extensions) as e\n where\n e ->> 'name' = 'MicrosoftMonitoringAgent'\n and e ->> 'provisioningState' = 'Succeeded'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_name <> 'windows' then 'skip'\n when m.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_name <> 'windows' then a.name || ' is of ' || a.os_name || ' operating system.'\n when m.id is not null then a.name || ' log analytics extension installed.'\n else a.name || ' log analytics extension not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\nazure_hybrid_compute_machine as a\nleft join compute_machine as m on m.id = a.id,\nazure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_hybrid_compute_machine ListOfTables: - azure_hybrid_compute_machine - azure_subscription Parameters: [] + PrimaryTable: azure_hybrid_compute_machine + QueryToExecute: | + WITH compute_machine AS ( + SELECT + id, + name, + subscription_id, + resource_group + FROM + azure_hybrid_compute_machine, + jsonb_array_elements(extensions) AS e + WHERE + e ->> 'name' = 'MicrosoftMonitoringAgent' + AND e ->> 'provisioningState' = 'Succeeded' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_name <> 'windows' THEN 'skip' + WHEN m.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_name <> 'windows' THEN a.name || ' is of ' || a.os_name || ' operating system.' + WHEN m.id IS NOT NULL THEN a.name || ' log analytics extension installed.' + ELSE a.name || ' log analytics extension not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_hybrid_compute_machine AS a + LEFT JOIN + compute_machine AS m ON m.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Log Analytics extension should be installed on your Windows Azure Arc machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_arc_kubernetes_cluster_azure_defender_extension_installed.yaml b/compliance/controls/azure/azure_arc_kubernetes_cluster_azure_defender_extension_installed.yaml old mode 100755 new mode 100644 index 4a5eae3eb..be84bbe3a --- a/compliance/controls/azure/azure_arc_kubernetes_cluster_azure_defender_extension_installed.yaml +++ b/compliance/controls/azure/azure_arc_kubernetes_cluster_azure_defender_extension_installed.yaml @@ -1,24 +1,24 @@ +Description: Microsoft Defender for Cloud extension for Azure Arc provides threat protection for your Arc enabled Kubernetes clusters. The extension collects data from all nodes in the cluster and sends it to the Azure Defender for Kubernetes backend in the cloud for further analysis. ID: azure_arc_kubernetes_cluster_azure_defender_extension_installed -Title: "Azure Arc enabled Kubernetes clusters should have Microsoft Defender for Cloud extension installed" -Description: "Microsoft Defender for Cloud extension for Azure Arc provides threat protection for your Arc enabled Kubernetes clusters. The extension collects data from all nodes in the cluster and sends it to the Azure Defender for Kubernetes backend in the cloud for further analysis." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Azure Arc enabled Kubernetes clusters should have Microsoft Defender for Cloud extension installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_audit_diagnostic_setting.yaml b/compliance/controls/azure/azure_audit_diagnostic_setting.yaml old mode 100755 new mode 100644 index 0c790ec4d..cc54729e1 --- a/compliance/controls/azure/azure_audit_diagnostic_setting.yaml +++ b/compliance/controls/azure/azure_audit_diagnostic_setting.yaml @@ -1,24 +1,24 @@ +Description: Audit diagnostic setting for selected resource types. Be sure to select only resource types which support diagnostics settings. ID: azure_audit_diagnostic_setting -Title: "Audit diagnostic setting for selected resource types" -Description: "Audit diagnostic setting for selected resource types. Be sure to select only resource types which support diagnostics settings." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Audit diagnostic setting for selected resource types \ No newline at end of file diff --git a/compliance/controls/azure/azure_authorize_access_to_security_functions_and_information.yaml b/compliance/controls/azure/azure_authorize_access_to_security_functions_and_information.yaml old mode 100755 new mode 100644 index 5a4416df7..1099f6d33 --- a/compliance/controls/azure/azure_authorize_access_to_security_functions_and_information.yaml +++ b/compliance/controls/azure/azure_authorize_access_to_security_functions_and_information.yaml @@ -1,24 +1,24 @@ +Description: CMA_0022 - Authorize access to security functions and information. ID: azure_authorize_access_to_security_functions_and_information -Title: "Authorize access to security functions and information" -Description: "CMA_0022 - Authorize access to security functions and information." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Authorize access to security functions and information \ No newline at end of file diff --git a/compliance/controls/azure/azure_automation_account_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_automation_account_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 1c47004a6..e366bf55e --- a/compliance/controls/azure/azure_automation_account_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_automation_account_encrypted_with_cmk.yaml @@ -1,24 +1,24 @@ +Description: Use customer-managed keys to manage the encryption at rest of your Azure Automation Accounts. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/automation-cmk. ID: azure_automation_account_encrypted_with_cmk -Title: "Azure Automation accounts should use customer-managed keys to encrypt data at rest" -Description: "Use customer-managed keys to manage the encryption at rest of your Azure Automation Accounts. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/automation-cmk." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Azure Automation accounts should use customer-managed keys to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_automation_account_variable_encryption_enabled.yaml b/compliance/controls/azure/azure_automation_account_variable_encryption_enabled.yaml old mode 100755 new mode 100644 index d154da92d..c53c1bee6 --- a/compliance/controls/azure/azure_automation_account_variable_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_automation_account_variable_encryption_enabled.yaml @@ -1,36 +1,36 @@ +Description: It is important to enable encryption of Automation account variable assets when storing sensitive data ID: azure_automation_account_variable_encryption_enabled -Title: "Automation account variables should be encrypted" -Description: "It is important to enable encryption of Automation account variable assets when storing sensitive data" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when is_encrypted then 'ok' - else 'alarm' - end as status, - case - when is_encrypted then a.title || ' encryption enabled.' - else a.title || ' encryption disabled.' - end as reason - , a.resource_group as resource_group - , sub.display_name as subscription - from - azure_automation_variable as a, - azure_subscription as sub; - PrimaryTable: azure_automation_variable ListOfTables: - azure_automation_variable - azure_subscription Parameters: [] + PrimaryTable: azure_automation_variable + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN is_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN is_encrypted THEN a.title || ' encryption enabled.' + ELSE a.title || ' encryption disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_automation_variable AS a, + azure_subscription AS sub; Severity: high Tags: pci_dss_v321: - "true" service: - Azure/Automation -IntegrationType: - - azure_subscription +Title: Automation account variables should be encrypted \ No newline at end of file diff --git a/compliance/controls/azure/azure_batch_account_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_batch_account_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 1bb236a73..b315029ea --- a/compliance/controls/azure/azure_batch_account_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_batch_account_encrypted_with_cmk.yaml @@ -1,19 +1,38 @@ +Description: Use customer-managed keys to manage the encryption at rest of your Batch account's data. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_batch_account_encrypted_with_cmk -Title: "Azure Batch account should use customer-managed keys to encrypt data" -Description: "Use customer-managed keys to manage the encryption at rest of your Batch account's data. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n batch.id as resource,\n batch.og_account_id as og_account_id,\n batch.og_resource_id as og_resource_id,\n case\n when encryption ->> 'keySource' = 'Microsoft.KeyVault' then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption ->> 'keySource' = 'Microsoft.KeyVault' then batch.name || ' encrypted with CMK.'\n else batch.name || ' not encrypted with CMK.'\n end as reason\n \n , batch.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_batch_account as batch,\n azure_subscription as sub\nwhere\n sub.subscription_id = batch.subscription_id;\n" - PrimaryTable: azure_batch_account ListOfTables: - azure_batch_account - azure_subscription Parameters: [] + PrimaryTable: azure_batch_account + QueryToExecute: | + SELECT + batch.id AS resource, + batch.og_account_id AS og_account_id, + batch.og_resource_id AS og_resource_id, + CASE + WHEN encryption ->> 'keySource' = 'Microsoft.KeyVault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption ->> 'keySource' = 'Microsoft.KeyVault' THEN batch.name || ' encrypted with CMK.' + ELSE batch.name || ' not encrypted with CMK.' + END AS reason, + batch.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_batch_account AS batch, + azure_subscription AS sub + WHERE + sub.subscription_id = batch.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Batch -IntegrationType: - - azure_subscription +Title: Azure Batch account should use customer-managed keys to encrypt data \ No newline at end of file diff --git a/compliance/controls/azure/azure_batch_account_identity_provider_enabled.yaml b/compliance/controls/azure/azure_batch_account_identity_provider_enabled.yaml old mode 100755 new mode 100644 index 6442b76a2..e40197798 --- a/compliance/controls/azure/azure_batch_account_identity_provider_enabled.yaml +++ b/compliance/controls/azure/azure_batch_account_identity_provider_enabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure that managed identity provider is enabled for the batch account. This control is non-compliant if batch account identity provider is disabled. ID: azure_batch_account_identity_provider_enabled -Title: "Batch accounts identity provider should be enabled" -Description: "Ensure that managed identity provider is enabled for the batch account. This control is non-compliant if batch account identity provider is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - b.id as resource, - b.og_account_id as og_account_id, - b.og_resource_id as og_resource_id, - case - when identity ->> 'type' = 'None' then 'alarm' - else 'ok' - end as status, - case - when identity ->> 'type' = 'None' then b.name || ' identity provider disabled.' - else b.name || ' identity provider enabled.' - end as reason - from - azure_batch_account as b, - azure_subscription as sub - where - sub.subscription_id = b.subscription_id; - PrimaryTable: azure_batch_account ListOfTables: - azure_batch_account - azure_subscription Parameters: [] + PrimaryTable: azure_batch_account + QueryToExecute: | + SELECT + b.id AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN identity ->> 'type' = 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity ->> 'type' = 'None' THEN b.name || ' identity provider disabled.' + ELSE b.name || ' identity provider enabled.' + END AS reason + FROM + azure_batch_account AS b, + azure_subscription AS sub + WHERE + sub.subscription_id = b.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Batch accounts identity provider should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_batch_account_logging_enabled.yaml b/compliance/controls/azure/azure_batch_account_logging_enabled.yaml old mode 100755 new mode 100644 index ce6fa2e13..25b214831 --- a/compliance/controls/azure/azure_batch_account_logging_enabled.yaml +++ b/compliance/controls/azure/azure_batch_account_logging_enabled.yaml @@ -1,14 +1,62 @@ +Description: Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised. ID: azure_batch_account_logging_enabled -Title: "Resource logs in Batch accounts should be enabled" -Description: "Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n distinct name as account_name\n from\n azure_batch_account,\n jsonb_array_elements(diagnostic_settings) setting,\n jsonb_array_elements(setting -> 'properties' -> 'logs') log\n where\n diagnostic_settings is not null\n and (\n (\n (log ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy' ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy') :: JSONB ? 'days'\n )\n or\n (\n (log ->> 'enabled') :: boolean\n and (\n log -> 'retentionPolicy' ->> 'enabled' <> 'true'\n or setting -> 'properties' ->> 'storageAccountId' = ''\n )\n )\n )\n)\nselect\n v.id as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when v.diagnostic_settings is null then 'alarm'\n when l.account_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when v.diagnostic_settings is null then v.name || ' logging not enabled.'\n when l.account_name is null then v.name || ' logging not enabled.'\n else v.name || ' logging enabled.'\n end as reason\n \n , v.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_batch_account as v\n left join logging_details as l on v.name = l.account_name,\n azure_subscription as sub\nwhere\n sub.subscription_id = v.subscription_id;\n" - PrimaryTable: azure_batch_account ListOfTables: - azure_batch_account - azure_subscription Parameters: [] + PrimaryTable: azure_batch_account + QueryToExecute: | + WITH logging_details AS ( + SELECT + DISTINCT name AS account_name + FROM + azure_batch_account, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND ( + ( + (log ->> 'enabled')::boolean + AND (log -> 'retentionPolicy' ->> 'enabled')::boolean + AND (log -> 'retentionPolicy')::JSONB ? 'days' + ) + OR + ( + (log ->> 'enabled')::boolean + AND ( + log -> 'retentionPolicy' ->> 'enabled' <> 'true' + OR setting -> 'properties' ->> 'storageAccountId' = '' + ) + ) + ) + ) + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.account_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.account_name IS NULL THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_batch_account AS v + LEFT JOIN logging_details AS l ON v.name = l.account_name, + azure_subscription AS sub + WHERE + sub.subscription_id = v.subscription_id Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +65,4 @@ Tags: - "true" service: - Azure/Batch -IntegrationType: - - azure_subscription +Title: Resource logs in Batch accounts should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_bot_service_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_bot_service_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index d8e38538c..1e0c5b67e --- a/compliance/controls/azure/azure_bot_service_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_bot_service_encrypted_with_cmk.yaml @@ -1,24 +1,24 @@ +Description: 'Azure Bot Service automatically encrypts your resource to protect your data and meet organizational security and compliance commitments. By default, Microsoft-managed encryption keys are used. For greater flexibility in managing keys or controlling access to your subscription, select customer-managed keys, also known as bring your own key (BYOK). Learn more about Azure Bot Service encryption: https://docs.microsoft.com/azure/bot-service/bot-service-encryption.' ID: azure_bot_service_encrypted_with_cmk -Title: "Bot Service should be encrypted with a customer-managed key" -Description: "Azure Bot Service automatically encrypts your resource to protect your data and meet organizational security and compliance commitments. By default, Microsoft-managed encryption keys are used. For greater flexibility in managing keys or controlling access to your subscription, select customer-managed keys, also known as bring your own key (BYOK). Learn more about Azure Bot Service encryption: https://docs.microsoft.com/azure/bot-service/bot-service-encryption." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Bot Service should be encrypted with a customer-managed key \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_1.yaml b/compliance/controls/azure/azure_cis_v130_1_1.yaml old mode 100755 new mode 100644 index 644f495b9..578b95c74 --- a/compliance/controls/azure/azure_cis_v130_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_1.yaml @@ -1,19 +1,19 @@ +Description: Enable multi-factor authentication for all user credentials who have write access to Azure resources. These include roles like 'Service Co-Administrators', 'Subscription Owners', 'Contributors'. ID: azure_cis_v130_1_1 -Title: "1.1 Ensure that multi-factor authentication is enabled for all privileged users" -Description: "Enable multi-factor authentication for all user credentials who have write access to Azure resources. These include roles like 'Service Co-Administrators', 'Subscription Owners', 'Contributors'." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1 Ensure that multi-factor authentication is enabled for all privileged users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_10.yaml b/compliance/controls/azure/azure_cis_v130_1_10.yaml old mode 100755 new mode 100644 index a21691c9e..c911b0d54 --- a/compliance/controls/azure/azure_cis_v130_1_10.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_10.yaml @@ -1,19 +1,19 @@ +Description: Require administrators to provide consent for the apps before use. ID: azure_cis_v130_1_10 -Title: "1.10 Ensure that 'Users can add gallery apps to their Access Panel' is set to 'No'" -Description: "Require administrators to provide consent for the apps before use." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.10 Ensure that 'Users can add gallery apps to their Access Panel' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_11.yaml b/compliance/controls/azure/azure_cis_v130_1_11.yaml old mode 100755 new mode 100644 index 6e6d888ef..a9152219f --- a/compliance/controls/azure/azure_cis_v130_1_11.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_11.yaml @@ -1,19 +1,19 @@ +Description: Require administrators to register third-party applications. ID: azure_cis_v130_1_11 -Title: "1.11 Ensure that 'Users can register applications' is set to 'No'" -Description: "Require administrators to register third-party applications." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.11 Ensure that 'Users can register applications' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_12.yaml b/compliance/controls/azure/azure_cis_v130_1_12.yaml old mode 100755 new mode 100644 index 88ff57c86..f9241df3a --- a/compliance/controls/azure/azure_cis_v130_1_12.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_12.yaml @@ -1,19 +1,19 @@ +Description: Limit guest user permissions. ID: azure_cis_v130_1_12 -Title: "1.12 Ensure that 'Guest user permissions are limited' is set to 'Yes'" -Description: "Limit guest user permissions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.12 Ensure that 'Guest user permissions are limited' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_13.yaml b/compliance/controls/azure/azure_cis_v130_1_13.yaml old mode 100755 new mode 100644 index 29336e68a..276f66e67 --- a/compliance/controls/azure/azure_cis_v130_1_13.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_13.yaml @@ -1,19 +1,19 @@ +Description: Restrict invitations to administrators only. ID: azure_cis_v130_1_13 -Title: "1.13 Ensure that 'Members can invite' is set to 'No'" -Description: "Restrict invitations to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.13 Ensure that 'Members can invite' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_14.yaml b/compliance/controls/azure/azure_cis_v130_1_14.yaml old mode 100755 new mode 100644 index 2a1e8f782..8a9e5cbc1 --- a/compliance/controls/azure/azure_cis_v130_1_14.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_14.yaml @@ -1,19 +1,19 @@ +Description: Restrict guest being able to invite other guests to collaborate with your organization. ID: azure_cis_v130_1_14 -Title: "1.14 Ensure that 'Guests can invite' is set to 'No'" -Description: "Restrict guest being able to invite other guests to collaborate with your organization." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.14 Ensure that 'Guests can invite' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_15.yaml b/compliance/controls/azure/azure_cis_v130_1_15.yaml old mode 100755 new mode 100644 index e80c90ef9..38e1b18d4 --- a/compliance/controls/azure/azure_cis_v130_1_15.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_15.yaml @@ -1,19 +1,19 @@ +Description: Restrict access to the Azure AD administration portal to administrators only. ID: azure_cis_v130_1_15 -Title: "1.15 Ensure that 'Restrict access to Azure AD administration portal' is set to 'Yes'" -Description: "Restrict access to the Azure AD administration portal to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.15 Ensure that 'Restrict access to Azure AD administration portal' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_16.yaml b/compliance/controls/azure/azure_cis_v130_1_16.yaml old mode 100755 new mode 100644 index ec7485249..4ea5d2a93 --- a/compliance/controls/azure/azure_cis_v130_1_16.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_16.yaml @@ -1,19 +1,19 @@ +Description: Restrict group creation to administrators only. ID: azure_cis_v130_1_16 -Title: "1.16 Ensure that 'Restrict user ability to access groups features in the Access Pane' is set to 'No'" -Description: "Restrict group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.16 Ensure that 'Restrict user ability to access groups features in the Access Pane' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_17.yaml b/compliance/controls/azure/azure_cis_v130_1_17.yaml old mode 100755 new mode 100644 index 644c3b079..b892dafbb --- a/compliance/controls/azure/azure_cis_v130_1_17.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_17.yaml @@ -1,19 +1,19 @@ +Description: Restrict security group creation to administrators only. ID: azure_cis_v130_1_17 -Title: "1.17 Ensure that 'Users can create security groups in Azure Portals' is set to 'No'" -Description: "Restrict security group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.17 Ensure that 'Users can create security groups in Azure Portals' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_18.yaml b/compliance/controls/azure/azure_cis_v130_1_18.yaml old mode 100755 new mode 100644 index 64d7d99d8..11334c2a9 --- a/compliance/controls/azure/azure_cis_v130_1_18.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_18.yaml @@ -1,19 +1,19 @@ +Description: Restrict security group management to administrators only. ID: azure_cis_v130_1_18 -Title: "1.18 Ensure that 'Owners can manage group membership requests in the Access Panel' is set to 'No'" -Description: "Restrict security group management to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.18 Ensure that 'Owners can manage group membership requests in the Access Panel' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_19.yaml b/compliance/controls/azure/azure_cis_v130_1_19.yaml old mode 100755 new mode 100644 index 5d6f086c4..a951d4314 --- a/compliance/controls/azure/azure_cis_v130_1_19.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_19.yaml @@ -1,19 +1,19 @@ +Description: Restrict Microsoft 365 group creation to administrators only. ID: azure_cis_v130_1_19 -Title: "1.19 Ensure that 'Users can create Microsoft 365 groups in Azure Portals' is set to 'No'" -Description: "Restrict Microsoft 365 group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.19 Ensure that 'Users can create Microsoft 365 groups in Azure Portals' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_2.yaml b/compliance/controls/azure/azure_cis_v130_1_2.yaml old mode 100755 new mode 100644 index 7d757bf15..0ee154da3 --- a/compliance/controls/azure/azure_cis_v130_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_2.yaml @@ -1,19 +1,19 @@ +Description: Enable multi-factor authentication for all non-privileged users. ID: azure_cis_v130_1_2 -Title: "1.2 Ensure that multi-factor authentication is enabled for all non- privileged users" -Description: "Enable multi-factor authentication for all non-privileged users." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2 Ensure that multi-factor authentication is enabled for all non-privileged users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_20.yaml b/compliance/controls/azure/azure_cis_v130_1_20.yaml old mode 100755 new mode 100644 index 60ee4cd8b..54413f2c6 --- a/compliance/controls/azure/azure_cis_v130_1_20.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_20.yaml @@ -1,19 +1,19 @@ +Description: Joining devices to the active directory should require Multi-factor authentication. ID: azure_cis_v130_1_20 -Title: "1.20 Ensure that 'Require Multi-Factor Auth to join devices' is set to 'Yes'" -Description: "Joining devices to the active directory should require Multi-factor authentication." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.20 Ensure that 'Require Multi-Factor Auth to join devices' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_21.yaml b/compliance/controls/azure/azure_cis_v130_1_21.yaml old mode 100755 new mode 100644 index f86295b7e..0cb3f1d72 --- a/compliance/controls/azure/azure_cis_v130_1_21.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_21.yaml @@ -1,53 +1,53 @@ +Description: Subscription ownership should not include permission to create custom owner roles. The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access. ID: azure_cis_v130_1_21 -Title: "1.21 Ensure that no custom subscription owner roles are created" -Description: "Subscription ownership should not include permission to create custom owner roles. The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with owner_custom_roles as ( - select + ListOfTables: + - azure_role_definition + - azure_subscription + Parameters: [] + PrimaryTable: azure_role_definition + QueryToExecute: | + WITH owner_custom_roles AS ( + SELECT role_name, role_type, title, action, _ctx, subscription_id - from + FROM azure_role_definition, - jsonb_array_elements(permissions) as s, - jsonb_array_elements_text(s -> 'actions') as action - where + jsonb_array_elements(permissions) AS s, + jsonb_array_elements_text(s -> 'actions') AS action + WHERE role_type = 'CustomRole' - and action in ('*', '*:*') + AND action IN ('*', '*:*') ) - select - cr.subscription_id as resource, - cr.og_account_id as og_account_id, - cr.og_resource_id as og_resource_id, - case - when count(*) > 0 then 'alarm' - else 'ok' - end as status, - case - when count(*) = 1 then 'There is one custom owner role.' - when count(*) > 1 then 'There are ' || count(*) || ' custom owner roles.' - else 'There are no custom owner roles.' - end as reason - from + SELECT + cr.subscription_id AS resource, + cr.og_account_id AS og_account_id, + cr.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(*) > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(*) = 1 THEN 'There is one custom owner role.' + WHEN COUNT(*) > 1 THEN 'There are ' || COUNT(*) || ' custom owner roles.' + ELSE 'There are no custom owner roles.' + END AS reason + FROM owner_custom_roles cr, azure_subscription sub - where + WHERE sub.subscription_id = cr.subscription_id - group by + GROUP BY cr.subscription_id, cr._ctx, sub.display_name; - PrimaryTable: azure_role_definition - ListOfTables: - - azure_role_definition - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.21 Ensure that no custom subscription owner roles are created \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_22.yaml b/compliance/controls/azure/azure_cis_v130_1_22.yaml old mode 100755 new mode 100644 index 8a97d9999..143a20107 --- a/compliance/controls/azure/azure_cis_v130_1_22.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_22.yaml @@ -1,19 +1,19 @@ +Description: Security defaults in Azure Active Directory (Azure AD) make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks. ID: azure_cis_v130_1_22 -Title: "1.22 Ensure Security Defaults is enabled on Azure Active Directory" -Description: "Security defaults in Azure Active Directory (Azure AD) make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.22 Ensure Security Defaults is enabled on Azure Active Directory \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_23.yaml b/compliance/controls/azure/azure_cis_v130_1_23.yaml old mode 100755 new mode 100644 index ee14bd94b..98ea8d3f6 --- a/compliance/controls/azure/azure_cis_v130_1_23.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_23.yaml @@ -1,19 +1,19 @@ +Description: Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration. ID: azure_cis_v130_1_23 -Title: "1.23 Ensure Custom Role is assigned for Administering Resource Locks" -Description: "Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.23 Ensure Custom Role is assigned for Administering Resource Locks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_3.yaml b/compliance/controls/azure/azure_cis_v130_1_3.yaml old mode 100755 new mode 100644 index b587d382a..719b9648c --- a/compliance/controls/azure/azure_cis_v130_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_3.yaml @@ -1,42 +1,42 @@ +Description: Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Guest users should be review on a monthly basis to ensure that inactive and unneeded accounts are removed. ID: azure_cis_v130_1_3 -Title: "1.3 Ensure guest users are reviewed on a monthly basis" -Description: "Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Guest users should be review on a monthly basis to ensure that inactive and unneeded accounts are removed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_user + Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - u.display_name as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when not account_enabled then 'alarm' - when u.created_date_time::timestamp <= (current_date - interval '30' day) then 'alarm' - else 'ok' - end as status, - case - when not account_enabled then 'Guest user ''' || u.display_name || ''' inactive.' - else 'Guest user ''' || u.display_name || ''' was created ' || extract(day from current_timestamp - u.created_date_time::timestamp) || ' days ago.' - end as reason, + SELECT + u.display_name AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN NOT account_enabled THEN 'alarm' + WHEN u.created_date_time::TIMESTAMP <= (CURRENT_DATE - INTERVAL '30' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT account_enabled THEN 'Guest user ''' || u.display_name || ''' inactive.' + ELSE 'Guest user ''' || u.display_name || ''' was created ' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - u.created_date_time::TIMESTAMP) || ' days ago.' + END AS reason, t.tenant_id - from - azuread_user as u - left join distinct_tenant as t on t.tenant_id = u.tenant_id - where + FROM + azuread_user AS u + LEFT JOIN distinct_tenant AS t ON t.tenant_id = u.tenant_id + WHERE u.user_type = 'Guest'; - PrimaryTable: azuread_user - ListOfTables: - - azure_tenant - - azuread_user - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.3 Ensure guest users are reviewed on a monthly basis \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_4.yaml b/compliance/controls/azure/azure_cis_v130_1_4.yaml old mode 100755 new mode 100644 index e47118183..ccc5470c5 --- a/compliance/controls/azure/azure_cis_v130_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_4.yaml @@ -1,19 +1,19 @@ +Description: Do not allow users to remember multi-factor authentication on devices. ID: azure_cis_v130_1_4 -Title: "1.4 Ensure that 'Allow users to remember multi-factor authentication on devices they trust' is 'Disabled'" -Description: "Do not allow users to remember multi-factor authentication on devices." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.4 Ensure that 'Allow users to remember multi-factor authentication on devices they trust' is 'Disabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_5.yaml b/compliance/controls/azure/azure_cis_v130_1_5.yaml old mode 100755 new mode 100644 index 622bf498b..988362c21 --- a/compliance/controls/azure/azure_cis_v130_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_5.yaml @@ -1,19 +1,19 @@ +Description: Ensure that two alternate forms of identification are provided before allowing a password reset. ID: azure_cis_v130_1_5 -Title: "1.5 Ensure that 'Number of methods required to reset' is set to '2'" -Description: "Ensure that two alternate forms of identification are provided before allowing a password reset." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.5 Ensure that 'Number of methods required to reset' is set to '2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_6.yaml b/compliance/controls/azure/azure_cis_v130_1_6.yaml old mode 100755 new mode 100644 index b08a5df0a..e51234890 --- a/compliance/controls/azure/azure_cis_v130_1_6.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_6.yaml @@ -1,19 +1,19 @@ +Description: Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0. ID: azure_cis_v130_1_6 -Title: "1.6 Ensure that 'Number of days before users are asked to re-confirm their authentication information' is not set to 0" -Description: "Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.6 Ensure that 'Number of days before users are asked to re-confirm their authentication information' is not set to 0 \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_7.yaml b/compliance/controls/azure/azure_cis_v130_1_7.yaml old mode 100755 new mode 100644 index bab22c36e..e1418d607 --- a/compliance/controls/azure/azure_cis_v130_1_7.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_7.yaml @@ -1,19 +1,19 @@ +Description: Ensure that users are notified on their primary and secondary emails on password resets. ID: azure_cis_v130_1_7 -Title: "1.7 Ensure that 'Notify users on password resets?' is set to 'Yes'" -Description: "Ensure that users are notified on their primary and secondary emails on password resets." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.7 Ensure that 'Notify users on password resets?' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_8.yaml b/compliance/controls/azure/azure_cis_v130_1_8.yaml old mode 100755 new mode 100644 index ffef15dbe..6aa86ce78 --- a/compliance/controls/azure/azure_cis_v130_1_8.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_8.yaml @@ -1,19 +1,19 @@ +Description: Ensure that all administrators are notified if any other administrator resets their password. ID: azure_cis_v130_1_8 -Title: "1.8 Ensure that 'Notify all admins when other admins reset their password?' is set to 'Yes'" -Description: "Ensure that all administrators are notified if any other administrator resets their password." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.8 Ensure that 'Notify all admins when other admins reset their password?' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_1_9.yaml b/compliance/controls/azure/azure_cis_v130_1_9.yaml old mode 100755 new mode 100644 index c43b0286b..cca01123d --- a/compliance/controls/azure/azure_cis_v130_1_9.yaml +++ b/compliance/controls/azure/azure_cis_v130_1_9.yaml @@ -1,19 +1,19 @@ +Description: Require administrators to provide consent for the apps before use. ID: azure_cis_v130_1_9 -Title: "1.9 Ensure that 'Users can consent to apps accessing company data on their behalf' is set to 'No'" -Description: "Require administrators to provide consent for the apps before use." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.9 Ensure that 'Users can consent to apps accessing company data on their behalf' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_1.yaml b/compliance/controls/azure/azure_cis_v130_2_1.yaml old mode 100755 new mode 100644 index 3da7930f8..2a82a4e51 --- a/compliance/controls/azure/azure_cis_v130_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_1.yaml @@ -1,32 +1,32 @@ +Description: Turning on Azure Defender enables threat detection for Server, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center. ID: azure_cis_v130_2_1 -Title: "2.1 Ensure that Azure Defender is set to On for Servers" -Description: "Turning on Azure Defender enables threat detection for Server, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Servers.' - else 'Azure Defender off for Servers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'VirtualMachines'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Servers.' + ELSE 'Azure Defender off for Servers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'VirtualMachines'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1 Ensure that Azure Defender is set to On for Servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_10.yaml b/compliance/controls/azure/azure_cis_v130_2_10.yaml old mode 100755 new mode 100644 index 596c965b1..f1a22ec5d --- a/compliance/controls/azure/azure_cis_v130_2_10.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_10.yaml @@ -1,32 +1,33 @@ +Description: This setting enables Microsoft Cloud App Security (MCAS) integration with Security Center. ID: azure_cis_v130_2_10 -Title: "2.10 Ensure that Microsoft Cloud App Security (MCAS) integration with Security Center is selected" -Description: "This setting enables Microsoft Cloud App Security (MCAS) integration with Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_sett.id as resource, - sc_sett.og_account_id as og_account_id, - sc_sett.og_resource_id as og_resource_id, - case - when enabled then 'ok' - else 'alarm' - end as status, - case - when enabled then 'Windows Defender ATP (WDATP) integrated with Security Center.' - else 'Windows Defender ATP (WDATP) not integrated with Security Center.' - end as reason - from - azure_security_center_setting sc_sett - right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id - where - name = 'MCAS'; - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Windows Defender ATP (WDATP) integrated with Security Center.' + ELSE 'Windows Defender ATP (WDATP) not integrated with Security Center.' + END AS reason + FROM + azure_security_center_setting sc_sett + RIGHT JOIN + azure_subscription sub ON sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'MCAS'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.10 Ensure that Microsoft Cloud App Security (MCAS) integration with Security Center is selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_11.yaml b/compliance/controls/azure/azure_cis_v130_2_11.yaml old mode 100755 new mode 100644 index 56f52881e..c1d94b5f9 --- a/compliance/controls/azure/azure_cis_v130_2_11.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_11.yaml @@ -1,15 +1,33 @@ +Description: Enable automatic provisioning of the monitoring agent to collect security data. ID: azure_cis_v130_2_11 -Title: "2.11 Ensure that 'Automatic provisioning of monitoring agent' is set to 'On'" -Description: "Enable automatic provisioning of the monitoring agent to collect security data." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sc_prov.id as resource,\n sc_prov.og_account_id as og_account_id,\n sc_prov.og_resource_id as og_resource_id,\n case\n when auto_provision = 'On' then 'ok'\n else 'alarm'\n end as status,\n case\n when auto_provision = 'On' then 'Automatic provisioning of monitoring agent is on.'\n else 'Automatic provisioning of monitoring agent is off.'\n end as reason\n \n \nfrom\n azure_security_center_auto_provisioning sc_prov\n right join azure_subscription sub on sc_prov.subscription_id = sub.subscription_id;" - PrimaryTable: azure_security_center_auto_provisioning ListOfTables: - azure_security_center_auto_provisioning - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_auto_provisioning + QueryToExecute: | + SELECT + sc_prov.id AS resource, + sc_prov.og_account_id AS og_account_id, + sc_prov.og_resource_id AS og_resource_id, + CASE + WHEN auto_provision = 'On' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_provision = 'On' THEN 'Automatic provisioning of monitoring agent is on.' + ELSE 'Automatic provisioning of monitoring agent is off.' + END AS reason + FROM + azure_security_center_auto_provisioning sc_prov + RIGHT JOIN + azure_subscription sub + ON + sc_prov.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.11 Ensure that 'Automatic provisioning of monitoring agent' is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_12.yaml b/compliance/controls/azure/azure_cis_v130_2_12.yaml old mode 100755 new mode 100644 index c5bf3f3b4..3e4ea4a5f --- a/compliance/controls/azure/azure_cis_v130_2_12.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_12.yaml @@ -1,50 +1,51 @@ +Description: None of the settings offered by ASC Default policy should be set to effect Disabled. ID: azure_cis_v130_2_12 -Title: "2.12 Ensure any of the ASC Default policy setting is not set to Disabled" -Description: "None of the settings offered by ASC Default policy should be set to effect Disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with policy_assignment_parameters as ( - select + ListOfTables: + - azure_policy_assignment + - azure_subscription + Parameters: [] + PrimaryTable: azure_policy_assignment + QueryToExecute: | + WITH policy_assignment_parameters AS ( + SELECT id, name, key, - parameters -> key ->> 'value' as value, + parameters -> key ->> 'value' AS value, subscription_id - from + FROM azure_policy_assignment, - jsonb_object_keys(parameters) as key - where + jsonb_object_keys(parameters) AS key + WHERE name = 'SecurityCenterBuiltIn' ) - select - sub.id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(value = 'Disabled') > 0 then 'alarm' - else 'ok' - end as status, - case - when count(value = 'Disabled') > 0 then 'Settings disabled for ' || count(*) filter (where value = 'Disabled') || ' parameters.' - else 'Settings enabled for all the parameters.' - end as reason - from + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(value = 'Disabled') > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(value = 'Disabled') > 0 THEN 'Settings disabled for ' || COUNT(*) FILTER (WHERE value = 'Disabled') || ' parameters.' + ELSE 'Settings enabled for all the parameters.' + END AS reason + FROM policy_assignment_parameters pol_assignment - right join azure_subscription sub on pol_assignment.subscription_id = sub.subscription_id - group by + RIGHT JOIN azure_subscription sub + ON pol_assignment.subscription_id = sub.subscription_id + GROUP BY sub.id, pol_assignment.id, sub._ctx, sub.subscription_id, pol_assignment.subscription_id, sub.display_name; - PrimaryTable: azure_policy_assignment - ListOfTables: - - azure_policy_assignment - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.12 Ensure any of the ASC Default policy setting is not set to Disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_13.yaml b/compliance/controls/azure/azure_cis_v130_2_13.yaml old mode 100755 new mode 100644 index e54e13583..85133cb04 --- a/compliance/controls/azure/azure_cis_v130_2_13.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_13.yaml @@ -1,44 +1,44 @@ +Description: Security Center emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address. ID: azure_cis_v130_2_13 -Title: "2.13 Ensure 'Additional email addresses' is configured with a security contact email" -Description: "Security Center emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with contact_info as ( - select - jsonb_agg(email) filter (where name = 'default' and email != '') as default_email, - count(*) filter (where name != 'default') as non_default_count, - count(*) filter (where name = 'default') as default_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_security_center_contact + QueryToExecute: | + WITH contact_info AS ( + SELECT + jsonb_agg(email) FILTER (WHERE name = 'default' AND email != '') AS default_email, + COUNT(*) FILTER (WHERE name != 'default') AS non_default_count, + COUNT(*) FILTER (WHERE name = 'default') AS default_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when non_default_count > 0 then 'ok' - when default_count = 1 and jsonb_array_length(default_email) != 0 then 'ok' - else 'alarm' - end as status, - case - when non_default_count > 0 then 'Additional email addresses configured.' - when default_count = 1 and default_email is not null then 'Additional email addresses configured.' - else 'Additional email addresses not configured.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN non_default_count > 0 THEN 'ok' + WHEN default_count = 1 AND jsonb_array_length(default_email) != 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN non_default_count > 0 THEN 'Additional email addresses configured.' + WHEN default_count = 1 AND default_email IS NOT NULL THEN 'Additional email addresses configured.' + ELSE 'Additional email addresses not configured.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - PrimaryTable: azure_security_center_contact - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.13 Ensure 'Additional email addresses' is configured with a security contact email \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_14.yaml b/compliance/controls/azure/azure_cis_v130_2_14.yaml old mode 100755 new mode 100644 index b323ec683..7cc4b902d --- a/compliance/controls/azure/azure_cis_v130_2_14.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_14.yaml @@ -1,42 +1,40 @@ +Description: Enables emailing security alerts to the subscription owner or other designated security contact. ID: azure_cis_v130_2_14 -Title: "2.14 Ensure that 'Notify about alerts with the following severity' is set to 'High'" -Description: "Enables emailing security alerts to the subscription owner or other designated security contact." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with contact_info as ( - select - count(*) filter (where alert_notifications = 'On') as notification_alert_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alert_notifications = 'On') AS notification_alert_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when notification_alert_count > 0 then 'ok' - else 'alarm' - end as status, - case - when notification_alert_count > 0 then '"Notify about alerts with the following severity" set to High.' - else '"Notify about alerts with the following severity" not set to High.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN notification_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN notification_alert_count > 0 THEN '"Notify about alerts with the following severity" set to High.' + ELSE '"Notify about alerts with the following severity" not set to High.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - ``` - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.14 Ensure that 'Notify about alerts with the following severity' is set to 'High' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_15.yaml b/compliance/controls/azure/azure_cis_v130_2_15.yaml old mode 100755 new mode 100644 index 4ccfcb48a..225e841f0 --- a/compliance/controls/azure/azure_cis_v130_2_15.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_15.yaml @@ -1,42 +1,40 @@ +Description: Enable security alert emails to subscription owners. ID: azure_cis_v130_2_15 -Title: "2.15 Ensure that 'All users with the following roles' is set to 'Owner'" -Description: "Enable security alert emails to subscription owners." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with contact_info as ( - select - count(*) filter (where alerts_to_admins = 'On') as admin_alert_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alerts_to_admins = 'On') AS admin_alert_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when admin_alert_count > 0 then 'ok' - else 'alarm' - end as status, - case - when admin_alert_count > 0 then '"All users with the following roles" set to Owner' - else '"All users with the following roles" not set to Owner.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN admin_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN admin_alert_count > 0 THEN '"All users with the following roles" set to Owner' + ELSE '"All users with the following roles" not set to Owner.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - ``` - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.15 Ensure that 'All users with the following roles' is set to 'Owner' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_2.yaml b/compliance/controls/azure/azure_cis_v130_2_2.yaml old mode 100755 new mode 100644 index e7655252c..d5aafb788 --- a/compliance/controls/azure/azure_cis_v130_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_2.yaml @@ -1,32 +1,35 @@ +Description: Turning on Azure Defender enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center. ID: azure_cis_v130_2_2 -Title: "2.2 Ensure that Azure Defender is set to On for App Service" -Description: "Turning on Azure Defender enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for App Services.' - else 'Azure Defender off for App Services.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'AppServices'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for App Services.' + ELSE 'Azure Defender off for App Services.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'AppServices'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.2 Ensure that Azure Defender is set to On for App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_3.yaml b/compliance/controls/azure/azure_cis_v130_2_3.yaml old mode 100755 new mode 100644 index df702d4ae..1ee99258c --- a/compliance/controls/azure/azure_cis_v130_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_3.yaml @@ -1,32 +1,33 @@ +Description: Turning on Azure Defender enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center. ID: azure_cis_v130_2_3 -Title: "2.3 Ensure that Azure Defender is set to On for Azure SQL database servers" -Description: "Turning on Azure Defender enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for SQL database servers.' - else 'Azure Defender off for SQL database servers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'SqlServers'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL database servers.' + ELSE 'Azure Defender off for SQL database servers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServers'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.3 Ensure that Azure Defender is set to On for Azure SQL database servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_4.yaml b/compliance/controls/azure/azure_cis_v130_2_4.yaml old mode 100755 new mode 100644 index a0dc56915..45bd14c97 --- a/compliance/controls/azure/azure_cis_v130_2_4.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_4.yaml @@ -1,32 +1,33 @@ +Description: Turning on Azure Defender enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center. ID: azure_cis_v130_2_4 -Title: "2.4 Ensure that Azure Defender is set to On for SQL servers on machines" -Description: "Turning on Azure Defender enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for SQL servers on machines.' - else 'Azure Defender off for SQL servers on machines.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'SqlServerVirtualMachines'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL servers on machines.' + ELSE 'Azure Defender off for SQL servers on machines.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServerVirtualMachines'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.4 Ensure that Azure Defender is set to On for SQL servers on machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_5.yaml b/compliance/controls/azure/azure_cis_v130_2_5.yaml old mode 100755 new mode 100644 index 04c987852..b247ddd2f --- a/compliance/controls/azure/azure_cis_v130_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_5.yaml @@ -1,32 +1,33 @@ +Description: Turning on Azure Defender enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center. ID: azure_cis_v130_2_5 -Title: "2.5 Ensure that Azure Defender is set to On for Storage" -Description: "Turning on Azure Defender enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Storage.' - else 'Azure Defender off for Storage.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'StorageAccounts'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Storage.' + ELSE 'Azure Defender off for Storage.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'StorageAccounts'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.5 Ensure that Azure Defender is set to On for Storage \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_6.yaml b/compliance/controls/azure/azure_cis_v130_2_6.yaml old mode 100755 new mode 100644 index a848da6ed..7774fe921 --- a/compliance/controls/azure/azure_cis_v130_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_6.yaml @@ -1,32 +1,32 @@ +Description: Turning on Azure Defender enables threat detection for Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center. ID: azure_cis_v130_2_6 -Title: "2.6 Ensure that Azure Defender is set to On for Kubernetes" -Description: "Turning on Azure Defender enables threat detection for Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Kubernetes.' - else 'Azure Defender off for Kubernetes.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'KubernetesService'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Kubernetes.' + ELSE 'Azure Defender off for Kubernetes.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'KubernetesService'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.6 Ensure that Azure Defender is set to On for Kubernetes \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_7.yaml b/compliance/controls/azure/azure_cis_v130_2_7.yaml old mode 100755 new mode 100644 index 361951463..1b6f02305 --- a/compliance/controls/azure/azure_cis_v130_2_7.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_7.yaml @@ -1,32 +1,33 @@ +Description: Turning on Azure Defender enables threat detection for Container Registries, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center. ID: azure_cis_v130_2_7 -Title: "2.7 Ensure that Azure Defender is set to On for Container Registries" -Description: "Turning on Azure Defender enables threat detection for Container Registries, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Container Registry.' - else 'Azure Defender off for Container Registry.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'ContainerRegistry'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Container Registry.' + ELSE 'Azure Defender off for Container Registry.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'ContainerRegistry'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.7 Ensure that Azure Defender is set to On for Container Registries \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_8.yaml b/compliance/controls/azure/azure_cis_v130_2_8.yaml old mode 100755 new mode 100644 index de2d7acbf..b1dc7ed5d --- a/compliance/controls/azure/azure_cis_v130_2_8.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_8.yaml @@ -1,32 +1,33 @@ +Description: Turning on Azure Defender enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center. ID: azure_cis_v130_2_8 -Title: "2.8 Ensure that Azure Defender is set to On for Key Vault" -Description: "Turning on Azure Defender enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Azure Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Key Vaults.' - else 'Azure Defender off for Key Vaults.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'KeyVaults'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Key Vaults.' + ELSE 'Azure Defender off for Key Vaults.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'KeyVaults'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.8 Ensure that Azure Defender is set to On for Key Vault \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_2_9.yaml b/compliance/controls/azure/azure_cis_v130_2_9.yaml old mode 100755 new mode 100644 index c1da9e5cc..e1727c6f2 --- a/compliance/controls/azure/azure_cis_v130_2_9.yaml +++ b/compliance/controls/azure/azure_cis_v130_2_9.yaml @@ -1,32 +1,32 @@ +Description: This setting enables Windows Defender ATP (WDATP) integration with Security Center. ID: azure_cis_v130_2_9 -Title: "2.9 Ensure that Windows Defender ATP (WDATP) integration with Security Center is selected" -Description: "This setting enables Windows Defender ATP (WDATP) integration with Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_sett.id as resource, - sc_sett.og_account_id as og_account_id, - sc_sett.og_resource_id as og_resource_id, - case - when enabled then 'ok' - else 'alarm' - end as status, - case - when enabled then 'Microsoft Cloud App Security (MCAS) integrated with Security Center.' - else 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.' - end as reason - from - azure_security_center_setting sc_sett - right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id - where - name = 'WDATP'; - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Microsoft Cloud App Security (MCAS) integrated with Security Center.' + ELSE 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.' + END AS reason + FROM + azure_security_center_setting sc_sett + RIGHT JOIN azure_subscription sub ON sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'WDATP'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.9 Ensure that Windows Defender ATP (WDATP) integration with Security Center is selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_3_1.yaml b/compliance/controls/azure/azure_cis_v130_3_1.yaml old mode 100755 new mode 100644 index 0b98cdae3..e58f9a71a --- a/compliance/controls/azure/azure_cis_v130_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v130_3_1.yaml @@ -1,32 +1,32 @@ +Description: Enable data encryption in transit. ID: azure_cis_v130_3_1 -Title: "3.1 Ensure that 'Secure transfer required' is set to 'Enabled'" -Description: "Enable data encryption in transit." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not enable_https_traffic_only then 'alarm' - else 'ok' - end as status, - case - when not enable_https_traffic_only then sa.name || ' encryption in transit not enabled.' - else sa.name || ' encryption in transit enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT enable_https_traffic_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT enable_https_traffic_only THEN sa.name || ' encryption in transit not enabled.' + ELSE sa.name || ' encryption in transit enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.1 Ensure that 'Secure transfer required' is set to 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_3_10.yaml b/compliance/controls/azure/azure_cis_v130_3_10.yaml old mode 100755 new mode 100644 index 55a4a510b..631b9aced --- a/compliance/controls/azure/azure_cis_v130_3_10.yaml +++ b/compliance/controls/azure/azure_cis_v130_3_10.yaml @@ -1,41 +1,41 @@ +Description: 'The Storage Blob service provides scalable, cost-efficient objective storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information, and the sizes of the request and response messages.' ID: azure_cis_v130_3_10 -Title: "3.10 Ensure Storage logging is enabled for Blob service for read, write, and delete requests" -Description: "The Storage Blob service provides scalable, cost-efficient objective storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details , concurrency information and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not (sa.blob_service_logging ->> 'Read') :: boolean - or not (sa.blob_service_logging ->> 'Write') :: boolean - or not (sa.blob_service_logging ->> 'Delete') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (sa.blob_service_logging ->> 'Read') :: boolean - or not (sa.blob_service_logging ->> 'Write') :: boolean - or not (sa.blob_service_logging ->> 'Delete') :: boolean then name || ' blob service logging not enabled for ' || - concat_ws(', ', - case when not (sa.blob_service_logging ->> 'Write') :: boolean then 'write' end, - case when not (sa.blob_service_logging ->> 'Read') :: boolean then 'read' end, - case when not (sa.blob_service_logging ->> 'Delete') :: boolean then 'delete' end - ) || ' requests.' - else name || ' blob service logging enabled for read, write, delete requests.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read') :: BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write') :: BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete') :: BOOLEAN THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read') :: BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write') :: BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete') :: BOOLEAN THEN name || ' blob service logging not enabled for ' || + CONCAT_WS(', ', + CASE WHEN NOT (sa.blob_service_logging ->> 'Write') :: BOOLEAN THEN 'write' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Read') :: BOOLEAN THEN 'read' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Delete') :: BOOLEAN THEN 'delete' END + ) || ' requests.' + ELSE name || ' blob service logging enabled for read, write, delete requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.10 Ensure Storage logging is enabled for Blob service for read, write, and delete requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_3_11.yaml b/compliance/controls/azure/azure_cis_v130_3_11.yaml old mode 100755 new mode 100644 index 4ad09a5f2..70437a5d2 --- a/compliance/controls/azure/azure_cis_v130_3_11.yaml +++ b/compliance/controls/azure/azure_cis_v130_3_11.yaml @@ -1,24 +1,24 @@ +Description: 'The Storage Table storage is a service that stores structure NoSQL data in the cloud, providing a key/attribute store with a schema less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information and the sizes of the request and response messages.' ID: azure_cis_v130_3_11 -Title: "3.11 Ensure Storage logging is enabled for Table service for read, write, and delete requests" -Description: "The Storage Table storage is a service that stores structure NoSQL data in the cloud, providing a key/attribute store with a schema less design. Storage Logging happens server- side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details , concurrency information and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.11 Ensure Storage logging is enabled for Table service for read, write, and delete requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_3_2.yaml b/compliance/controls/azure/azure_cis_v130_3_2.yaml old mode 100755 new mode 100644 index 8e4c34c78..8b518ca7b --- a/compliance/controls/azure/azure_cis_v130_3_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_3_2.yaml @@ -1,24 +1,24 @@ +Description: Regenerate storage account access keys periodically. ID: azure_cis_v130_3_2 -Title: "3.2 Ensure that storage account access keys are periodically regenerated" -Description: "Regenerate storage account access keys periodically." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.2 Ensure that storage account access keys are periodically regenerated \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_3_3.yaml b/compliance/controls/azure/azure_cis_v130_3_3.yaml old mode 100755 new mode 100644 index de2d99765..339fda775 --- a/compliance/controls/azure/azure_cis_v130_3_3.yaml +++ b/compliance/controls/azure/azure_cis_v130_3_3.yaml @@ -1,38 +1,38 @@ +Description: 'The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details , concurrency information and the sizes of the request and response messages.' ID: azure_cis_v130_3_3 -Title: "3.3 Ensure Storage logging is enabled for Queue service for read, write, and delete requests" -Description: "The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details , concurrency information and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when queue_logging_read and queue_logging_write and queue_logging_delete then 'ok' - else 'alarm' - end as status, - case - when queue_logging_read and queue_logging_write and queue_logging_delete - then sa.name || ' queue service logging enabled for read, write, delete requests.' - else sa.name || ' queue service logging not enabled for: ' || - concat_ws(', ', - case when not queue_logging_write then 'write' end, - case when not queue_logging_read then 'read' end, - case when not queue_logging_delete then 'delete' end - ) || ' requests.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete + THEN sa.name || ' queue service logging enabled for read, write, delete requests.' + ELSE sa.name || ' queue service logging not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT queue_logging_write THEN 'write' END, + CASE WHEN NOT queue_logging_read THEN 'read' END, + CASE WHEN NOT queue_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.3 Ensure Storage logging is enabled for Queue service for read, write, and delete requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_3_4.yaml b/compliance/controls/azure/azure_cis_v130_3_4.yaml old mode 100755 new mode 100644 index d7eedcd99..73edb461a --- a/compliance/controls/azure/azure_cis_v130_3_4.yaml +++ b/compliance/controls/azure/azure_cis_v130_3_4.yaml @@ -1,22 +1,22 @@ +Description: A shared access signature (SAS) is a URI that grants restricted access rights to Azure Storage resources. A shared access signature can be provided to clients who should not be trusted with the storage account key but for whom it may be necessary to delegate access to certain storage account resources. Providing a shared access signature URI to these clients allows them access to a resource for a specified period of time. This time should be set as low as possible and preferably no longer than an hour. ID: azure_cis_v130_3_4 -Title: "3.4 Ensure that shared access signature tokens expire within an hour" -Description: "A shared access signature (SAS) is a URI that grants restricted access rights to Azure Storage resources. A shared access signature can be provided to clients who should not be trusted with the storage account key but for whom it may be necessary to delegate access to certain storage account resources. Providing a shared access signature URI to these clients allows them access to a resource for a specified period of time. This time should be set as low as possible and preferably no longer than an hour." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.4 Ensure that shared access signature tokens expire within an hour \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_3_6.yaml b/compliance/controls/azure/azure_cis_v130_3_6.yaml old mode 100755 new mode 100644 index 9c6b3537d..c069e5161 --- a/compliance/controls/azure/azure_cis_v130_3_6.yaml +++ b/compliance/controls/azure/azure_cis_v130_3_6.yaml @@ -1,32 +1,32 @@ +Description: Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed. ID: azure_cis_v130_3_6 -Title: "3.6 Ensure default network access rule for Storage Accounts is set to deny" -Description: "Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when sa.network_rule_default_action = 'Allow' then 'alarm' - else 'ok' - end as status, - case - when sa.network_rule_default_action = 'Allow' then name || ' allows traffic from all networks.' - else name || ' allows traffic from specific networks.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN name || ' allows traffic from all networks.' + ELSE name || ' allows traffic from specific networks.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.6 Ensure default network access rule for Storage Accounts is set to deny \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_3_7.yaml b/compliance/controls/azure/azure_cis_v130_3_7.yaml old mode 100755 new mode 100644 index c55f1a018..d7bf8834a --- a/compliance/controls/azure/azure_cis_v130_3_7.yaml +++ b/compliance/controls/azure/azure_cis_v130_3_7.yaml @@ -1,32 +1,32 @@ +Description: 'Some Microsoft services that interact with storage accounts operate from networks that can''t be granted access through network rules. To help this type of service work as intended, allow the set of trusted Microsoft services to bypass the network rules. These services will then use strong authentication to access the storage account. If the Allow trusted Microsoft services exception is enabled, the following services: Azure Backup, Azure Site Recovery, Azure DevTest Labs, Azure Event Grid, Azure Event Hubs, Azure Networking, Azure Monitor and Azure SQL Data Warehouse (when registered in the subscription), are granted access to the storage account.' ID: azure_cis_v130_3_7 -Title: "3.7 Ensure 'Trusted Microsoft Services' is enabled for Storage Account access" -Description: "Some Microsoft services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Microsoft services to bypass the network rules. These services will then use strong authentication to access the storage account. If the Allow trusted Microsoft services exception is enabled, the following services: Azure Backup, Azure Site Recovery, Azure DevTest Labs, Azure Event Grid, Azure Event Hubs, Azure Networking, Azure Monitor and Azure SQL Data Warehouse (when registered in the subscription), are granted access to the storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when network_rule_bypass not like '%AzureServices%' then 'alarm' - else 'ok' - end as status, - case - when network_rule_bypass not like '%AzureServices%' then sa.name || ' trusted Microsoft services not enabled.' - else sa.name || ' trusted Microsoft services enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN sa.name || ' trusted Microsoft services not enabled.' + ELSE sa.name || ' trusted Microsoft services enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.7 Ensure 'Trusted Microsoft Services' is enabled for Storage Account access \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_3_8.yaml b/compliance/controls/azure/azure_cis_v130_3_8.yaml old mode 100755 new mode 100644 index 589bf67d0..baa4dd108 --- a/compliance/controls/azure/azure_cis_v130_3_8.yaml +++ b/compliance/controls/azure/azure_cis_v130_3_8.yaml @@ -1,32 +1,32 @@ +Description: The Azure Storage blobs contain data like ePHI, Financial, secret or personal. Erroneously modified or deleted accidentally by an application or other storage account user cause data loss or data unavailability. It is recommended the Azure Storage be made recoverable by enabling soft delete configuration. This is to save and recover data when blobs or blob snapshots are deleted. ID: azure_cis_v130_3_8 -Title: "3.8 Ensure soft delete is enabled for Azure Storage" -Description: "The Azure Storage blobs contain data like ePHI, Financial, secret or personal. Erroneously modified or deleted accidentally by an application or other storage account user cause data loss or data unavailability. It is recommended the Azure Storage be made recoverable by enabling soft delete configuration. This is to save and recover data when blobs or blob snapshots are deleted." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not blob_soft_delete_enabled then 'alarm' - else 'ok' - end as status, - case - when not blob_soft_delete_enabled then sa.name || ' blobs soft delete disabled.' - else sa.name || ' blobs soft delete enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT blob_soft_delete_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT blob_soft_delete_enabled THEN sa.name || ' blobs soft delete disabled.' + ELSE sa.name || ' blobs soft delete enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.8 Ensure soft delete is enabled for Azure Storage \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_3_9.yaml b/compliance/controls/azure/azure_cis_v130_3_9.yaml old mode 100755 new mode 100644 index 6a5dfbc92..54d2641f2 --- a/compliance/controls/azure/azure_cis_v130_3_9.yaml +++ b/compliance/controls/azure/azure_cis_v130_3_9.yaml @@ -1,32 +1,32 @@ +Description: Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys ID: azure_cis_v130_3_9 -Title: "3.9 Ensure storage for critical data are encrypted with Customer Managed Key" -Description: "Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when sa.encryption_key_source = 'Microsoft.Storage' then 'alarm' - else 'ok' - end as status, - case - when sa.encryption_key_source = 'Microsoft.Storage' then sa.name || ' not encrypted with CMK.' - else sa.name || ' encrypted with CMK.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN sa.name || ' not encrypted with CMK.' + ELSE sa.name || ' encrypted with CMK.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.9 Ensure storage for critical data are encrypted with Customer Managed Key \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_4_1_2.yaml b/compliance/controls/azure/azure_cis_v130_4_1_2.yaml old mode 100755 new mode 100644 index 1c9033cf5..09354eb04 --- a/compliance/controls/azure/azure_cis_v130_4_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_4_1_2.yaml @@ -1,33 +1,37 @@ -ID: azure_cis_v130_4_1_2 -Title: "4.1.2 Ensure that 'Data encryption' is set to 'On' on a SQL Database" Description: "" +ID: azure_cis_v130_4_1_2 +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.database_id resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then s.title || ' transparent data encryption enabled.' - else s.title || ' transparent data encryption disabled.' - end as reason - from - azure_sql_database as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id - and s.name <> 'master'; - PrimaryTable: azure_sql_database ListOfTables: - azure_sql_database - azure_subscription Parameters: [] + PrimaryTable: azure_sql_database + QueryToExecute: | + SELECT + s.database_id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' + OR transparent_data_encryption ->> 'state' = 'Enabled' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' + OR transparent_data_encryption ->> 'state' = 'Enabled' + THEN s.title || ' transparent data encryption enabled.' + ELSE s.title || ' transparent data encryption disabled.' + END AS reason + FROM + azure_sql_database AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id + AND s.name <> 'master'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.2 Ensure that 'Data encryption' is set to 'On' on a SQL Database \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_4_3_1.yaml b/compliance/controls/azure/azure_cis_v130_4_3_1.yaml old mode 100755 new mode 100644 index 9efc0c301..b21689de5 --- a/compliance/controls/azure/azure_cis_v130_4_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v130_4_3_1.yaml @@ -1,32 +1,32 @@ +Description: Enable SSL connection on PostgreSQL Servers. ID: azure_cis_v130_4_3_1 -Title: "4.3.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for PostgreSQL Database Server" -Description: "Enable SSL connection on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when ssl_enforcement = 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when ssl_enforcement = 'Disabled' then name || ' SSL connection disabled.' - else name || ' SSL connection enabled.' - end as reason - from - azure_postgresql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN name || ' SSL connection disabled.' + ELSE name || ' SSL connection enabled.' + END AS reason + FROM + azure_postgresql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_4_3_2.yaml b/compliance/controls/azure/azure_cis_v130_4_3_2.yaml old mode 100755 new mode 100644 index e210769c1..3e9ee3fc8 --- a/compliance/controls/azure/azure_cis_v130_4_3_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_4_3_2.yaml @@ -1,32 +1,32 @@ +Description: Enable SSL connection on MYSQL Servers. ID: azure_cis_v130_4_3_2 -Title: "4.3.2 Ensure 'Enforce SSL connection' is set to 'ENABLED' for MySQL Database Server" -Description: "Enable SSL connection on MYSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when ssl_enforcement = 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when ssl_enforcement = 'Disabled' then s.name || ' SSL connection disabled.' - else s.name || ' SSL connection enabled.' - end as reason - from - azure_mysql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN s.name || ' SSL connection disabled.' + ELSE s.name || ' SSL connection enabled.' + END AS reason + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.2 Ensure 'Enforce SSL connection' is set to 'ENABLED' for MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_4_3_5.yaml b/compliance/controls/azure/azure_cis_v130_4_3_5.yaml old mode 100755 new mode 100644 index 6d97dd054..3c949822e --- a/compliance/controls/azure/azure_cis_v130_4_3_5.yaml +++ b/compliance/controls/azure/azure_cis_v130_4_3_5.yaml @@ -1,34 +1,34 @@ +Description: Enable log_disconnections on PostgreSQL Servers. ID: azure_cis_v130_4_3_5 -Title: "4.3.5 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_disconnections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm' - else 'ok' - end as status, - case - when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then name || ' server parameter log_disconnections off.' - else name || ' server parameter log_disconnections on.' - end as reason - from - azure_postgresql_server s, - jsonb_array_elements(server_configurations) config, - azure_subscription sub - where - config ->> 'Name' = 'log_disconnections' - and sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN name || ' server parameter log_disconnections off.' + ELSE name || ' server parameter log_disconnections on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_disconnections' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.5 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_4_3_8.yaml b/compliance/controls/azure/azure_cis_v130_4_3_8.yaml old mode 100755 new mode 100644 index 1687fd0ce..a10912a94 --- a/compliance/controls/azure/azure_cis_v130_4_3_8.yaml +++ b/compliance/controls/azure/azure_cis_v130_4_3_8.yaml @@ -1,24 +1,24 @@ +Description: Disable access from Azure services to PostgreSQL Database Server. ID: azure_cis_v130_4_3_8 -Title: "4.3.8 Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled" -Description: "Disable access from Azure services to PostgreSQL Database Server." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 4.3.8 Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_4_4.yaml b/compliance/controls/azure/azure_cis_v130_4_4.yaml old mode 100755 new mode 100644 index 217e38440..39ce4f676 --- a/compliance/controls/azure/azure_cis_v130_4_4.yaml +++ b/compliance/controls/azure/azure_cis_v130_4_4.yaml @@ -1,32 +1,33 @@ +Description: Use Azure Active Directory Authentication for authentication with SQL Database. ID: azure_cis_v130_4_4 -Title: "4.4 Ensure that Azure Active Directory Admin is configured" -Description: "Use Azure Active Directory Authentication for authentication with SQL Database." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when server_azure_ad_administrator is null then 'alarm' - else 'ok' - end as status, - case - when server_azure_ad_administrator is null then name || ' Azure AD authentication not configured.' - else name || ' Azure AD authentication configured.' - end as reason - from - azure_sql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN server_azure_ad_administrator IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN server_azure_ad_administrator IS NULL + THEN name || ' Azure AD authentication not configured.' + ELSE name || ' Azure AD authentication configured.' + END AS reason + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4 Ensure that Azure Active Directory Admin is configured \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_1_1.yaml b/compliance/controls/azure/azure_cis_v130_5_1_1.yaml old mode 100755 new mode 100644 index ec296f8e9..164931024 --- a/compliance/controls/azure/azure_cis_v130_5_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_1_1.yaml @@ -1,24 +1,24 @@ +Description: Enable Diagnostic settings for exporting activity logs. Diagnostic setting are available for each individual resources within a subscription. Settings should be configured for all appropriate resources for your environment. ID: azure_cis_v130_5_1_1 -Title: "5.1.1 Ensure that a 'Diagnostics Setting' exists" -Description: "Enable Diagnostic settings for exporting activity logs. Diagnostic setting are available for each individual resources within a subscription. Settings should be configured for all appropriate resources for your environment." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.1 Ensure that a 'Diagnostics Setting' exists \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_1_2.yaml b/compliance/controls/azure/azure_cis_v130_5_1_2.yaml old mode 100755 new mode 100644 index 0768faaf4..acb7f40d7 --- a/compliance/controls/azure/azure_cis_v130_5_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_1_2.yaml @@ -1,15 +1,58 @@ +Description: Enable Diagnostic settings for exporting activity logs. Diagnostic setting are available for each individual resources within a subscription. Settings should be configured for all appropriate resources for your environment. ID: azure_cis_v130_5_1_2 -Title: "5.1.2 Ensure Diagnostic Setting captures appropriate categories" -Description: "Enable Diagnostic settings for exporting activity logs. Diagnostic setting are available for each individual resources within a subscription. Settings should be configured for all appropriate resources for your environment." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with enabled_settings as (\n select\n name,\n id,\n _ctx,\n resource_group,\n subscription_id,\n count(*) filter (where l ->> 'enabled' = 'true'\n and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy')\n ) as valid_category_count,\n string_agg(l ->> 'category', ', ') filter (where l ->> 'enabled' = 'true'\n and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy')\n ) as valid_categories\n from\n azure_diagnostic_setting,\n jsonb_array_elements(logs) as l\n group by\n name,\n id,\n _ctx,\n resource_group,\n subscription_id\n)\nselect\n sett.id as resource,\n sett.og_account_id as og_account_id,\n sett.og_resource_id as og_resource_id,\n case\n when valid_category_count = 4 then 'ok'\n else 'alarm'\n end as status,\n case\n when valid_category_count = 4\n then name || ' logs enabled for required categories administrative, security, alert and policy.'\n when valid_category_count > 0\n then sett.name || ' logs enabled for ' || valid_categories || ' categories.'\n else sett.name || ' logs not enabled for categories administrative, security, alert and policy.'\n end as reason\n \n \nfrom\n enabled_settings sett,\n azure_subscription sub\nwhere\n sub.subscription_id = sett.subscription_id;" - PrimaryTable: azure_diagnostic_setting ListOfTables: - azure_diagnostic_setting - azure_subscription Parameters: [] + PrimaryTable: azure_diagnostic_setting + QueryToExecute: | + WITH enabled_settings AS ( + SELECT + name, + id, + _ctx, + resource_group, + subscription_id, + COUNT(*) FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy') + ) AS valid_category_count, + STRING_AGG(l ->> 'category', ', ') FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy') + ) AS valid_categories + FROM + azure_diagnostic_setting, + jsonb_array_elements(logs) AS l + GROUP BY + name, + id, + _ctx, + resource_group, + subscription_id + ) + SELECT + sett.id AS resource, + sett.og_account_id AS og_account_id, + sett.og_resource_id AS og_resource_id, + CASE + WHEN valid_category_count = 4 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN valid_category_count = 4 + THEN name || ' logs enabled for required categories administrative, security, alert, and policy.' + WHEN valid_category_count > 0 + THEN sett.name || ' logs enabled for ' || valid_categories || ' categories.' + ELSE sett.name || ' logs not enabled for categories administrative, security, alert, and policy.' + END AS reason + FROM + enabled_settings sett, + azure_subscription sub + WHERE + sub.subscription_id = sett.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.2 Ensure Diagnostic Setting captures appropriate categories \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_1_3.yaml b/compliance/controls/azure/azure_cis_v130_5_1_3.yaml old mode 100755 new mode 100644 index e6e37dd5a..32cd30752 --- a/compliance/controls/azure/azure_cis_v130_5_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_1_3.yaml @@ -1,34 +1,34 @@ +Description: The storage account container containing the activity log export should not be publicly accessible. ID: azure_cis_v130_5_1_3 -Title: "5.1.3 Ensure the storage container storing the activity logs is not publicly accessible" -Description: "The storage account container containing the activity log export should not be publicly accessible." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc.id as resource, - sc.og_account_id as og_account_id, - sc.og_resource_id as og_resource_id, - case - when public_access != 'None' then 'alarm' - else 'ok' - end as status, - case - when public_access != 'None' - then account_name || ' container insights-operational-logs storing activity logs publicly accessible.' - else account_name || ' container insights-operational-logs storing activity logs not publicly accessible.' - end as reason - from - azure_storage_container sc, - azure_subscription sub - where - name = 'insights-operational-logs' - and sub.subscription_id = sc.subscription_id; - PrimaryTable: azure_storage_container ListOfTables: - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_container + QueryToExecute: | + SELECT + sc.id AS resource, + sc.og_account_id AS og_account_id, + sc.og_resource_id AS og_resource_id, + CASE + WHEN public_access != 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_access != 'None' + THEN account_name || ' container insights-operational-logs storing activity logs publicly accessible.' + ELSE account_name || ' container insights-operational-logs storing activity logs not publicly accessible.' + END AS reason + FROM + azure_storage_container sc, + azure_subscription sub + WHERE + name = 'insights-operational-logs' + AND sub.subscription_id = sc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.3 Ensure the storage container storing the activity logs is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_1_5.yaml b/compliance/controls/azure/azure_cis_v130_5_1_5.yaml old mode 100755 new mode 100644 index 17fabe125..60b28d536 --- a/compliance/controls/azure/azure_cis_v130_5_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_1_5.yaml @@ -1,51 +1,49 @@ +Description: Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available. ID: azure_cis_v130_5_1_5 -Title: "5.1.5 Ensure that logging for Azure KeyVault is 'Enabled'" -Description: "Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with logging_details as ( - select - name as key_vault_name - from - azure_key_vault, - jsonb_array_elements(diagnostic_settings) setting, - jsonb_array_elements(setting -> 'properties' -> 'logs') log - where - diagnostic_settings is not null - and setting -> 'properties' ->> 'storageAccountId' <> '' - and (log ->> 'enabled') :: boolean - and log ->> 'category' = 'AuditEvent' - and (log -> 'retentionPolicy') :: JSONB ? 'days' - ) - select - v.id as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when v.diagnostic_settings is null then 'alarm' - when l.key_vault_name not like concat('%', v.name, '%') then 'alarm' - else 'ok' - end as status, - case - when v.diagnostic_settings is null then v.name || ' logging not enabled.' - when l.key_vault_name not like concat('%', v.name, '%') then v.name || ' logging not enabled.' - else v.name || ' logging enabled.' - end as reason - from - azure_key_vault v, - logging_details l, - azure_subscription sub - where - sub.subscription_id = v.subscription_id; - ``` - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + WITH logging_details AS ( + SELECT + name AS key_vault_name + FROM + azure_key_vault, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND setting -> 'properties' ->> 'storageAccountId' <> '' + AND (log ->> 'enabled')::boolean + AND log ->> 'category' = 'AuditEvent' + AND (log -> 'retentionPolicy')::JSONB ? 'days' + ) + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason + FROM + azure_key_vault v, + logging_details l, + azure_subscription sub + WHERE + sub.subscription_id = v.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.5 Ensure that logging for Azure KeyVault is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_2_1.yaml b/compliance/controls/azure/azure_cis_v130_5_2_1.yaml old mode 100755 new mode 100644 index 6a0ddec17..b4e76d63e --- a/compliance/controls/azure/azure_cis_v130_5_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_2_1.yaml @@ -1,53 +1,53 @@ +Description: Create an activity log alert for the Create Policy Assignment event. ID: azure_cis_v130_5_2_1 -Title: "5.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment" -Description: "Create an activity log alert for the Create Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' - limit 1 + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' + LIMIT 1 ) - select - a.subscription_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create policy assignment event.' - else 'Activity log alert does not exists for create policy assignment event.' - end as reason - from + SELECT + a.subscription_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create policy assignment event.' + ELSE 'Activity log alert does not exist for create policy assignment event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY a.subscription_id, sub.subscription_id, sub._ctx, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_2_2.yaml b/compliance/controls/azure/azure_cis_v130_5_2_2.yaml old mode 100755 new mode 100644 index 06bb22d83..943b965df --- a/compliance/controls/azure/azure_cis_v130_5_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_2_2.yaml @@ -1,15 +1,52 @@ +Description: Create an activity log alert for the Delete Policy Assignment event. ID: azure_cis_v130_5_2_2 -Title: "5.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment" -Description: "Create an activity log alert for the Delete Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Authorization/policyAssignments/delete\"}]'\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for delete policy assignment event.'\n else 'Activity log alert does not exists for delete policy assignment event.'\n end as reason\n \n \nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub._ctx,\n sub.subscription_id,\n sub.display_name;" - PrimaryTable: azure_subscription ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative", "field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/delete"}]' + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete policy assignment event.' + ELSE 'Activity log alert does not exist for delete policy assignment event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_2_3.yaml b/compliance/controls/azure/azure_cis_v130_5_2_3.yaml old mode 100755 new mode 100644 index 82e23c70a..d78ed44d0 --- a/compliance/controls/azure/azure_cis_v130_5_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_2_3.yaml @@ -1,62 +1,62 @@ +Description: Create an Activity Log Alert for the "Create" or "Update Network Security Group" event. ID: azure_cis_v130_5_2_3 -Title: "5.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group" -Description: "Create an Activity Log Alert for the \\\"Create\\\" or \\\"Update Network Security Group\\\" event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Network Security Group event.' - else 'Activity log alert does not exists for create or update Network Security Group event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Network Security Group event.' + ELSE 'Activity log alert does not exist for create or update Network Security Group event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_2_4.yaml b/compliance/controls/azure/azure_cis_v130_5_2_4.yaml old mode 100755 new mode 100644 index c6f2400d1..73915ba3f --- a/compliance/controls/azure/azure_cis_v130_5_2_4.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_2_4.yaml @@ -1,63 +1,63 @@ +Description: Create an activity log alert for the Delete Network Security Group event. ID: azure_cis_v130_5_2_4 -Title: "5.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group" -Description: "Create an activity log alert for the Delete Network Security Group event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id, jsonb_array_length(alert.condition -> 'allOf') - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Network Security Group event.' - else 'Activity log alert does not exists for delete Network Security Group event.' - end as reason - from - azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by - sub._ctx, - sub.subscription_id, - sub.display_name; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Network Security Group event.' + ELSE 'Activity log alert does not exist for delete Network Security Group event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_2_5.yaml b/compliance/controls/azure/azure_cis_v130_5_2_5.yaml old mode 100755 new mode 100644 index 1114f5ddf..9d96c6384 --- a/compliance/controls/azure/azure_cis_v130_5_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_2_5.yaml @@ -1,15 +1,62 @@ +Description: Create an activity log alert for the Create or Update Network Security Group Rule event. ID: azure_cis_v130_5_2_5 -Title: "5.2.5 Ensure that Activity Log Alert exists for Create or Update Network Security Group Rule" -Description: "Create an activity log alert for the Create or Update Network Security Group Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and (\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/networksecuritygroups/securityrules/write\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/networksecuritygroups/securityrules\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Network Security Group Rule event.'\n else 'Activity log alert does not exists for create or update Network Security Group Rule event.'\n end as reason\n \n \nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub._ctx,\n sub.subscription_id,\n sub.display_name;" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networksecuritygroups/securityrules/write"}]' + ) + OR + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups/securityrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Network Security Group Rule event.' + ELSE 'Activity log alert does not exist for create or update Network Security Group Rule event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.5 Ensure that Activity Log Alert exists for Create or Update Network Security Group Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_2_6.yaml b/compliance/controls/azure/azure_cis_v130_5_2_6.yaml old mode 100755 new mode 100644 index bde1af436..3b24ba9e7 --- a/compliance/controls/azure/azure_cis_v130_5_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_2_6.yaml @@ -1,64 +1,62 @@ +Description: Create an activity log alert for the Create or Update Network Security Group Rule event. ID: azure_cis_v130_5_2_6 -Title: "5.2.6 Ensure that Activity Log Alert exists for Create or Update Network Security Group Rule" -Description: "Create an activity log alert for the Create or Update Network Security Group Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networksecuritygroups/securityrules/delete"}]' + alert.condition->'allOf' @> '[{"equals":"Administrative", "field":"category"}]' + AND alert.condition->'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networksecuritygroups/securityrules/delete"}]' ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups/securityrules"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + OR ( + alert.condition->'allOf' @> '[{"equals":"Administrative", "field":"category"}]' + AND alert.condition->'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups/securityrules"}]' + AND jsonb_array_length(alert.condition->'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Network Security Group Rule event.' - else 'Activity log alert does not exists for delete Network Security Group Rule event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Network Security Group Rule event.' + ELSE 'Activity log alert does not exist for delete Network Security Group Rule event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a + ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - ``` - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.6 Ensure that Activity Log Alert exists for Create or Update Network Security Group Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_2_7.yaml b/compliance/controls/azure/azure_cis_v130_5_2_7.yaml old mode 100755 new mode 100644 index e096442e7..167873b50 --- a/compliance/controls/azure/azure_cis_v130_5_2_7.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_2_7.yaml @@ -1,64 +1,62 @@ +Description: Create an activity log alert for the Create or Update Security Solution event. ID: azure_cis_v130_5_2_7 -Title: "5.2.7 Ensure that Activity Log Alert exists for Create or Update Security Solution" -Description: "Create an activity log alert for the Create or Update Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/write"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/write"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Security Solution event.' - else 'Activity log alert does not exists for create or update Security Solution event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Security Solution event.' + ELSE 'Activity log alert does not exist for create or update Security Solution event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - ``` - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.7 Ensure that Activity Log Alert exists for Create or Update Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_2_8.yaml b/compliance/controls/azure/azure_cis_v130_5_2_8.yaml old mode 100755 new mode 100644 index ef95eb5b1..c2c522ce4 --- a/compliance/controls/azure/azure_cis_v130_5_2_8.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_2_8.yaml @@ -1,62 +1,62 @@ +Description: Create an activity log alert for the Delete Security Solution event. ID: azure_cis_v130_5_2_8 -Title: "5.2.8 Ensure that Activity Log Alert exists for Delete Security Solution" -Description: "Create an activity log alert for the Delete Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/delete"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/delete"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Security Solution event.' - else 'Activity log alert does not exists for delete Security Solution event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Security Solution event.' + ELSE 'Activity log alert does not exist for delete Security Solution event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.8 Ensure that Activity Log Alert exists for Delete Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_2_9.yaml b/compliance/controls/azure/azure_cis_v130_5_2_9.yaml old mode 100755 new mode 100644 index f1b3d7049..22b3e3be1 --- a/compliance/controls/azure/azure_cis_v130_5_2_9.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_2_9.yaml @@ -1,53 +1,53 @@ +Description: Create an activity log alert for the Create or Update or Delete SQL Server Firewall Rule event. ID: azure_cis_v130_5_2_9 -Title: "5.2.9 Ensure that Activity Log Alert exists for Create or Update or Delete SQL Server Firewall Rule" -Description: "Create an activity log alert for the Create or Update or Delete SQL Server Firewall Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - limit 1 + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create, update and delete SQL Server Firewall Rule event.' - else 'Activity log alert does not exists for create, update and delete SQL Server Firewall Rule event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create, update and delete SQL Server Firewall Rule event.' + ELSE 'Activity log alert does not exist for create, update and delete SQL Server Firewall Rule event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.9 Ensure that Activity Log Alert exists for Create or Update or Delete SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_5_3.yaml b/compliance/controls/azure/azure_cis_v130_5_3.yaml old mode 100755 new mode 100644 index 442bded4d..61d74bccd --- a/compliance/controls/azure/azure_cis_v130_5_3.yaml +++ b/compliance/controls/azure/azure_cis_v130_5_3.yaml @@ -1,24 +1,24 @@ +Description: Diagnostic Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself. It is crucial that logging systems are correctly configured to log all relevant activities and retain those logs for a sufficient length of time. ID: azure_cis_v130_5_3 -Title: "5.3 Ensure that Diagnostic Logs are enabled for all services which support it" -Description: "Diagnostic Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself. It is crucial that logging systems are correctly configured to log all relevant activities and retain those logs for a sufficient length of time." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.3 Ensure that Diagnostic Logs are enabled for all services which support it \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_6_1.yaml b/compliance/controls/azure/azure_cis_v130_6_1.yaml old mode 100755 new mode 100644 index 7da551471..0ce9d8dd9 --- a/compliance/controls/azure/azure_cis_v130_6_1.yaml +++ b/compliance/controls/azure/azure_cis_v130_6_1.yaml @@ -1,54 +1,60 @@ +Description: Disable RDP access on network security groups from the Internet. ID: azure_cis_v130_6_1 -Title: "6.1 Ensure that RDP access is restricted from the internet" -Description: "Disable RDP access on network security groups from the Internet." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group QueryToExecute: | - with network_sg as ( - select - distinct name sg_name - from + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text( + sg -> 'properties' -> 'destinationPortRanges' + || (sg -> 'properties' -> 'destinationPortRange')::jsonb + ) dport, + jsonb_array_elements_text( + sg -> 'properties' -> 'sourceAddressPrefixes' + || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb + ) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('3389', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 3389 - and split_part(dport, '-', 2) :: integer >= 3389 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('3389', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::integer <= 3389 + AND split_part(dport, '-', 2)::integer >= 3389 ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts RDP access from internet.' - else sg.title || ' allows RDP access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts RDP access from internet.' + ELSE sg.title || ' allows RDP access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.1 Ensure that RDP access is restricted from the internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_6_2.yaml b/compliance/controls/azure/azure_cis_v130_6_2.yaml old mode 100755 new mode 100644 index b6c2310ce..265428dbe --- a/compliance/controls/azure/azure_cis_v130_6_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_6_2.yaml @@ -1,54 +1,57 @@ +Description: Disable SSH access on network security groups from the Internet. ID: azure_cis_v130_6_2 -Title: "6.2 Ensure that SSH access is restricted from the internet" -Description: "Disable SSH access on network security groups from the Internet." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('22', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 22 - and split_part(dport, '-', 2) :: integer >= 22 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('22', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::INTEGER <= 22 + AND split_part(dport, '-', 2)::INTEGER >= 22 ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts SSH access from internet.' - else sg.title || ' allows SSH access from internet.' - end as reason - from + + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts SSH access from internet.' + ELSE sg.title || ' allows SSH access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN + network_sg nsg ON nsg.sg_name = sg.name + JOIN + azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.2 Ensure that SSH access is restricted from the internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_6_3.yaml b/compliance/controls/azure/azure_cis_v130_6_3.yaml old mode 100755 new mode 100644 index 6f775a0f6..719a26499 --- a/compliance/controls/azure/azure_cis_v130_6_3.yaml +++ b/compliance/controls/azure/azure_cis_v130_6_3.yaml @@ -1,36 +1,36 @@ +Description: Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP). ID: azure_cis_v130_6_3 -Title: "6.3 Ensure no SQL Databases allow ingress 0.0.0.0/0 (ANY IP)" -Description: "Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' - or firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' - then 'alarm' - else 'ok' - end as status, - case - when firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' - or firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' - then s.title || ' allows ingress 0.0.0.0/0 or any ip over internet.' - else s.title || ' not allows ingress 0.0.0.0/0 or any ip over internet.' - end as reason - from - azure_sql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN s.title || ' allows ingress 0.0.0.0/0 or any IP over Internet.' + ELSE s.title || ' does not allow ingress 0.0.0.0/0 or any IP over Internet.' + END AS reason + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.3 Ensure no SQL Databases allow ingress 0.0.0.0/0 (ANY IP) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_6_6.yaml b/compliance/controls/azure/azure_cis_v130_6_6.yaml old mode 100755 new mode 100644 index 08354de21..651f2f376 --- a/compliance/controls/azure/azure_cis_v130_6_6.yaml +++ b/compliance/controls/azure/azure_cis_v130_6_6.yaml @@ -1,59 +1,59 @@ +Description: Disable Internet exposed UDP ports on network security groups. ID: azure_cis_v130_6_6 -Title: "6.6 Ensure that UDP Services are restricted from the Internet" -Description: "Disable Internet exposed UDP ports on network security groups." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and sg -> 'properties' ->> 'protocol' = 'UDP' - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' = 'UDP' + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( dport = '*' - or ( - dport like '%-%' - and ( - 53 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 123 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 161 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 389 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 1900 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer + OR ( + dport LIKE '%-%' + AND ( + 53 BETWEEN split_part(dport, '-', 1)::integer AND split_part(dport, '-', 2)::integer + OR 123 BETWEEN split_part(dport, '-', 1)::integer AND split_part(dport, '-', 2)::integer + OR 161 BETWEEN split_part(dport, '-', 1)::integer AND split_part(dport, '-', 2)::integer + OR 389 BETWEEN split_part(dport, '-', 1)::integer AND split_part(dport, '-', 2)::integer + OR 1900 BETWEEN split_part(dport, '-', 1)::integer AND split_part(dport, '-', 2)::integer ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts UDP services from internet.' - else sg.title || ' allows UDP services from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts UDP services from internet.' + ELSE sg.title || ' allows UDP services from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.6 Ensure that UDP Services are restricted from the Internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_7_1.yaml b/compliance/controls/azure/azure_cis_v130_7_1.yaml old mode 100755 new mode 100644 index 2c91805e0..81ec549de --- a/compliance/controls/azure/azure_cis_v130_7_1.yaml +++ b/compliance/controls/azure/azure_cis_v130_7_1.yaml @@ -1,32 +1,32 @@ +Description: Migrate BLOB based VHD's to Managed Disks on Virtual Machines to exploit the default features of this configuration. ID: azure_cis_v130_7_1 -Title: "7.1 Ensure Virtual Machines are utilizing Managed Disks" -Description: "Migrate BLOB based VHD's to Managed Disks on Virtual Machines to exploit the default features of this configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - vm.id as resource, - vm.og_account_id as og_account_id, - vm.og_resource_id as og_resource_id, - case - when managed_disk_id is null then 'alarm' - else 'ok' - end as status, - case - when managed_disk_id is null then vm.name || ' VM not utilizing managed disks.' - else vm.name || ' VM utilizing managed disks.' - end as reason - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where - sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN managed_disk_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN managed_disk_id IS NULL THEN vm.name || ' VM not utilizing managed disks.' + ELSE vm.name || ' VM utilizing managed disks.' + END AS reason + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.1 Ensure Virtual Machines are utilizing Managed Disks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_7_2.yaml b/compliance/controls/azure/azure_cis_v130_7_2.yaml old mode 100755 new mode 100644 index 298e02f0e..de44d7ce5 --- a/compliance/controls/azure/azure_cis_v130_7_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_7_2.yaml @@ -1,33 +1,33 @@ +Description: Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK. ID: azure_cis_v130_7_2 -Title: "7.2 Ensure that 'OS and Data' disks are encrypted with CMK" -Description: "Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.' - else disk.name || ' not encrypted with CMK.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state = 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state = 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.2 Ensure that 'OS and Data' disks are encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_7_3.yaml b/compliance/controls/azure/azure_cis_v130_7_3.yaml old mode 100755 new mode 100644 index a17f8f6fe..e9ff9670c --- a/compliance/controls/azure/azure_cis_v130_7_3.yaml +++ b/compliance/controls/azure/azure_cis_v130_7_3.yaml @@ -1,33 +1,33 @@ +Description: Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK). ID: azure_cis_v130_7_3 -Title: "7.3 Ensure that 'Unattached disks' are encrypted with CMK" -Description: "Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.' - else disk.name || ' not encrypted with CMK.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state != 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state != 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.3 Ensure that 'Unattached disks' are encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_7_4.yaml b/compliance/controls/azure/azure_cis_v130_7_4.yaml old mode 100755 new mode 100644 index d62648142..a1883b086 --- a/compliance/controls/azure/azure_cis_v130_7_4.yaml +++ b/compliance/controls/azure/azure_cis_v130_7_4.yaml @@ -1,24 +1,24 @@ +Description: Only install organization-approved extensions on VMs. ID: azure_cis_v130_7_4 -Title: "7.4 Ensure that only approved extensions are installed" -Description: "Only install organization-approved extensions on VMs." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.4 Ensure that only approved extensions are installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_7_5.yaml b/compliance/controls/azure/azure_cis_v130_7_5.yaml old mode 100755 new mode 100644 index 8abead2a6..277098e49 --- a/compliance/controls/azure/azure_cis_v130_7_5.yaml +++ b/compliance/controls/azure/azure_cis_v130_7_5.yaml @@ -1,24 +1,24 @@ +Description: Ensure that the latest OS patches for all virtual machines are applied. ID: azure_cis_v130_7_5 -Title: "7.5 Ensure that the latest OS Patches for all Virtual Machines are applied" -Description: "Ensure that the latest OS patches for all virtual machines are applied." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.5 Ensure that the latest OS Patches for all Virtual Machines are applied \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_7_6.yaml b/compliance/controls/azure/azure_cis_v130_7_6.yaml old mode 100755 new mode 100644 index f68ad6088..fd2445416 --- a/compliance/controls/azure/azure_cis_v130_7_6.yaml +++ b/compliance/controls/azure/azure_cis_v130_7_6.yaml @@ -1,24 +1,24 @@ +Description: Install endpoint protection for all virtual machines. ID: azure_cis_v130_7_6 -Title: "7.6 Ensure that the endpoint protection for all Virtual Machines is installed" -Description: "Install endpoint protection for all virtual machines." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.6 Ensure that the endpoint protection for all Virtual Machines is installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_7_7.yaml b/compliance/controls/azure/azure_cis_v130_7_7.yaml old mode 100755 new mode 100644 index ba8142ee3..670631205 --- a/compliance/controls/azure/azure_cis_v130_7_7.yaml +++ b/compliance/controls/azure/azure_cis_v130_7_7.yaml @@ -1,24 +1,24 @@ +Description: VHD (Virtual Hard Disks) are stored in BLOB storage and are the old style disks that were attached to Virtual Machines, and the BLOB VHD was then leased to the VM. By Default storage accounts are not encrypted, and Azure Defender(Security Centre) would then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK and this should be turned on for storage accounts containing VHD's. ID: azure_cis_v130_7_7 -Title: "7.7 Ensure that VHD's are encrypted" -Description: "VHD (Virtual Hard Disks) are stored in BLOB storage and are the old style disks that were attached to Virtual Machines, and the BLOB VHD was then leased to the VM. By Default storage accounts are not encrypted, and Azure Defender(Security Centre) would then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK and this should be turned on for storage accounts containing VHD's." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.7 Ensure that VHD's are encrypted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_8_1.yaml b/compliance/controls/azure/azure_cis_v130_8_1.yaml old mode 100755 new mode 100644 index 486d14058..7c93db52b --- a/compliance/controls/azure/azure_cis_v130_8_1.yaml +++ b/compliance/controls/azure/azure_cis_v130_8_1.yaml @@ -1,15 +1,34 @@ +Description: Ensure that all keys in Azure Key Vault have an expiration time set. ID: azure_cis_v130_8_1 -Title: "8.1 Ensure that the expiration date is set on all keys" -Description: "Ensure that all keys in Azure Key Vault have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kvk.id as resource,\n kvk.og_account_id as og_account_id,\n kvk.og_resource_id as og_resource_id,\n case\n when enabled and expires_at is null then 'alarm'\n else 'ok'\n end as status,\n vault_name || ' key ' || name ||\n case\n when enabled and expires_at is null then ' expiration date not set.'\n when not enabled then ' disabled.'\n else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.'\n end as reason\n \n \n \nfrom\n azure_key_vault_key kvk,\n azure_subscription sub\nwhere\n sub.subscription_id = kvk.subscription_id;" - PrimaryTable: azure_key_vault_key ListOfTables: - azure_key_vault_key - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + vault_name || ' key ' || name || + CASE + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + azure_key_vault_key kvk, + azure_subscription sub + WHERE + sub.subscription_id = kvk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.1 Ensure that the expiration date is set on all keys \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_8_2.yaml b/compliance/controls/azure/azure_cis_v130_8_2.yaml old mode 100755 new mode 100644 index 5f6d3a88c..08f58e967 --- a/compliance/controls/azure/azure_cis_v130_8_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_8_2.yaml @@ -1,34 +1,34 @@ +Description: Ensure that all Secrets in the Azure Key Vault have an expiration time set. ID: azure_cis_v130_8_2 -Title: "8.2 Ensure that the expiration date is set on all Secrets" -Description: "Ensure that all Secrets in the Azure Key Vault have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kvs.id as resource, - kvs.og_account_id as og_account_id, - kvs.og_resource_id as og_resource_id, - case - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, - vault_name || ' secret ' || name || - case - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from - azure_key_vault_secret as kvs, - azure_subscription as sub - where - sub.subscription_id = kvs.subscription_id; - PrimaryTable: azure_key_vault_secret ListOfTables: - azure_key_vault_secret - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + vault_name || ' secret ' || name || + CASE + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + azure_key_vault_secret AS kvs, + azure_subscription AS sub + WHERE + sub.subscription_id = kvs.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.2 Ensure that the expiration date is set on all Secrets \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_8_3.yaml b/compliance/controls/azure/azure_cis_v130_8_3.yaml old mode 100755 new mode 100644 index eca16fed9..ae02558c7 --- a/compliance/controls/azure/azure_cis_v130_8_3.yaml +++ b/compliance/controls/azure/azure_cis_v130_8_3.yaml @@ -1,24 +1,24 @@ +Description: Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion. ID: azure_cis_v130_8_3 -Title: "8.3 Ensure that Resource Locks are set for mission critical Azure resources" -Description: "Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 8.3 Ensure that Resource Locks are set for mission critical Azure resources \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_8_4.yaml b/compliance/controls/azure/azure_cis_v130_8_4.yaml old mode 100755 new mode 100644 index c820c555f..4f8fc120a --- a/compliance/controls/azure/azure_cis_v130_8_4.yaml +++ b/compliance/controls/azure/azure_cis_v130_8_4.yaml @@ -1,34 +1,34 @@ +Description: The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the "Do Not Purge" and "Soft Delete" functions. ID: azure_cis_v130_8_4 -Title: "8.4 Ensure the key vault is recoverable" -Description: "The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the \\\"Do Not Purge\\\" and \\\"Soft Delete\\\" functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when soft_delete_enabled and purge_protection_enabled then 'ok' - else 'alarm' - end as status, - case - when not soft_delete_enabled and not purge_protection_enabled then name || ' "soft delete" and "do not purge" not enabled.' - when not soft_delete_enabled then name || ' "soft delete" not enabled.' - when not purge_protection_enabled then name || ' "do not purge" not enabled.' - else name || ' "soft delete" and "do not purge" enabled.' - end as reason - from - azure_key_vault kv, - azure_subscription sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN soft_delete_enabled AND purge_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT soft_delete_enabled AND NOT purge_protection_enabled THEN name || ' "soft delete" and "do not purge" not enabled.' + WHEN NOT soft_delete_enabled THEN name || ' "soft delete" not enabled.' + WHEN NOT purge_protection_enabled THEN name || ' "do not purge" not enabled.' + ELSE name || ' "soft delete" and "do not purge" enabled.' + END AS reason + FROM + azure_key_vault kv, + azure_subscription sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.4 Ensure the key vault is recoverable \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_8_5.yaml b/compliance/controls/azure/azure_cis_v130_8_5.yaml old mode 100755 new mode 100644 index 8ed1ec04f..bf094b3c3 --- a/compliance/controls/azure/azure_cis_v130_8_5.yaml +++ b/compliance/controls/azure/azure_cis_v130_8_5.yaml @@ -1,34 +1,34 @@ +Description: Ensure that RBAC is enabled on all Azure Kubernetes Services Instances. ID: azure_cis_v130_8_5 -Title: "8.5 Enable role-based access control (RBAC) within Azure Kubernetes Services" -Description: "Ensure that RBAC is enabled on all Azure Kubernetes Services Instances." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when soft_delete_enabled and purge_protection_enabled then 'ok' - else 'alarm' - end as status, - case - when not soft_delete_enabled and not purge_protection_enabled then name || ' "soft delete" and "do not purge" not enabled.' - when not soft_delete_enabled then name || ' "soft delete" not enabled.' - when not purge_protection_enabled then name || ' "do not purge" not enabled.' - else name || ' "soft delete" and "do not purge" enabled.' - end as reason - from - azure_key_vault kv, - azure_subscription sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN soft_delete_enabled AND purge_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT soft_delete_enabled AND NOT purge_protection_enabled THEN name || ' "soft delete" and "do not purge" not enabled.' + WHEN NOT soft_delete_enabled THEN name || ' "soft delete" not enabled.' + WHEN NOT purge_protection_enabled THEN name || ' "do not purge" not enabled.' + ELSE name || ' "soft delete" and "do not purge" enabled.' + END AS reason + FROM + azure_key_vault kv, + azure_subscription sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.5 Enable role-based access control (RBAC) within Azure Kubernetes Services \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_9_1.yaml b/compliance/controls/azure/azure_cis_v130_9_1.yaml old mode 100755 new mode 100644 index 280a35b0c..cdd31c822 --- a/compliance/controls/azure/azure_cis_v130_9_1.yaml +++ b/compliance/controls/azure/azure_cis_v130_9_1.yaml @@ -1,32 +1,32 @@ +Description: Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching the API app, or authenticate those that have tokens before they reach the API app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented. ID: azure_cis_v130_9_1 -Title: "9.1 Ensure App Service Authentication is set on Azure App Service" -Description: "Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching the API app, or authenticate those that have tokens before they reach the API app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then name || ' authentication not set.' - else name || ' authentication set.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::boolean THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::boolean THEN name || ' authentication not set.' + ELSE name || ' authentication set.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.1 Ensure App Service Authentication is set on Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_9_11.yaml b/compliance/controls/azure/azure_cis_v130_9_11.yaml old mode 100755 new mode 100644 index 5d7bd5bfa..ff61f18ce --- a/compliance/controls/azure/azure_cis_v130_9_11.yaml +++ b/compliance/controls/azure/azure_cis_v130_9_11.yaml @@ -1,24 +1,24 @@ +Description: Encryption keys, Certificate thumbprints and Managed Identity Credentials can be coded into the APP service, this renders them visible as part of the configuration, to maintain security of these keys it is better to store in an Azure Keyvault and reference them from the Keyvault. ID: azure_cis_v130_9_11 -Title: "9.11 Ensure Azure Keyvaults are used to store secrets" -Description: "Encryption keys, Certificate thumbprints and Managed Identity Credentials can be coded into the APP service, this renders them visible as part of the configuration, to maintain security of these keys it is better to store in an Azure Keyvault and reference them from the Keyvault." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.11 Ensure Azure Keyvaults are used to store secrets \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_9_2.yaml b/compliance/controls/azure/azure_cis_v130_9_2.yaml old mode 100755 new mode 100644 index 8f4a4296e..a65b0774b --- a/compliance/controls/azure/azure_cis_v130_9_2.yaml +++ b/compliance/controls/azure/azure_cis_v130_9_2.yaml @@ -1,32 +1,32 @@ +Description: Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic. ID: azure_cis_v130_9_2 -Title: "9.2 Ensure web app redirects all HTTP traffic to HTTPS in Azure App Service" -Description: "Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not https_only then 'alarm' - else 'ok' - end as status, - case - when not https_only then name || ' does not redirect all HTTP traffic to HTTPS.' - else name || ' redirects all HTTP traffic to HTTPS.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT https_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT https_only THEN name || ' does not redirect all HTTP traffic to HTTPS.' + ELSE name || ' redirects all HTTP traffic to HTTPS.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.2 Ensure web app redirects all HTTP traffic to HTTPS in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_9_3.yaml b/compliance/controls/azure/azure_cis_v130_9_3.yaml old mode 100755 new mode 100644 index 9b78f2e75..5f7c369bd --- a/compliance/controls/azure/azure_cis_v130_9_3.yaml +++ b/compliance/controls/azure/azure_cis_v130_9_3.yaml @@ -1,32 +1,32 @@ +Description: The TLS(Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards, such as PCI DSS. ID: azure_cis_v130_9_3 -Title: "9.3 Ensure web app is using the latest version of TLS encryption" -Description: "The TLS(Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards, such as PCI DSS." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then 'alarm' - else 'ok' - end as status, - case - when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then name || ' not using the latest version of TLS encryption.' - else name || ' using the latest version of TLS encryption.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN name || ' not using the latest version of TLS encryption.' + ELSE name || ' using the latest version of TLS encryption.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.3 Ensure web app is using the latest version of TLS encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_9_4.yaml b/compliance/controls/azure/azure_cis_v130_9_4.yaml old mode 100755 new mode 100644 index 912f69df8..8f58241a6 --- a/compliance/controls/azure/azure_cis_v130_9_4.yaml +++ b/compliance/controls/azure/azure_cis_v130_9_4.yaml @@ -1,32 +1,32 @@ +Description: Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app. ID: azure_cis_v130_9_4 -Title: "9.4 Ensure the web app has 'Client Certificates (Incoming client certificates)' set to 'On'" -Description: "Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not client_cert_enabled then 'alarm' - else 'ok' - end as status, - case - when not client_cert_enabled then name || ' incoming client certificates set to off.' - else name || ' incoming client certificates set to on.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT client_cert_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT client_cert_enabled THEN name || ' incoming client certificates set to off.' + ELSE name || ' incoming client certificates set to on.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.4 Ensure the web app has 'Client Certificates (Incoming client certificates)' set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_9_5.yaml b/compliance/controls/azure/azure_cis_v130_9_5.yaml old mode 100755 new mode 100644 index 9d08d8601..6c2733625 --- a/compliance/controls/azure/azure_cis_v130_9_5.yaml +++ b/compliance/controls/azure/azure_cis_v130_9_5.yaml @@ -1,32 +1,32 @@ +Description: Managed service identity in App Service makes the app more secure by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in the app service, the app will connect to other Azure services securely without the need of username and passwords. ID: azure_cis_v130_9_5 -Title: "9.5 Ensure that Register with Azure Active Directory is enabled on App Service" -Description: "Managed service identity in App Service makes the app more secure by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in the app service, the app will connect to other Azure services securely without the need of username and passwords." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when identity = '{}' then 'alarm' - else 'ok' - end as status, - case - when identity = '{}' then name || ' register with azure active directory disabled.' - else name || ' register with azure active directory enabled.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN identity = '{}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity = '{}' THEN name || ' register with azure active directory disabled.' + ELSE name || ' register with azure active directory enabled.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.5 Ensure that Register with Azure Active Directory is enabled on App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_9_6.yaml b/compliance/controls/azure/azure_cis_v130_9_6.yaml old mode 100755 new mode 100644 index 1dc823eca..bf436f830 --- a/compliance/controls/azure/azure_cis_v130_9_6.yaml +++ b/compliance/controls/azure/azure_cis_v130_9_6.yaml @@ -1,24 +1,24 @@ +Description: Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version. ID: azure_cis_v130_9_6 -Title: "9.6 Ensure that 'PHP version' is the latest, if used to run the web app" -Description: "Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.6 Ensure that 'PHP version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_9_7.yaml b/compliance/controls/azure/azure_cis_v130_9_7.yaml old mode 100755 new mode 100644 index 4deca8283..634046f82 --- a/compliance/controls/azure/azure_cis_v130_9_7.yaml +++ b/compliance/controls/azure/azure_cis_v130_9_7.yaml @@ -1,24 +1,24 @@ +Description: Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version. ID: azure_cis_v130_9_7 -Title: "9.7 Ensure that 'Python version' is the latest, if used to run the web app" -Description: "Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.7 Ensure that 'Python version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_9_8.yaml b/compliance/controls/azure/azure_cis_v130_9_8.yaml old mode 100755 new mode 100644 index 9869c96cc..82facc4a8 --- a/compliance/controls/azure/azure_cis_v130_9_8.yaml +++ b/compliance/controls/azure/azure_cis_v130_9_8.yaml @@ -1,24 +1,24 @@ +Description: Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version. ID: azure_cis_v130_9_8 -Title: "9.8 Ensure that 'Java version' is the latest, if used to run the web app" -Description: "Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.8 Ensure that 'Java version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v130_9_9.yaml b/compliance/controls/azure/azure_cis_v130_9_9.yaml old mode 100755 new mode 100644 index 4dc6f8319..1bfec5694 --- a/compliance/controls/azure/azure_cis_v130_9_9.yaml +++ b/compliance/controls/azure/azure_cis_v130_9_9.yaml @@ -1,32 +1,32 @@ +Description: Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version. ID: azure_cis_v130_9_9 -Title: "9.9 Ensure that 'HTTP Version' is the latest, if used to run the web app" -Description: "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then name || ' HTTP version not latest.' - else name || ' HTTP version is latest.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::BOOLEAN THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::BOOLEAN THEN name || ' HTTP version not latest.' + ELSE name || ' HTTP version is latest.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.9 Ensure that 'HTTP Version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_1.yaml b/compliance/controls/azure/azure_cis_v140_1_1.yaml old mode 100755 new mode 100644 index ac0f308ba..f936fc5c5 --- a/compliance/controls/azure/azure_cis_v140_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_1.yaml @@ -1,19 +1,19 @@ +Description: Enable multi-factor authentication for all user credentials who have write access to Azure resources. These include roles like 'Service Co-Administrators', 'Subscription Owners', 'Contributors'. ID: azure_cis_v140_1_1 -Title: "1.1 Ensure that multi-factor authentication status is enabled for all privileged users" -Description: "Enable multi-factor authentication for all user credentials who have write access to Azure resources. These include roles like 'Service Co-Administrators', 'Subscription Owners', 'Contributors'." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1 Ensure that multi-factor authentication status is enabled for all privileged users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_10.yaml b/compliance/controls/azure/azure_cis_v140_1_10.yaml old mode 100755 new mode 100644 index 18d82d560..943e4c3c7 --- a/compliance/controls/azure/azure_cis_v140_1_10.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_10.yaml @@ -1,19 +1,19 @@ +Description: Require administrators to provide consent for the apps before use. ID: azure_cis_v140_1_10 -Title: "1.10 Ensure that 'Users can add gallery apps to their Access Panel' is set to 'No'" -Description: "Require administrators to provide consent for the apps before use." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.10 Ensure that 'Users can add gallery apps to their Access Panel' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_11.yaml b/compliance/controls/azure/azure_cis_v140_1_11.yaml old mode 100755 new mode 100644 index e079b29a0..157431160 --- a/compliance/controls/azure/azure_cis_v140_1_11.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_11.yaml @@ -1,19 +1,19 @@ +Description: Require administrators to register third-party applications. ID: azure_cis_v140_1_11 -Title: "1.11 Ensure that 'Users can register applications' is set to 'No'" -Description: "Require administrators to register third-party applications." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.11 Ensure that 'Users can register applications' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_12.yaml b/compliance/controls/azure/azure_cis_v140_1_12.yaml old mode 100755 new mode 100644 index a60030724..61f8210d3 --- a/compliance/controls/azure/azure_cis_v140_1_12.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_12.yaml @@ -1,19 +1,19 @@ +Description: Limit guest user permissions. ID: azure_cis_v140_1_12 -Title: "1.12 Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects'" -Description: "Limit guest user permissions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.12 Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_13.yaml b/compliance/controls/azure/azure_cis_v140_1_13.yaml old mode 100755 new mode 100644 index 3f61de48b..004cfeaed --- a/compliance/controls/azure/azure_cis_v140_1_13.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_13.yaml @@ -1,19 +1,19 @@ +Description: Restrict invitations to users with specific admin roles only. ID: azure_cis_v140_1_13 -Title: "1.13 Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users'" -Description: "Restrict invitations to users with specific admin roles only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.13 Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_14.yaml b/compliance/controls/azure/azure_cis_v140_1_14.yaml old mode 100755 new mode 100644 index d7caa66d6..723323e60 --- a/compliance/controls/azure/azure_cis_v140_1_14.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_14.yaml @@ -1,19 +1,19 @@ +Description: Restrict access to the Azure AD administration portal to administrators only. ID: azure_cis_v140_1_14 -Title: "1.14 Ensure That 'Restrict access to Azure AD administration portal' is set to 'Yes'" -Description: "Restrict access to the Azure AD administration portal to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.14 Ensure That 'Restrict access to Azure AD administration portal' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_15.yaml b/compliance/controls/azure/azure_cis_v140_1_15.yaml old mode 100755 new mode 100644 index a8bbb2ff2..e230b5e4d --- a/compliance/controls/azure/azure_cis_v140_1_15.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_15.yaml @@ -1,19 +1,19 @@ +Description: Restricts group creation to administrators with permissions only. ID: azure_cis_v140_1_15 -Title: "1.15 Ensure that 'Restrict user ability to access groups features in the Access Pane' is Set to 'Yes'" -Description: "Restricts group creation to administrators with permissions only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.15 Ensure that 'Restrict user ability to access groups features in the Access Pane' is Set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_16.yaml b/compliance/controls/azure/azure_cis_v140_1_16.yaml old mode 100755 new mode 100644 index 79cb1fe7e..e06d4cc31 --- a/compliance/controls/azure/azure_cis_v140_1_16.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_16.yaml @@ -1,19 +1,19 @@ +Description: Restrict security group creation to administrators only. ID: azure_cis_v140_1_16 -Title: "1.16 Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No'" -Description: "Restrict security group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.16 Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_17.yaml b/compliance/controls/azure/azure_cis_v140_1_17.yaml old mode 100755 new mode 100644 index 0cb82f562..56cd901cf --- a/compliance/controls/azure/azure_cis_v140_1_17.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_17.yaml @@ -1,19 +1,19 @@ +Description: Restrict security group management to administrators only. ID: azure_cis_v140_1_17 -Title: "1.17 Ensure that 'Owners can manage group membership requests in the Access Panel' is set to 'No'" -Description: "Restrict security group management to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.17 Ensure that 'Owners can manage group membership requests in the Access Panel' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_18.yaml b/compliance/controls/azure/azure_cis_v140_1_18.yaml old mode 100755 new mode 100644 index fca44957d..094d84f53 --- a/compliance/controls/azure/azure_cis_v140_1_18.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_18.yaml @@ -1,19 +1,19 @@ +Description: Restrict Microsoft 365 group creation to administrators only. ID: azure_cis_v140_1_18 -Title: "1.18 Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No'" -Description: "Restrict Microsoft 365 group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.18 Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_19.yaml b/compliance/controls/azure/azure_cis_v140_1_19.yaml old mode 100755 new mode 100644 index a3be56c6b..f059d59bf --- a/compliance/controls/azure/azure_cis_v140_1_19.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_19.yaml @@ -1,19 +1,19 @@ +Description: Joining or registering devices to the active directory should require Multi-factor authentication. ID: azure_cis_v140_1_19 -Title: "1.19 Ensure that 'Require Multi-Factor Authentication to register or join devices with Azure AD' is set to 'Yes'" -Description: "Joining or registering devices to the active directory should require Multi-factor authentication." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.19 Ensure that 'Require Multi-Factor Authentication to register or join devices with Azure AD' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_2.yaml b/compliance/controls/azure/azure_cis_v140_1_2.yaml old mode 100755 new mode 100644 index 2fc34ebb8..845971983 --- a/compliance/controls/azure/azure_cis_v140_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_2.yaml @@ -1,19 +1,19 @@ +Description: Enable multi-factor authentication for all non-privileged users. ID: azure_cis_v140_1_2 -Title: "1.2 Ensure that multi-factor authentication status is enabled for all non- privileged users" -Description: "Enable multi-factor authentication for all non-privileged users." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2 Ensure that multi-factor authentication status is enabled for all non-privileged users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_20.yaml b/compliance/controls/azure/azure_cis_v140_1_20.yaml old mode 100755 new mode 100644 index 9f2f34482..7193d171d --- a/compliance/controls/azure/azure_cis_v140_1_20.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_20.yaml @@ -1,53 +1,53 @@ +Description: Subscription ownership should not include permission to create custom owner roles. The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access. ID: azure_cis_v140_1_20 -Title: "1.20 Ensure that no custom subscription owner roles are created" -Description: "Subscription ownership should not include permission to create custom owner roles. The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with owner_custom_roles as ( - select + ListOfTables: + - azure_role_definition + - azure_subscription + Parameters: [] + PrimaryTable: azure_role_definition + QueryToExecute: | + WITH owner_custom_roles AS ( + SELECT role_name, role_type, title, action, _ctx, subscription_id - from + FROM azure_role_definition, - jsonb_array_elements(permissions) as s, - jsonb_array_elements_text(s -> 'actions') as action - where + JSONB_ARRAY_ELEMENTS(permissions) AS s, + JSONB_ARRAY_ELEMENTS_TEXT(s -> 'actions') AS action + WHERE role_type = 'CustomRole' - and action in ('*', '*:*') + AND action IN ('*', '*:*') ) - select - cr.subscription_id as resource, - cr.og_account_id as og_account_id, - cr.og_resource_id as og_resource_id, - case - when count(*) > 0 then 'alarm' - else 'ok' - end as status, - case - when count(*) = 1 then 'There is one custom owner role.' - when count(*) > 1 then 'There are ' || count(*) || ' custom owner roles.' - else 'There are no custom owner roles.' - end as reason - from + SELECT + cr.subscription_id AS resource, + cr.og_account_id AS og_account_id, + cr.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(*) > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(*) = 1 THEN 'There is one custom owner role.' + WHEN COUNT(*) > 1 THEN 'There are ' || COUNT(*) || ' custom owner roles.' + ELSE 'There are no custom owner roles.' + END AS reason + FROM owner_custom_roles cr, azure_subscription sub - where + WHERE sub.subscription_id = cr.subscription_id - group by + GROUP BY cr.subscription_id, cr._ctx, sub.display_name; - PrimaryTable: azure_role_definition - ListOfTables: - - azure_role_definition - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.20 Ensure that no custom subscription owner roles are created \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_21.yaml b/compliance/controls/azure/azure_cis_v140_1_21.yaml old mode 100755 new mode 100644 index fe0176842..966c5d4a8 --- a/compliance/controls/azure/azure_cis_v140_1_21.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_21.yaml @@ -1,19 +1,19 @@ +Description: Security defaults in Azure Active Directory (Azure AD) make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks. ID: azure_cis_v140_1_21 -Title: "1.21 Ensure Security Defaults is enabled on Azure Active Directory" -Description: "Security defaults in Azure Active Directory (Azure AD) make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.21 Ensure Security Defaults is enabled on Azure Active Directory \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_22.yaml b/compliance/controls/azure/azure_cis_v140_1_22.yaml old mode 100755 new mode 100644 index e5f6a26e4..a80038c38 --- a/compliance/controls/azure/azure_cis_v140_1_22.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_22.yaml @@ -1,19 +1,19 @@ +Description: Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration. ID: azure_cis_v140_1_22 -Title: "1.22 Ensure Custom Role is assigned for Administering Resource Locks" -Description: "Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.22 Ensure Custom Role is assigned for Administering Resource Locks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_3.yaml b/compliance/controls/azure/azure_cis_v140_1_3.yaml old mode 100755 new mode 100644 index 33c731515..6f558780b --- a/compliance/controls/azure/azure_cis_v140_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_3.yaml @@ -1,42 +1,42 @@ +Description: Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Guest users should be review on a monthly basis to ensure that inactive and unneeded accounts are removed. ID: azure_cis_v140_1_3 -Title: "1.3 Ensure guest users are reviewed on a monthly basis" -Description: "Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Guest users should be review on a monthly basis to ensure that inactive and unneeded accounts are removed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_user + Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT DISTINCT + tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - u.display_name as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when not account_enabled then 'alarm' - when u.created_date_time::timestamp <= (current_date - interval '30' day) then 'alarm' - else 'ok' - end as status, - case - when not account_enabled then 'Guest user ''' || u.display_name || ''' inactive.' - else 'Guest user ''' || u.display_name || ''' was created ' || extract(day from current_timestamp - u.created_date_time::timestamp) || ' days ago.' - end as reason, + SELECT + u.display_name AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN NOT account_enabled THEN 'alarm' + WHEN u.created_date_time::timestamp <= (CURRENT_DATE - INTERVAL '30' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT account_enabled THEN 'Guest user ''' || u.display_name || ''' inactive.' + ELSE 'Guest user ''' || u.display_name || ''' was created ' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - u.created_date_time::timestamp) || ' days ago.' + END AS reason, t.tenant_id - from - azuread_user as u - left join distinct_tenant as t on t.tenant_id = u.tenant_id - where + FROM + azuread_user AS u + LEFT JOIN distinct_tenant AS t ON t.tenant_id = u.tenant_id + WHERE u.user_type = 'Guest'; - PrimaryTable: azuread_user - ListOfTables: - - azure_tenant - - azuread_user - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.3 Ensure guest users are reviewed on a monthly basis \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_4.yaml b/compliance/controls/azure/azure_cis_v140_1_4.yaml old mode 100755 new mode 100644 index e259937d5..4ccacc2c1 --- a/compliance/controls/azure/azure_cis_v140_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_4.yaml @@ -1,19 +1,19 @@ +Description: Do not allow users to remember multi-factor authentication on devices. ID: azure_cis_v140_1_4 -Title: "1.4 Ensure that 'Restore multi-factor authentication on all remembered devices' is enabled" -Description: "Do not allow users to remember multi-factor authentication on devices." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.4 Ensure that 'Restore multi-factor authentication on all remembered devices' is enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_5.yaml b/compliance/controls/azure/azure_cis_v140_1_5.yaml old mode 100755 new mode 100644 index 712907b30..91f62dbdf --- a/compliance/controls/azure/azure_cis_v140_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_5.yaml @@ -1,19 +1,19 @@ +Description: Ensure that two alternate forms of identification are provided before allowing a password reset. ID: azure_cis_v140_1_5 -Title: "1.5 Ensure that 'Number of methods required to reset' is set to '2'" -Description: "Ensure that two alternate forms of identification are provided before allowing a password reset." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.5 Ensure that 'Number of methods required to reset' is set to '2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_7.yaml b/compliance/controls/azure/azure_cis_v140_1_7.yaml old mode 100755 new mode 100644 index 90f58dbd4..a72400c61 --- a/compliance/controls/azure/azure_cis_v140_1_7.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_7.yaml @@ -1,19 +1,19 @@ +Description: Ensure that users are notified on their primary and secondary emails on password resets. ID: azure_cis_v140_1_7 -Title: "1.7 Ensure that 'Notify users on password resets?' is set to 'Yes'" -Description: "Ensure that users are notified on their primary and secondary emails on password resets." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.7 Ensure that 'Notify users on password resets?' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_1_9.yaml b/compliance/controls/azure/azure_cis_v140_1_9.yaml old mode 100755 new mode 100644 index c05c4022c..df591852b --- a/compliance/controls/azure/azure_cis_v140_1_9.yaml +++ b/compliance/controls/azure/azure_cis_v140_1_9.yaml @@ -1,19 +1,19 @@ +Description: Require administrators to provide consent for the apps before use. ID: azure_cis_v140_1_9 -Title: "1.9 Ensure that 'Users can consent to apps accessing company data on their behalf' is set to 'No'" -Description: "Require administrators to provide consent for the apps before use." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.9 Ensure that 'Users can consent to apps accessing company data on their behalf' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_1.yaml b/compliance/controls/azure/azure_cis_v140_2_1.yaml old mode 100755 new mode 100644 index a2e62f79f..84cf3f013 --- a/compliance/controls/azure/azure_cis_v140_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_1.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v140_2_1 -Title: "2.1 Ensure that Microsoft Defender for Servers is set to 'On'" -Description: "Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Servers.' - else 'Azure Defender off for Servers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'VirtualMachines'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Servers.' + ELSE 'Azure Defender off for Servers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'VirtualMachines'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1 Ensure that Microsoft Defender for Servers is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_10.yaml b/compliance/controls/azure/azure_cis_v140_2_10.yaml old mode 100755 new mode 100644 index 5b298360c..344c356c1 --- a/compliance/controls/azure/azure_cis_v140_2_10.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_10.yaml @@ -1,32 +1,33 @@ +Description: This setting enables Microsoft Defender for Cloud Apps (MCAS) integration with Microsoft Defender for Cloud. ID: azure_cis_v140_2_10 -Title: "2.10 Ensure that Microsoft Defender for Cloud Apps (MCAS) Integration with Microsoft Defender for Cloud is Selected" -Description: "This setting enables Microsoft Defender for Cloud Apps (MCAS) integration with Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_sett.id as resource, - sc_sett.og_account_id as og_account_id, - sc_sett.og_resource_id as og_resource_id, - case - when enabled then 'ok' - else 'alarm' - end as status, - case - when enabled then 'Windows Defender ATP (WDATP) integrated with Security Center.' - else 'Windows Defender ATP (WDATP) not integrated with Security Center.' - end as reason - from - azure_security_center_setting sc_sett - right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id - where - name = 'MCAS'; - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Windows Defender ATP (WDATP) integrated with Security Center.' + ELSE 'Windows Defender ATP (WDATP) not integrated with Security Center.' + END AS reason + FROM + azure_security_center_setting sc_sett + RIGHT JOIN azure_subscription sub + ON sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'MCAS'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.10 Ensure that Microsoft Defender for Cloud Apps (MCAS) Integration with Microsoft Defender for Cloud is Selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_11.yaml b/compliance/controls/azure/azure_cis_v140_2_11.yaml old mode 100755 new mode 100644 index 518836983..f505a86f5 --- a/compliance/controls/azure/azure_cis_v140_2_11.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_11.yaml @@ -1,30 +1,32 @@ +Description: Enable automatic provisioning of the monitoring agent to collect security data. ID: azure_cis_v140_2_11 -Title: "2.11 Ensure That Auto provisioning of 'Log Analytics agent for Azure VMs' is Set to 'On'" -Description: "Enable automatic provisioning of the monitoring agent to collect security data." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_prov.id as resource, - sc_prov.og_account_id as og_account_id, - sc_prov.og_resource_id as og_resource_id, - case - when auto_provision = 'On' then 'ok' - else 'alarm' - end as status, - case - when auto_provision = 'On' then 'Automatic provisioning of monitoring agent is on.' - else 'Automatic provisioning of monitoring agent is off.' - end as reason - from - azure_security_center_auto_provisioning sc_prov - right join azure_subscription sub on sc_prov.subscription_id = sub.subscription_id; - PrimaryTable: azure_security_center_auto_provisioning ListOfTables: - azure_security_center_auto_provisioning - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_auto_provisioning + QueryToExecute: | + SELECT + sc_prov.id AS resource, + sc_prov.og_account_id AS og_account_id, + sc_prov.og_resource_id AS og_resource_id, + CASE + WHEN auto_provision = 'On' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_provision = 'On' THEN 'Automatic provisioning of monitoring agent is on.' + ELSE 'Automatic provisioning of monitoring agent is off.' + END AS reason + FROM + azure_security_center_auto_provisioning sc_prov + RIGHT JOIN + azure_subscription sub + ON sc_prov.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.11 Ensure That Auto provisioning of 'Log Analytics agent for Azure VMs' is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_12.yaml b/compliance/controls/azure/azure_cis_v140_2_12.yaml old mode 100755 new mode 100644 index 6d76f7652..07e04e070 --- a/compliance/controls/azure/azure_cis_v140_2_12.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_12.yaml @@ -1,15 +1,50 @@ +Description: None of the settings offered by ASC Default policy should be set to effect "Disabled". ID: azure_cis_v140_2_12 -Title: "2.12 Ensure Any of the ASC Default Policy Setting is Not Set to 'Disabled'" -Description: "None of the settings offered by ASC Default policy should be set to effect \\\"Disabled\\\"." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with policy_assignment_parameters as (\n select\n id,\n name,\n key,\n parameters -> key ->> 'value' as value,\n subscription_id\n from\n azure_policy_assignment,\n jsonb_object_keys(parameters) as key\n where\n name = 'SecurityCenterBuiltIn'\n)\nselect\n sub.id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(value = 'Disabled') > 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when count(value = 'Disabled') > 0 then 'Settings disabled for ' || count(*) filter (where value = 'Disabled') || ' parameters.'\n else 'Settings enabled for all the parameters.'\n end as reason\n \n \nfrom\n policy_assignment_parameters pol_assignment\n right join azure_subscription sub on pol_assignment.subscription_id = sub.subscription_id\ngroup by\n sub.id,\n pol_assignment.id,\n sub._ctx,\n sub.subscription_id,\n pol_assignment.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_policy_assignment ListOfTables: - azure_policy_assignment - azure_subscription Parameters: [] + PrimaryTable: azure_policy_assignment + QueryToExecute: | + WITH policy_assignment_parameters AS ( + SELECT + id, + name, + key, + parameters -> key ->> 'value' AS value, + subscription_id + FROM + azure_policy_assignment, + jsonb_object_keys(parameters) AS key + WHERE + name = 'SecurityCenterBuiltIn' + ) + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(value = 'Disabled') > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(value = 'Disabled') > 0 THEN 'Settings disabled for ' || COUNT(*) FILTER (WHERE value = 'Disabled') || ' parameters.' + ELSE 'Settings enabled for all the parameters.' + END AS reason + FROM + policy_assignment_parameters pol_assignment + RIGHT JOIN azure_subscription sub ON pol_assignment.subscription_id = sub.subscription_id + GROUP BY + sub.id, + pol_assignment.id, + sub._ctx, + sub.subscription_id, + pol_assignment.subscription_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.12 Ensure Any of the ASC Default Policy Setting is Not Set to 'Disabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_13.yaml b/compliance/controls/azure/azure_cis_v140_2_13.yaml old mode 100755 new mode 100644 index ae3b5445a..4689ba202 --- a/compliance/controls/azure/azure_cis_v140_2_13.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_13.yaml @@ -1,15 +1,44 @@ +Description: Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address. ID: azure_cis_v140_2_13 -Title: "2.13 Ensure 'Additional email addresses' is Configured with a Security Contact Email" -Description: "Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with contact_info as (\n select\n jsonb_agg(email) filter (where name = 'default' and email != '') as default_email,\n count(*) filter (where name != 'default') as non_default_count,\n count(*) filter (where name = 'default') as default_count,\n subscription_id\n from\n azure_security_center_contact\n group by\n subscription_id\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when non_default_count > 0 then 'ok'\n when default_count = 1 and jsonb_array_length(default_email) != 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when non_default_count > 0 then 'Additional email addresses configured.'\n when default_count = 1 and default_email is not null then'Additional email addresses configured.'\n else 'Additional email addresses not configured.'\n end as reason\n \n \nfrom\n azure_subscription sub\n left join contact_info ci on sub.subscription_id = ci.subscription_id;" - PrimaryTable: azure_security_center_contact ListOfTables: - azure_security_center_contact - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_contact + QueryToExecute: | + WITH contact_info AS ( + SELECT + jsonb_agg(email) FILTER (WHERE name = 'default' AND email != '') AS default_email, + COUNT(*) FILTER (WHERE name != 'default') AS non_default_count, + COUNT(*) FILTER (WHERE name = 'default') AS default_count, + subscription_id + FROM + azure_security_center_contact + GROUP BY + subscription_id + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN non_default_count > 0 THEN 'ok' + WHEN default_count = 1 AND jsonb_array_length(default_email) != 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN non_default_count > 0 THEN 'Additional email addresses configured.' + WHEN default_count = 1 AND default_email IS NOT NULL THEN 'Additional email addresses configured.' + ELSE 'Additional email addresses not configured.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.13 Ensure 'Additional email addresses' is Configured with a Security Contact Email \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_14.yaml b/compliance/controls/azure/azure_cis_v140_2_14.yaml old mode 100755 new mode 100644 index 20d96417e..1dc323437 --- a/compliance/controls/azure/azure_cis_v140_2_14.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_14.yaml @@ -1,40 +1,40 @@ +Description: Enables emailing security alerts to the subscription owner or other designated security contact. ID: azure_cis_v140_2_14 -Title: "2.14 Ensure that 'Notify about alerts with the following severity' is set to 'High'" -Description: "Enables emailing security alerts to the subscription owner or other designated security contact." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with contact_info as ( - select - count(*) filter (where alert_notifications = 'On') as notification_alert_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alert_notifications = 'On') AS notification_alert_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when notification_alert_count > 0 then 'ok' - else 'alarm' - end as status, - case - when notification_alert_count > 0 then '"Notify about alerts with the following severity" set to High.' - else '"Notify about alerts with the following severity" not set to High.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN notification_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN notification_alert_count > 0 THEN '"Notify about alerts with the following severity" set to High.' + ELSE '"Notify about alerts with the following severity" not set to High.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.14 Ensure that 'Notify about alerts with the following severity' is set to 'High' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_15.yaml b/compliance/controls/azure/azure_cis_v140_2_15.yaml old mode 100755 new mode 100644 index 02549f947..e5efc691b --- a/compliance/controls/azure/azure_cis_v140_2_15.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_15.yaml @@ -1,42 +1,40 @@ +Description: Enable security alert emails to subscription owners. ID: azure_cis_v140_2_15 -Title: "2.15 Ensure that 'All users with the following roles' is set to 'Owner'" -Description: "Enable security alert emails to subscription owners." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with contact_info as ( - select - count(*) filter (where alerts_to_admins = 'On') as admin_alert_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alerts_to_admins = 'On') AS admin_alert_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when admin_alert_count > 0 then 'ok' - else 'alarm' - end as status, - case - when admin_alert_count > 0 then '"All users with the following roles" set to Owner' - else '"All users with the following roles" not set to Owner.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN admin_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN admin_alert_count > 0 THEN '"All users with the following roles" set to Owner' + ELSE '"All users with the following roles" not set to Owner.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - ``` - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.15 Ensure that 'All users with the following roles' is set to 'Owner' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_2.yaml b/compliance/controls/azure/azure_cis_v140_2_2.yaml old mode 100755 new mode 100644 index afce4f5a1..2f712aafd --- a/compliance/controls/azure/azure_cis_v140_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_2.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v140_2_2 -Title: "2.2 Ensure that Microsoft Defender for App Service is set to 'On'" -Description: "Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for App Services.' - else 'Azure Defender off for App Services.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'AppServices'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for App Services.' + ELSE 'Azure Defender off for App Services.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'AppServices'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.2 Ensure that Microsoft Defender for App Service is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_3.yaml b/compliance/controls/azure/azure_cis_v140_2_3.yaml old mode 100755 new mode 100644 index 21cec300c..2a13b23cd --- a/compliance/controls/azure/azure_cis_v140_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_3.yaml @@ -1,15 +1,33 @@ +Description: Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v140_2_3 -Title: "2.3 Ensure that Microsoft Defender for Azure SQL Databases is set to 'On'" -Description: "Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for SQL database servers.'\n else 'Azure Defender off for SQL database servers.'\n end as reason\n \n \nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'SqlServers';" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL database servers.' + ELSE 'Azure Defender off for SQL database servers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServers'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.3 Ensure that Microsoft Defender for Azure SQL Databases is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_4.yaml b/compliance/controls/azure/azure_cis_v140_2_4.yaml old mode 100755 new mode 100644 index 407d1e81e..7f79f5c95 --- a/compliance/controls/azure/azure_cis_v140_2_4.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_4.yaml @@ -1,33 +1,32 @@ +Description: Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v140_2_4 -Title: "2.4 Ensure that Microsoft Defender for SQL servers on machines is set to 'On'" -Description: "Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for SQL servers on machines.' - else 'Azure Defender off for SQL servers on machines.' - end as reason - - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'SqlServerVirtualMachines'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL servers on machines.' + ELSE 'Azure Defender off for SQL servers on machines.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServerVirtualMachines'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.4 Ensure that Microsoft Defender for SQL servers on machines is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_5.yaml b/compliance/controls/azure/azure_cis_v140_2_5.yaml old mode 100755 new mode 100644 index de7881043..18b3eaf7f --- a/compliance/controls/azure/azure_cis_v140_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_5.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v140_2_5 -Title: "2.5 Ensure that Microsoft Defender for Storage is set to 'On'" -Description: "Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Storage.' - else 'Azure Defender off for Storage.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'StorageAccounts'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Storage.' + ELSE 'Azure Defender off for Storage.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'StorageAccounts'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.5 Ensure that Microsoft Defender for Storage is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_6.yaml b/compliance/controls/azure/azure_cis_v140_2_6.yaml old mode 100755 new mode 100644 index f70aa4f8d..3f5cce57f --- a/compliance/controls/azure/azure_cis_v140_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_6.yaml @@ -1,15 +1,33 @@ +Description: Turning on Microsoft Defender for Kubernetes enables threat detection for Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v140_2_6 -Title: "2.6 Ensure that Microsoft Defender for Kubernetes is set to 'On'" -Description: "Turning on Microsoft Defender for Kubernetes enables threat detection for Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Kubernetes.'\n else 'Azure Defender off for Kubernetes.'\n end as reason\n \n \nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'KubernetesService';" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Kubernetes.' + ELSE 'Azure Defender off for Kubernetes.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'KubernetesService'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.6 Ensure that Microsoft Defender for Kubernetes is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_7.yaml b/compliance/controls/azure/azure_cis_v140_2_7.yaml old mode 100755 new mode 100644 index a2325f2fe..e8aa38249 --- a/compliance/controls/azure/azure_cis_v140_2_7.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_7.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Container Registries enables threat detection for Container Registries, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v140_2_7 -Title: "2.7 Ensure that Microsoft Defender for Container Registries is set to 'On'" -Description: "Turning on Microsoft Defender for Container Registries enables threat detection for Container Registries, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Container Registry.' - else 'Azure Defender off for Container Registry.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'ContainerRegistry'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Container Registry.' + ELSE 'Azure Defender off for Container Registry.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'ContainerRegistry'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.7 Ensure that Microsoft Defender for Container Registries is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_8.yaml b/compliance/controls/azure/azure_cis_v140_2_8.yaml old mode 100755 new mode 100644 index 74a49e477..328fa7d8e --- a/compliance/controls/azure/azure_cis_v140_2_8.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_8.yaml @@ -1,32 +1,35 @@ +Description: Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v140_2_8 -Title: "2.8 Ensure that Microsoft Defender for Key Vault is set to 'On'" -Description: "Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Key Vaults.' - else 'Azure Defender off for Key Vaults.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'KeyVaults'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Key Vaults.' + ELSE 'Azure Defender off for Key Vaults.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'KeyVaults'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.8 Ensure that Microsoft Defender for Key Vault is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_2_9.yaml b/compliance/controls/azure/azure_cis_v140_2_9.yaml old mode 100755 new mode 100644 index aca4189aa..7558795c5 --- a/compliance/controls/azure/azure_cis_v140_2_9.yaml +++ b/compliance/controls/azure/azure_cis_v140_2_9.yaml @@ -1,15 +1,33 @@ +Description: This setting enables Microsoft Defender for Endpoint integration with Microsoft Defender for Cloud. ID: azure_cis_v140_2_9 -Title: "2.9 Ensure that Microsoft Defender for Endpoint (WDATP) integration with Microsoft Defender for Cloud is selected" -Description: "This setting enables Microsoft Defender for Endpoint integration with Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sc_sett.id as resource,\n sc_sett.og_account_id as og_account_id,\n sc_sett.og_resource_id as og_resource_id,\n case\n when enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when enabled then 'Microsoft Cloud App Security (MCAS) integrated with Security Center.'\n else 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.'\n end as reason\n \n \nfrom\n azure_security_center_setting sc_sett\n right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id\nwhere\n name = 'WDATP';" - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Microsoft Cloud App Security (MCAS) integrated with Security Center.' + ELSE 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.' + END AS reason + FROM + azure_security_center_setting sc_sett + RIGHT JOIN + azure_subscription sub ON sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'WDATP'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.9 Ensure that Microsoft Defender for Endpoint (WDATP) integration with Microsoft Defender for Cloud is selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_1.yaml b/compliance/controls/azure/azure_cis_v140_3_1.yaml old mode 100755 new mode 100644 index 051f06d2a..a4587fd7b --- a/compliance/controls/azure/azure_cis_v140_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_1.yaml @@ -1,32 +1,32 @@ +Description: Enable data encryption in transit. ID: azure_cis_v140_3_1 -Title: "3.1 Ensure that 'Secure transfer required' is set to 'Enabled'" -Description: "Enable data encryption in transit." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not enable_https_traffic_only then 'alarm' - else 'ok' - end as status, - case - when not enable_https_traffic_only then sa.name || ' encryption in transit not enabled.' - else sa.name || ' encryption in transit enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT enable_https_traffic_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT enable_https_traffic_only THEN sa.name || ' encryption in transit not enabled.' + ELSE sa.name || ' encryption in transit enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.1 Ensure that 'Secure transfer required' is set to 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_10.yaml b/compliance/controls/azure/azure_cis_v140_3_10.yaml old mode 100755 new mode 100644 index f099c6a56..ba1f953ae --- a/compliance/controls/azure/azure_cis_v140_3_10.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_10.yaml @@ -1,41 +1,43 @@ +Description: 'The Storage Blob service provides scalable, cost-efficient objective storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details , concurrency information and the sizes of the request and response messages.' ID: azure_cis_v140_3_10 -Title: "3.10 Ensure Storage logging is enabled for Blob service for 'Read', 'Write', and 'Delete' requests" -Description: "The Storage Blob service provides scalable, cost-efficient objective storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details , concurrency information and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not (sa.blob_service_logging ->> 'Read') :: boolean - or not (sa.blob_service_logging ->> 'Write') :: boolean - or not (sa.blob_service_logging ->> 'Delete') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (sa.blob_service_logging ->> 'Read') :: boolean - or not (sa.blob_service_logging ->> 'Write') :: boolean - or not (sa.blob_service_logging ->> 'Delete') :: boolean then name || ' blob service logging not enabled for ' || - concat_ws(', ', - case when not (sa.blob_service_logging ->> 'Write') :: boolean then 'write' end, - case when not (sa.blob_service_logging ->> 'Read') :: boolean then 'read' end, - case when not (sa.blob_service_logging ->> 'Delete') :: boolean then 'delete' end - ) || ' requests.' - else name || ' blob service logging enabled for read, write, delete requests.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read'):: BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write'):: BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete'):: BOOLEAN + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read'):: BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write'):: BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete'):: BOOLEAN + THEN name || ' blob service logging not enabled for ' || + CONCAT_WS(', ', + CASE WHEN NOT (sa.blob_service_logging ->> 'Write'):: BOOLEAN THEN 'write' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Read'):: BOOLEAN THEN 'read' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Delete'):: BOOLEAN THEN 'delete' END + ) || ' requests.' + ELSE name || ' blob service logging enabled for read, write, delete requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.10 Ensure Storage logging is enabled for Blob service for 'Read', 'Write', and 'Delete' requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_11.yaml b/compliance/controls/azure/azure_cis_v140_3_11.yaml old mode 100755 new mode 100644 index 9d36d2a94..753bf9363 --- a/compliance/controls/azure/azure_cis_v140_3_11.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_11.yaml @@ -1,24 +1,24 @@ +Description: 'The Storage Table storage is a service that stores structure NoSQL data in the cloud, providing a key/attribute store with a schema less design. Storage Logging happens server- side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details , concurrency information and the sizes of the request and response messages.' ID: azure_cis_v140_3_11 -Title: "3.11 Ensure Storage logging is enabled for Table service for 'Read', 'Write', and 'Delete' requests" -Description: "The Storage Table storage is a service that stores structure NoSQL data in the cloud, providing a key/attribute store with a schema less design. Storage Logging happens server- side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details , concurrency information and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.11 Ensure Storage logging is enabled for Table service for 'Read', 'Write', and 'Delete' requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_12.yaml b/compliance/controls/azure/azure_cis_v140_3_12.yaml old mode 100755 new mode 100644 index 90115545c..20c587a70 --- a/compliance/controls/azure/azure_cis_v140_3_12.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_12.yaml @@ -1,34 +1,34 @@ +Description: Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2. ID: azure_cis_v140_3_12 -Title: "3.12 Ensure the 'Minimum TLS version' is set to 'Version 1.2'" -Description: "Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when minimum_tls_version = 'TLSEnforcementDisabled' then 'alarm' - when minimum_tls_version = 'TLS1_2' then 'ok' - else 'alarm' - end as status, - case - when minimum_tls_version = 'TLSEnforcementDisabled' then sa.name || ' TLS enforcement is disabled.' - when minimum_tls_version = 'TLS1_2' then sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' - else sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN minimum_tls_version = 'TLSEnforcementDisabled' THEN 'alarm' + WHEN minimum_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_tls_version = 'TLSEnforcementDisabled' THEN sa.name || ' TLS enforcement is disabled.' + WHEN minimum_tls_version = 'TLS1_2' THEN sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + ELSE sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.12 Ensure the 'Minimum TLS version' is set to 'Version 1.2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_2.yaml b/compliance/controls/azure/azure_cis_v140_3_2.yaml old mode 100755 new mode 100644 index ba1bc80ba..34edc2429 --- a/compliance/controls/azure/azure_cis_v140_3_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_2.yaml @@ -1,24 +1,24 @@ +Description: Regenerate storage account access keys periodically. ID: azure_cis_v140_3_2 -Title: "3.2 Ensure that storage account access keys are periodically regenerated" -Description: "Regenerate storage account access keys periodically." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.2 Ensure that storage account access keys are periodically regenerated \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_3.yaml b/compliance/controls/azure/azure_cis_v140_3_3.yaml old mode 100755 new mode 100644 index 331ec6759..9c05bf485 --- a/compliance/controls/azure/azure_cis_v140_3_3.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_3.yaml @@ -1,38 +1,38 @@ +Description: 'The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information and the sizes of the request and response messages.' ID: azure_cis_v140_3_3 -Title: "3.3 Ensure Storage logging is enabled for Queue service for 'Read', 'Write', and 'Delete' requests" -Description: "The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details , concurrency information and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when queue_logging_read and queue_logging_write and queue_logging_delete then 'ok' - else 'alarm' - end as status, - case - when queue_logging_read and queue_logging_write and queue_logging_delete - then sa.name || ' queue service logging enabled for read, write, delete requests.' - else sa.name || ' queue service logging not enabled for: ' || + ListOfTables: + - azure_storage_account + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete + THEN sa.name || ' queue service logging enabled for read, write, delete requests.' + ELSE sa.name || ' queue service logging not enabled for: ' || concat_ws(', ', - case when not queue_logging_write then 'write' end, - case when not queue_logging_read then 'read' end, - case when not queue_logging_delete then 'delete' end + CASE WHEN NOT queue_logging_write THEN 'write' END, + CASE WHEN NOT queue_logging_read THEN 'read' END, + CASE WHEN NOT queue_logging_delete THEN 'delete' END ) || ' requests.' - end as reason - from + END AS reason + FROM azure_storage_account sa, azure_subscription sub - where + WHERE sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.3 Ensure Storage logging is enabled for Queue service for 'Read', 'Write', and 'Delete' requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_4.yaml b/compliance/controls/azure/azure_cis_v140_3_4.yaml old mode 100755 new mode 100644 index 83c057933..dc818a9dc --- a/compliance/controls/azure/azure_cis_v140_3_4.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_4.yaml @@ -1,24 +1,24 @@ +Description: A shared access signature (SAS) is a URI that grants restricted access rights to Azure Storage resources. A shared access signature can be provided to clients who should not be trusted with the storage account key but for whom it may be necessary to delegate access to certain storage account resources. Providing a shared access signature URI to these clients allows them access to a resource for a specified period of time. This time should be set as low as possible and preferably no longer than an hour. ID: azure_cis_v140_3_4 -Title: "3.4 Ensure that shared access signature tokens expire within an hour" -Description: "A shared access signature (SAS) is a URI that grants restricted access rights to Azure Storage resources. A shared access signature can be provided to clients who should not be trusted with the storage account key but for whom it may be necessary to delegate access to certain storage account resources. Providing a shared access signature URI to these clients allows them access to a resource for a specified period of time. This time should be set as low as possible and preferably no longer than an hour." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.4 Ensure that shared access signature tokens expire within an hour \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_6.yaml b/compliance/controls/azure/azure_cis_v140_3_6.yaml old mode 100755 new mode 100644 index 450d12864..13cf37ae7 --- a/compliance/controls/azure/azure_cis_v140_3_6.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_6.yaml @@ -1,32 +1,32 @@ +Description: Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed. ID: azure_cis_v140_3_6 -Title: "3.6 Ensure default network access rule for Storage Accounts is set to deny" -Description: "Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when sa.network_rule_default_action = 'Allow' then 'alarm' - else 'ok' - end as status, - case - when sa.network_rule_default_action = 'Allow' then name || ' allows traffic from all networks.' - else name || ' allows traffic from specific networks.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN name || ' allows traffic from all networks.' + ELSE name || ' allows traffic from specific networks.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.6 Ensure default network access rule for Storage Accounts is set to deny \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_7.yaml b/compliance/controls/azure/azure_cis_v140_3_7.yaml old mode 100755 new mode 100644 index 43211cd76..1222435a7 --- a/compliance/controls/azure/azure_cis_v140_3_7.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_7.yaml @@ -1,32 +1,32 @@ +Description: 'Some Microsoft services that interact with storage accounts operate from networks that can''t be granted access through network rules. To help this type of service work as intended, allow the set of trusted Microsoft services to bypass the network rules. These services will then use strong authentication to access the storage account. If the Allow trusted Microsoft services exception is enabled, the following services: Azure Backup, Azure Site Recovery, Azure DevTest Labs, Azure Event Grid, Azure Event Hubs, Azure Networking, Azure Monitor and Azure SQL Data Warehouse (when registered in the subscription), are granted access to the storage account.' ID: azure_cis_v140_3_7 -Title: "3.7 Ensure 'Trusted Microsoft Services' is enabled for Storage Account access" -Description: "Some Microsoft services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Microsoft services to bypass the network rules. These services will then use strong authentication to access the storage account. If the Allow trusted Microsoft services exception is enabled, the following services: Azure Backup, Azure Site Recovery, Azure DevTest Labs, Azure Event Grid, Azure Event Hubs, Azure Networking, Azure Monitor and Azure SQL Data Warehouse (when registered in the subscription), are granted access to the storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when network_rule_bypass not like '%AzureServices%' then 'alarm' - else 'ok' - end as status, - case - when network_rule_bypass not like '%AzureServices%' then sa.name || ' trusted Microsoft services not enabled.' - else sa.name || ' trusted Microsoft services enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN sa.name || ' trusted Microsoft services not enabled.' + ELSE sa.name || ' trusted Microsoft services enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.7 Ensure 'Trusted Microsoft Services' is enabled for Storage Account access \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_8.yaml b/compliance/controls/azure/azure_cis_v140_3_8.yaml old mode 100755 new mode 100644 index db7d22e4b..df4e544a2 --- a/compliance/controls/azure/azure_cis_v140_3_8.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_8.yaml @@ -1,32 +1,32 @@ +Description: The Azure Storage blobs contain data like ePHI, Financial, secret or personal. Erroneously modified or deleted accidentally by an application or other storage account user cause data loss or data unavailability. It is recommended the Azure Storage be made recoverable by enabling soft delete configuration. This is to save and recover data when blobs or blob snapshots are deleted. ID: azure_cis_v140_3_8 -Title: "3.8 Ensure soft delete is enabled for Azure Storage" -Description: "The Azure Storage blobs contain data like ePHI, Financial, secret or personal. Erroneously modified or deleted accidentally by an application or other storage account user cause data loss or data unavailability. It is recommended the Azure Storage be made recoverable by enabling soft delete configuration. This is to save and recover data when blobs or blob snapshots are deleted." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not blob_soft_delete_enabled then 'alarm' - else 'ok' - end as status, - case - when not blob_soft_delete_enabled then sa.name || ' blobs soft delete disabled.' - else sa.name || ' blobs soft delete enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT blob_soft_delete_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT blob_soft_delete_enabled THEN sa.name || ' blobs soft delete disabled.' + ELSE sa.name || ' blobs soft delete enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.8 Ensure soft delete is enabled for Azure Storage \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_3_9.yaml b/compliance/controls/azure/azure_cis_v140_3_9.yaml old mode 100755 new mode 100644 index 0c640dd11..a1dded755 --- a/compliance/controls/azure/azure_cis_v140_3_9.yaml +++ b/compliance/controls/azure/azure_cis_v140_3_9.yaml @@ -1,32 +1,32 @@ +Description: Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys ID: azure_cis_v140_3_9 -Title: "3.9 Ensure storage for critical data are encrypted with Customer Managed Key" -Description: "Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when sa.encryption_key_source = 'Microsoft.Storage' then 'alarm' - else 'ok' - end as status, - case - when sa.encryption_key_source = 'Microsoft.Storage' then sa.name || ' not encrypted with CMK.' - else sa.name || ' encrypted with CMK.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN sa.name || ' not encrypted with CMK.' + ELSE sa.name || ' encrypted with CMK.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.9 Ensure storage for critical data are encrypted with Customer Managed Key \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_4_1_2.yaml b/compliance/controls/azure/azure_cis_v140_4_1_2.yaml old mode 100755 new mode 100644 index b34bc11c7..43ead3b9e --- a/compliance/controls/azure/azure_cis_v140_4_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_4_1_2.yaml @@ -1,33 +1,35 @@ -ID: azure_cis_v140_4_1_2 -Title: "4.1.2 Ensure that 'Data encryption' is set to 'On' on a SQL Database" Description: "" +ID: azure_cis_v140_4_1_2 +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.database_id resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then s.title || ' transparent data encryption enabled.' - else s.title || ' transparent data encryption disabled.' - end as reason - from - azure_sql_database as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id - and s.name <> 'master'; - PrimaryTable: azure_sql_database ListOfTables: - azure_sql_database - azure_subscription Parameters: [] + PrimaryTable: azure_sql_database + QueryToExecute: | + SELECT + s.database_id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' + OR transparent_data_encryption ->> 'state' = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' + OR transparent_data_encryption ->> 'state' = 'Enabled' THEN s.title || ' transparent data encryption enabled.' + ELSE s.title || ' transparent data encryption disabled.' + END AS reason + FROM + azure_sql_database AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id + AND s.name <> 'master'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.2 Ensure that 'Data encryption' is set to 'On' on a SQL Database \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_4_3_1.yaml b/compliance/controls/azure/azure_cis_v140_4_3_1.yaml old mode 100755 new mode 100644 index f49b4dfb0..7c9d874fb --- a/compliance/controls/azure/azure_cis_v140_4_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_4_3_1.yaml @@ -1,32 +1,32 @@ +Description: Enable SSL connection on PostgreSQL Servers. ID: azure_cis_v140_4_3_1 -Title: "4.3.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for PostgreSQL Database Server" -Description: "Enable SSL connection on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when ssl_enforcement = 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when ssl_enforcement = 'Disabled' then name || ' SSL connection disabled.' - else name || ' SSL connection enabled.' - end as reason - from - azure_postgresql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN name || ' SSL connection disabled.' + ELSE name || ' SSL connection enabled.' + END AS reason + FROM + azure_postgresql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_4_3_7.yaml b/compliance/controls/azure/azure_cis_v140_4_3_7.yaml old mode 100755 new mode 100644 index 049c0cadc..687f03539 --- a/compliance/controls/azure/azure_cis_v140_4_3_7.yaml +++ b/compliance/controls/azure/azure_cis_v140_4_3_7.yaml @@ -1,24 +1,24 @@ +Description: Disable access from Azure services to PostgreSQL Database Server. ID: azure_cis_v140_4_3_7 -Title: "4.3.7 Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled" -Description: "Disable access from Azure services to PostgreSQL Database Server." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 4.3.7 Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_4_3_8.yaml b/compliance/controls/azure/azure_cis_v140_4_3_8.yaml old mode 100755 new mode 100644 index 8573a299b..f6fb78781 --- a/compliance/controls/azure/azure_cis_v140_4_3_8.yaml +++ b/compliance/controls/azure/azure_cis_v140_4_3_8.yaml @@ -1,32 +1,32 @@ +Description: Enable encryption at rest for PostgreSQL Databases. ID: azure_cis_v140_4_3_8 -Title: "4.3.8 Ensure 'Infrastructure double encryption' for PostgreSQL Database Server is 'Enabled'" -Description: "Enable encryption at rest for PostgreSQL Databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when infrastructure_encryption = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when infrastructure_encryption = 'Enabled' then name || ' infrastructure encryption enabled.' - else name || ' infrastructure encryption disabled.' - end as reason - from - azure_postgresql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN name || ' infrastructure encryption enabled.' + ELSE name || ' infrastructure encryption disabled.' + END AS reason + FROM + azure_postgresql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.8 Ensure 'Infrastructure double encryption' for PostgreSQL Database Server is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_4_4_1.yaml b/compliance/controls/azure/azure_cis_v140_4_4_1.yaml old mode 100755 new mode 100644 index 8f794db1c..e3eea74e0 --- a/compliance/controls/azure/azure_cis_v140_4_4_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_4_4_1.yaml @@ -1,32 +1,32 @@ +Description: Enable SSL connection on MYSQL Servers. ID: azure_cis_v140_4_4_1 -Title: "4.4.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for MySQL Database Server" -Description: "Enable SSL connection on MYSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when ssl_enforcement = 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when ssl_enforcement = 'Disabled' then s.name || ' SSL connection disabled.' - else s.name || ' SSL connection enabled.' - end as reason - from - azure_mysql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN s.name || ' SSL connection disabled.' + ELSE s.name || ' SSL connection enabled.' + END AS reason + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_4_4_2.yaml b/compliance/controls/azure/azure_cis_v140_4_4_2.yaml old mode 100755 new mode 100644 index cdbd992a5..b02687882 --- a/compliance/controls/azure/azure_cis_v140_4_4_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_4_4_2.yaml @@ -1,34 +1,34 @@ +Description: Ensure TLS version on MySQL flexible servers is set to the default value. ID: azure_cis_v140_4_4_2 -Title: "4.4.2 Ensure 'TLS Version' is set to 'TLSV1.2' for MySQL flexible Database Server" -Description: "Ensure TLS version on MySQL flexible servers is set to the default value." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when minimal_tls_version = 'TLSEnforcementDisabled' then 'alarm' - when minimal_tls_version = 'TLS1_2' then 'ok' - else 'alarm' - end as status, - case - when minimal_tls_version = 'TLSEnforcementDisabled' then s.name || ' TLS enforcement is disabled.' - when minimal_tls_version = 'TLS1_2' then s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' - else s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' - end as reason - from - azure_mysql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN minimal_tls_version = 'TLSEnforcementDisabled' THEN 'alarm' + WHEN minimal_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimal_tls_version = 'TLSEnforcementDisabled' THEN s.name || ' TLS enforcement is disabled.' + WHEN minimal_tls_version = 'TLS1_2' THEN s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' + ELSE s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' + END AS reason + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.2 Ensure 'TLS Version' is set to 'TLSV1.2' for MySQL flexible Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_4_5.yaml b/compliance/controls/azure/azure_cis_v140_4_5.yaml old mode 100755 new mode 100644 index 08ca87697..2acdaa14b --- a/compliance/controls/azure/azure_cis_v140_4_5.yaml +++ b/compliance/controls/azure/azure_cis_v140_4_5.yaml @@ -1,32 +1,32 @@ +Description: Use Azure Active Directory Authentication for authentication with SQL Database. ID: azure_cis_v140_4_5 -Title: "4.5 Ensure that Azure Active Directory Admin is configured" -Description: "Use Azure Active Directory Authentication for authentication with SQL Database." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when server_azure_ad_administrator is null then 'alarm' - else 'ok' - end as status, - case - when server_azure_ad_administrator is null then name || ' Azure AD authentication not configured.' - else name || ' Azure AD authentication configured.' - end as reason - from - azure_sql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN server_azure_ad_administrator IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN server_azure_ad_administrator IS NULL THEN name || ' Azure AD authentication not configured.' + ELSE name || ' Azure AD authentication configured.' + END AS reason + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.5 Ensure that Azure Active Directory Admin is configured \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_1_1.yaml b/compliance/controls/azure/azure_cis_v140_5_1_1.yaml old mode 100755 new mode 100644 index 0e1ea19da..e78cb8480 --- a/compliance/controls/azure/azure_cis_v140_5_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_1_1.yaml @@ -1,24 +1,24 @@ +Description: Enable Diagnostic settings for exporting activity logs. Diagnostic setting are available for each individual resources within a subscription. Settings should be configured for all appropriate resources for your environment. ID: azure_cis_v140_5_1_1 -Title: "5.1.1 Ensure that a 'Diagnostics Setting' exists" -Description: "Enable Diagnostic settings for exporting activity logs. Diagnostic setting are available for each individual resources within a subscription. Settings should be configured for all appropriate resources for your environment." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.1 Ensure that a 'Diagnostics Setting' exists \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_1_2.yaml b/compliance/controls/azure/azure_cis_v140_5_1_2.yaml old mode 100755 new mode 100644 index 1c6058d1a..4307ff7c8 --- a/compliance/controls/azure/azure_cis_v140_5_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_1_2.yaml @@ -1,58 +1,58 @@ +Description: Enable Diagnostic settings for exporting activity logs. Diagnostic setting are available for each individual resources within a subscription. Settings should be configured for all appropriate resources for your environment. ID: azure_cis_v140_5_1_2 -Title: "5.1.2 Ensure Diagnostic Setting captures appropriate categories" -Description: "Enable Diagnostic settings for exporting activity logs. Diagnostic setting are available for each individual resources within a subscription. Settings should be configured for all appropriate resources for your environment." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with enabled_settings as ( - select + ListOfTables: + - azure_diagnostic_setting + - azure_subscription + Parameters: [] + PrimaryTable: azure_diagnostic_setting + QueryToExecute: | + WITH enabled_settings AS ( + SELECT name, id, _ctx, resource_group, subscription_id, - count(*) filter (where l ->> 'enabled' = 'true' - and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy') - ) as valid_category_count, - string_agg(l ->> 'category', ', ') filter (where l ->> 'enabled' = 'true' - and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy') - ) as valid_categories - from + COUNT(*) FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy') + ) AS valid_category_count, + STRING_AGG(l ->> 'category', ', ') FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy') + ) AS valid_categories + FROM azure_diagnostic_setting, - jsonb_array_elements(logs) as l - group by + JSONB_ARRAY_ELEMENTS(logs) AS l + GROUP BY name, id, _ctx, resource_group, subscription_id ) - select - sett.id as resource, - sett.og_account_id as og_account_id, - sett.og_resource_id as og_resource_id, - case - when valid_category_count = 4 then 'ok' - else 'alarm' - end as status, - case - when valid_category_count = 4 - then name || ' logs enabled for required categories administrative, security, alert and policy.' - when valid_category_count > 0 - then sett.name || ' logs enabled for ' || valid_categories || ' categories.' - else sett.name || ' logs not enabled for categories administrative, security, alert and policy.' - end as reason - from + SELECT + sett.id AS resource, + sett.og_account_id AS og_account_id, + sett.og_resource_id AS og_resource_id, + CASE + WHEN valid_category_count = 4 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN valid_category_count = 4 + THEN name || ' logs enabled for required categories administrative, security, alert and policy.' + WHEN valid_category_count > 0 + THEN sett.name || ' logs enabled for ' || valid_categories || ' categories.' + ELSE sett.name || ' logs not enabled for categories administrative, security, alert and policy.' + END AS reason + FROM enabled_settings sett, azure_subscription sub - where + WHERE sub.subscription_id = sett.subscription_id; - PrimaryTable: azure_diagnostic_setting - ListOfTables: - - azure_diagnostic_setting - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.2 Ensure Diagnostic Setting captures appropriate categories \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_1_3.yaml b/compliance/controls/azure/azure_cis_v140_5_1_3.yaml old mode 100755 new mode 100644 index 12bee2ac1..ef6732c38 --- a/compliance/controls/azure/azure_cis_v140_5_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_1_3.yaml @@ -1,34 +1,34 @@ +Description: The storage account container containing the activity log export should not be publicly accessible. ID: azure_cis_v140_5_1_3 -Title: "5.1.3 Ensure the storage container storing the activity logs is not publicly accessible" -Description: "The storage account container containing the activity log export should not be publicly accessible." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc.id as resource, - sc.og_account_id as og_account_id, - sc.og_resource_id as og_resource_id, - case - when public_access != 'None' then 'alarm' - else 'ok' - end as status, - case - when public_access != 'None' - then account_name || ' container insights-operational-logs storing activity logs publicly accessible.' - else account_name || ' container insights-operational-logs storing activity logs not publicly accessible.' - end as reason - from - azure_storage_container sc, - azure_subscription sub - where - name = 'insights-operational-logs' - and sub.subscription_id = sc.subscription_id; - PrimaryTable: azure_storage_container ListOfTables: - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_container + QueryToExecute: | + SELECT + sc.id AS resource, + sc.og_account_id AS og_account_id, + sc.og_resource_id AS og_resource_id, + CASE + WHEN public_access != 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_access != 'None' + THEN account_name || ' container insights-operational-logs storing activity logs publicly accessible.' + ELSE account_name || ' container insights-operational-logs storing activity logs not publicly accessible.' + END AS reason + FROM + azure_storage_container sc, + azure_subscription sub + WHERE + name = 'insights-operational-logs' + AND sub.subscription_id = sc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.3 Ensure the storage container storing the activity logs is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_1_5.yaml b/compliance/controls/azure/azure_cis_v140_5_1_5.yaml old mode 100755 new mode 100644 index 6827bd9b0..29e123973 --- a/compliance/controls/azure/azure_cis_v140_5_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_1_5.yaml @@ -1,49 +1,49 @@ +Description: Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available. ID: azure_cis_v140_5_1_5 -Title: "5.1.5 Ensure that logging for Azure KeyVault is 'Enabled'" -Description: "Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with logging_details as ( - select - name as key_vault_name - from + ListOfTables: + - azure_key_vault + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + WITH logging_details AS ( + SELECT + name AS key_vault_name + FROM azure_key_vault, jsonb_array_elements(diagnostic_settings) setting, jsonb_array_elements(setting -> 'properties' -> 'logs') log - where - diagnostic_settings is not null - and setting -> 'properties' ->> 'storageAccountId' <> '' - and (log ->> 'enabled') :: boolean - and log ->> 'category' = 'AuditEvent' - and (log -> 'retentionPolicy') :: JSONB ? 'days' + WHERE + diagnostic_settings IS NOT NULL + AND setting -> 'properties' ->> 'storageAccountId' <> '' + AND (log ->> 'enabled')::BOOLEAN + AND log ->> 'category' = 'AuditEvent' + AND (log -> 'retentionPolicy')::JSONB ? 'days' ) - select - v.id as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when v.diagnostic_settings is null then 'alarm' - when l.key_vault_name not like concat('%', v.name, '%') then 'alarm' - else 'ok' - end as status, - case - when v.diagnostic_settings is null then v.name || ' logging not enabled.' - when l.key_vault_name not like concat('%', v.name, '%') then v.name || ' logging not enabled.' - else v.name || ' logging enabled.' - end as reason - from + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason + FROM azure_key_vault v, logging_details l, azure_subscription sub - where + WHERE sub.subscription_id = v.subscription_id; - PrimaryTable: azure_key_vault - ListOfTables: - - azure_key_vault - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.5 Ensure that logging for Azure KeyVault is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_2_1.yaml b/compliance/controls/azure/azure_cis_v140_5_2_1.yaml old mode 100755 new mode 100644 index 834e81275..f27001a3c --- a/compliance/controls/azure/azure_cis_v140_5_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_2_1.yaml @@ -1,53 +1,53 @@ +Description: Create an activity log alert for the Create Policy Assignment event. ID: azure_cis_v140_5_2_1 -Title: "5.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment" -Description: "Create an activity log alert for the Create Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' - limit 1 + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' + LIMIT 1 ) - select - a.subscription_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create policy assignment event.' - else 'Activity log alert does not exists for create policy assignment event.' - end as reason - from + SELECT + a.subscription_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create policy assignment event.' + ELSE 'Activity log alert does not exist for create policy assignment event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY a.subscription_id, sub.subscription_id, sub._ctx, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_2_2.yaml b/compliance/controls/azure/azure_cis_v140_5_2_2.yaml old mode 100755 new mode 100644 index 89c575a57..334f74639 --- a/compliance/controls/azure/azure_cis_v140_5_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_2_2.yaml @@ -1,52 +1,52 @@ +Description: Create an activity log alert for the Delete Policy Assignment event. ID: azure_cis_v140_5_2_2 -Title: "5.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment" -Description: "Create an activity log alert for the Delete Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/delete"}]' - limit 1 + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/delete"}]' + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete policy assignment event.' - else 'Activity log alert does not exists for delete policy assignment event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete policy assignment event.' + ELSE 'Activity log alert does not exist for delete policy assignment event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_2_3.yaml b/compliance/controls/azure/azure_cis_v140_5_2_3.yaml old mode 100755 new mode 100644 index 99c37ee9f..565d1501d --- a/compliance/controls/azure/azure_cis_v140_5_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_2_3.yaml @@ -1,64 +1,62 @@ +Description: Create an Activity Log Alert for the "Create" or "Update Network Security Group" event. ID: azure_cis_v140_5_2_3 -Title: "5.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group" -Description: "Create an Activity Log Alert for the \\\"Create\\\" or \\\"Update Network Security Group\\\" event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, - alert.enabled, - alert.location, - alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where - alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' - ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - ) - ) - limit 1 - ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Network Security Group event.' - else 'Activity log alert does not exists for create or update Network Security Group event.' - end as reason - from - azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by - sub._ctx, - sub.subscription_id, - sub.display_name; - ``` - PrimaryTable: azure_subscription ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' + ) + OR + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Network Security Group event.' + ELSE 'Activity log alert does not exist for create or update Network Security Group event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_2_4.yaml b/compliance/controls/azure/azure_cis_v140_5_2_4.yaml old mode 100755 new mode 100644 index c41265ca8..204279620 --- a/compliance/controls/azure/azure_cis_v140_5_2_4.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_2_4.yaml @@ -1,65 +1,63 @@ +Description: Create an activity log alert for the Delete Network Security Group event. ID: azure_cis_v140_5_2_4 -Title: "5.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group" -Description: "Create an activity log alert for the Delete Network Security Group event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id, jsonb_array_length(alert.condition -> 'allOf') - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Network Security Group event.' - else 'Activity log alert does not exists for delete Network Security Group event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Network Security Group event.' + ELSE 'Activity log alert does not exist for delete Network Security Group event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - ``` - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_2_5.yaml b/compliance/controls/azure/azure_cis_v140_5_2_5.yaml old mode 100755 new mode 100644 index 97aa60d44..2e30a62ca --- a/compliance/controls/azure/azure_cis_v140_5_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_2_5.yaml @@ -1,62 +1,60 @@ +Description: Create an activity log alert for the Create or Update Network Security Group Rule event. ID: azure_cis_v140_5_2_5 -Title: "5.2.5 Ensure that Activity Log Alert exists for Create or Update Network Security Group Rule" -Description: "Create an activity log alert for the Create or Update Network Security Group Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networksecuritygroups/securityrules/write"}]' - ) - or - ( + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networksecuritygroups/securityrules/write"}]' + ) OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups/securityrules"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups/securityrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Network Security Group Rule event.' - else 'Activity log alert does not exists for create or update Network Security Group Rule event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Network Security Group Rule event.' + ELSE 'Activity log alert does not exist for create or update Network Security Group Rule event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.5 Ensure that Activity Log Alert exists for Create or Update Network Security Group Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_2_6.yaml b/compliance/controls/azure/azure_cis_v140_5_2_6.yaml old mode 100755 new mode 100644 index 2eb5dda67..9b15973bb --- a/compliance/controls/azure/azure_cis_v140_5_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_2_6.yaml @@ -1,15 +1,62 @@ +Description: Create an activity log alert for the Delete Network Security Group Rule event. ID: azure_cis_v140_5_2_6 -Title: "5.2.6 Ensure that Activity Log Alert exists for Delete Network Security Group Rule" -Description: "Create an activity log alert for the Delete Network Security Group Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and (\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/networksecuritygroups/securityrules/delete\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/networksecuritygroups/securityrules\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Network Security Group Rule event.'\n else 'Activity log alert does not exists for delete Network Security Group Rule event.'\n end as reason\n \n \nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub._ctx,\n sub.subscription_id,\n sub.display_name;" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networksecuritygroups/securityrules/delete"}]' + ) + OR + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups/securityrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Network Security Group Rule event.' + ELSE 'Activity log alert does not exist for delete Network Security Group Rule event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.6 Ensure that Activity Log Alert exists for Delete Network Security Group Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_2_7.yaml b/compliance/controls/azure/azure_cis_v140_5_2_7.yaml old mode 100755 new mode 100644 index 5cfe35254..306cdbc09 --- a/compliance/controls/azure/azure_cis_v140_5_2_7.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_2_7.yaml @@ -1,15 +1,61 @@ +Description: Create an activity log alert for the Create or Update Security Solution event. ID: azure_cis_v140_5_2_7 -Title: "5.2.7 Ensure that Activity Log Alert exists for Create or Update Security Solution" -Description: "Create an activity log alert for the Create or Update Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and (\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Security\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Security/securitySolutions/write\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Security\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.security/securitysolutions\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Security Solution event.'\n else 'Activity log alert does not exists for create or update Security Solution event.'\n end as reason\n \n \nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub._ctx,\n sub.subscription_id,\n sub.display_name;" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/write"}]' + ) + OR ( + alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Security Solution event.' + ELSE 'Activity log alert does not exist for create or update Security Solution event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.7 Ensure that Activity Log Alert exists for Create or Update Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_2_8.yaml b/compliance/controls/azure/azure_cis_v140_5_2_8.yaml old mode 100755 new mode 100644 index 6db58b61d..d07533ec1 --- a/compliance/controls/azure/azure_cis_v140_5_2_8.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_2_8.yaml @@ -1,62 +1,62 @@ +Description: Create an activity log alert for the Delete Security Solution event. ID: azure_cis_v140_5_2_8 -Title: "5.2.8 Ensure that Activity Log Alert exists for Delete Security Solution" -Description: "Create an activity log alert for the Delete Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/delete"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/delete"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Security Solution event.' - else 'Activity log alert does not exists for delete Security Solution event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Security Solution event.' + ELSE 'Activity log alert does not exist for delete Security Solution event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.8 Ensure that Activity Log Alert exists for Delete Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_2_9.yaml b/compliance/controls/azure/azure_cis_v140_5_2_9.yaml old mode 100755 new mode 100644 index 434975526..c051a8dfc --- a/compliance/controls/azure/azure_cis_v140_5_2_9.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_2_9.yaml @@ -1,53 +1,53 @@ +Description: Create an activity log alert for the Create or Update or Delete SQL Server Firewall Rule event. ID: azure_cis_v140_5_2_9 -Title: "5.2.9 Ensure that Activity Log Alert exists for Create or Update or Delete SQL Server Firewall Rule" -Description: "Create an activity log alert for the Create or Update or Delete SQL Server Firewall Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, - alert.enabled, - alert.location, - alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where - alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - limit 1 - ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create, update and delete SQL Server Firewall Rule event.' - else 'Activity log alert does not exist for create, update and delete SQL Server Firewall Rule event.' - end as reason - from - azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by - sub._ctx, - sub.subscription_id, - sub.display_name; - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create, update and delete SQL Server Firewall Rule event.' + ELSE 'Activity log alert does not exist for create, update and delete SQL Server Firewall Rule event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.9 Ensure that Activity Log Alert exists for Create or Update or Delete SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_5_3.yaml b/compliance/controls/azure/azure_cis_v140_5_3.yaml old mode 100755 new mode 100644 index d3bea3441..d2c1c7232 --- a/compliance/controls/azure/azure_cis_v140_5_3.yaml +++ b/compliance/controls/azure/azure_cis_v140_5_3.yaml @@ -1,24 +1,24 @@ +Description: Diagnostic Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself. It is crucial that logging systems are correctly configured to log all relevant activities and retain those logs for a sufficient length of time. ID: azure_cis_v140_5_3 -Title: "5.3 Ensure that Diagnostic Logs are enabled for all services which support it" -Description: "Diagnostic Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself. It is crucial that logging systems are correctly configured to log all relevant activities and retain those logs for a sufficient length of time." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.3 Ensure that Diagnostic Logs are enabled for all services which support it \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_6_1.yaml b/compliance/controls/azure/azure_cis_v140_6_1.yaml old mode 100755 new mode 100644 index 38540b7f8..e292b43ad --- a/compliance/controls/azure/azure_cis_v140_6_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_6_1.yaml @@ -1,54 +1,57 @@ +Description: Disable RDP access on network security groups from the Internet. ID: azure_cis_v140_6_1 -Title: "6.1 Ensure that RDP access is restricted from the internet" -Description: "Disable RDP access on network security groups from the Internet." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || + (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || + (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('3389', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 3389 - and split_part(dport, '-', 2) :: integer >= 3389 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' + OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('3389', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1) :: integer <= 3389 + AND split_part(dport, '-', 2) :: integer >= 3389 ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts RDP access from internet.' - else sg.title || ' allows RDP access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts RDP access from internet.' + ELSE sg.title || ' allows RDP access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.1 Ensure that RDP access is restricted from the internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_6_2.yaml b/compliance/controls/azure/azure_cis_v140_6_2.yaml old mode 100755 new mode 100644 index 58d153137..7a444cab6 --- a/compliance/controls/azure/azure_cis_v140_6_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_6_2.yaml @@ -1,54 +1,54 @@ +Description: Disable SSH access on network security groups from the Internet. ID: azure_cis_v140_6_2 -Title: "6.2 Ensure that SSH access is restricted from the internet" -Description: "Disable SSH access on network security groups from the Internet." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) AS dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('22', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 22 - and split_part(dport, '-', 2) :: integer >= 22 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('22', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1) :: INTEGER <= 22 + AND split_part(dport, '-', 2) :: INTEGER >= 22 ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts SSH access from internet.' - else sg.title || ' allows SSH access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts SSH access from internet.' + ELSE sg.title || ' allows SSH access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.2 Ensure that SSH access is restricted from the internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_6_3.yaml b/compliance/controls/azure/azure_cis_v140_6_3.yaml old mode 100755 new mode 100644 index 135761772..02feec3e7 --- a/compliance/controls/azure/azure_cis_v140_6_3.yaml +++ b/compliance/controls/azure/azure_cis_v140_6_3.yaml @@ -1,36 +1,36 @@ +Description: Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP). ID: azure_cis_v140_6_3 -Title: "6.3 Ensure no SQL Databases allow ingress 0.0.0.0/0 (ANY IP)" -Description: "Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' - or firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' - then 'alarm' - else 'ok' - end as status, - case - when firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' - or firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' - then s.title || ' allows ingress 0.0.0.0/0 or any ip over internet.' - else s.title || ' not allows ingress 0.0.0.0/0 or any ip over internet.' - end as reason - from - azure_sql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN s.title || ' allows ingress 0.0.0.0/0 or any IP over internet.' + ELSE s.title || ' does not allow ingress 0.0.0.0/0 or any IP over internet.' + END AS reason + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.3 Ensure no SQL Databases allow ingress 0.0.0.0/0 (ANY IP) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_6_6.yaml b/compliance/controls/azure/azure_cis_v140_6_6.yaml old mode 100755 new mode 100644 index f1459914d..553bb818b --- a/compliance/controls/azure/azure_cis_v140_6_6.yaml +++ b/compliance/controls/azure/azure_cis_v140_6_6.yaml @@ -1,59 +1,59 @@ +Description: Disable Internet exposed UDP ports on network security groups. ID: azure_cis_v140_6_6 -Title: "6.6 Ensure that UDP Services are restricted from the Internet" -Description: "Disable Internet exposed UDP ports on network security groups." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and sg -> 'properties' ->> 'protocol' = 'UDP' - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' = 'UDP' + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( dport = '*' - or ( - dport like '%-%' - and ( - 53 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 123 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 161 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 389 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 1900 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer + OR ( + dport LIKE '%-%' + AND ( + 53 BETWEEN split_part(dport, '-', 1)::INTEGER AND split_part(dport, '-', 2)::INTEGER + OR 123 BETWEEN split_part(dport, '-', 1)::INTEGER AND split_part(dport, '-', 2)::INTEGER + OR 161 BETWEEN split_part(dport, '-', 1)::INTEGER AND split_part(dport, '-', 2)::INTEGER + OR 389 BETWEEN split_part(dport, '-', 1)::INTEGER AND split_part(dport, '-', 2)::INTEGER + OR 1900 BETWEEN split_part(dport, '-', 1)::INTEGER AND split_part(dport, '-', 2)::INTEGER ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts UDP services from internet.' - else sg.title || ' allows UDP services from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts UDP services from internet.' + ELSE sg.title || ' allows UDP services from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.6 Ensure that UDP Services are restricted from the Internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_7_1.yaml b/compliance/controls/azure/azure_cis_v140_7_1.yaml old mode 100755 new mode 100644 index 96213b0c7..f1e6792e2 --- a/compliance/controls/azure/azure_cis_v140_7_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_7_1.yaml @@ -1,32 +1,32 @@ +Description: Migrate BLOB based VHD's to Managed Disks on Virtual Machines to exploit the default features of this configuration. ID: azure_cis_v140_7_1 -Title: "7.1 Ensure Virtual Machines are utilizing Managed Disks" -Description: "Migrate BLOB based VHD's to Managed Disks on Virtual Machines to exploit the default features of this configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - vm.id as resource, - vm.og_account_id as og_account_id, - vm.og_resource_id as og_resource_id, - case - when managed_disk_id is null then 'alarm' - else 'ok' - end as status, - case - when managed_disk_id is null then vm.name || ' VM not utilizing managed disks.' - else vm.name || ' VM utilizing managed disks.' - end as reason - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where - sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN managed_disk_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN managed_disk_id IS NULL THEN vm.name || ' VM not utilizing managed disks.' + ELSE vm.name || ' VM utilizing managed disks.' + END AS reason + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.1 Ensure Virtual Machines are utilizing Managed Disks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_7_2.yaml b/compliance/controls/azure/azure_cis_v140_7_2.yaml old mode 100755 new mode 100644 index 93c3a95ac..0d0069279 --- a/compliance/controls/azure/azure_cis_v140_7_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_7_2.yaml @@ -1,33 +1,33 @@ +Description: Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE or Server Side Encryption(SSE). ID: azure_cis_v140_7_2 -Title: "7.2 Ensure that 'OS and Data' disks are encrypted with Customer Managed Key (CMK)" -Description: "Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE or Server Side Encryption(SSE)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.' - else disk.name || ' not encrypted with CMK.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state = 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state = 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.2 Ensure that 'OS and Data' disks are encrypted with Customer Managed Key (CMK) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_7_3.yaml b/compliance/controls/azure/azure_cis_v140_7_3.yaml old mode 100755 new mode 100644 index e76511918..d93100067 --- a/compliance/controls/azure/azure_cis_v140_7_3.yaml +++ b/compliance/controls/azure/azure_cis_v140_7_3.yaml @@ -1,33 +1,33 @@ +Description: Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK). ID: azure_cis_v140_7_3 -Title: "7.3 Ensure that 'Unattached disks' are encrypted with CMK" -Description: "Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.' - else disk.name || ' not encrypted with CMK.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state != 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state != 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.3 Ensure that 'Unattached disks' are encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_7_4.yaml b/compliance/controls/azure/azure_cis_v140_7_4.yaml old mode 100755 new mode 100644 index d93d5ee7f..3ddd623a1 --- a/compliance/controls/azure/azure_cis_v140_7_4.yaml +++ b/compliance/controls/azure/azure_cis_v140_7_4.yaml @@ -1,24 +1,24 @@ +Description: For added security only install organization-approved extensions on VMs. ID: azure_cis_v140_7_4 -Title: "7.4 Ensure that only approved extensions are installed" -Description: "For added security only install organization-approved extensions on VMs." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.4 Ensure that only approved extensions are installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_7_5.yaml b/compliance/controls/azure/azure_cis_v140_7_5.yaml old mode 100755 new mode 100644 index ec937e502..3f88cb4a0 --- a/compliance/controls/azure/azure_cis_v140_7_5.yaml +++ b/compliance/controls/azure/azure_cis_v140_7_5.yaml @@ -1,24 +1,24 @@ +Description: Ensure that the latest OS patches for all virtual machines are applied. ID: azure_cis_v140_7_5 -Title: "7.5 Ensure that the latest OS Patches for all Virtual Machines are applied" -Description: "Ensure that the latest OS patches for all virtual machines are applied." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.5 Ensure that the latest OS Patches for all Virtual Machines are applied \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_7_6.yaml b/compliance/controls/azure/azure_cis_v140_7_6.yaml old mode 100755 new mode 100644 index db3f73862..2512012fc --- a/compliance/controls/azure/azure_cis_v140_7_6.yaml +++ b/compliance/controls/azure/azure_cis_v140_7_6.yaml @@ -1,24 +1,24 @@ +Description: Install endpoint protection for all virtual machines. ID: azure_cis_v140_7_6 -Title: "7.6 Ensure that the endpoint protection for all Virtual Machines is installed" -Description: "Install endpoint protection for all virtual machines." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.6 Ensure that the endpoint protection for all Virtual Machines is installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_7_7.yaml b/compliance/controls/azure/azure_cis_v140_7_7.yaml old mode 100755 new mode 100644 index fda75165c..ead22761d --- a/compliance/controls/azure/azure_cis_v140_7_7.yaml +++ b/compliance/controls/azure/azure_cis_v140_7_7.yaml @@ -1,24 +1,24 @@ +Description: VHD (Virtual Hard Disks) are stored in BLOB storage and are the old style disks that were attached to Virtual Machines, and the BLOB VHD was then leased to the VM. By Default storage accounts are not encrypted, and Azure Defender(Security Centre) would then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK and this should be turned on for storage accounts containing VHD's. ID: azure_cis_v140_7_7 -Title: "7.7 Ensure that VHD's are encrypted" -Description: "VHD (Virtual Hard Disks) are stored in BLOB storage and are the old style disks that were attached to Virtual Machines, and the BLOB VHD was then leased to the VM. By Default storage accounts are not encrypted, and Azure Defender(Security Centre) would then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK and this should be turned on for storage accounts containing VHD's." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.7 Ensure that VHD's are encrypted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_8_1.yaml b/compliance/controls/azure/azure_cis_v140_8_1.yaml old mode 100755 new mode 100644 index 0851d7b46..cb9e3f0be --- a/compliance/controls/azure/azure_cis_v140_8_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_8_1.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set. ID: azure_cis_v140_8_1 -Title: "8.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults" -Description: "Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_key + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + WITH rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where enable_rbac_authorization + WHERE + enable_rbac_authorization ) - select - kvk.id as resource, - kvk.og_account_id as og_account_id, - kvk.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvk.name || - case - when v.name is null then ' not RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' not RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_key kvk - left join rbac_vault as v on v.name = kvk.vault_name, + LEFT JOIN rbac_vault AS v ON v.name = kvk.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvk.subscription_id; - PrimaryTable: azure_key_vault_key - ListOfTables: - - azure_key_vault - - azure_key_vault_key - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_8_2.yaml b/compliance/controls/azure/azure_cis_v140_8_2.yaml old mode 100755 new mode 100644 index cabc3d102..5bf9ecb4c --- a/compliance/controls/azure/azure_cis_v140_8_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_8_2.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set. ID: azure_cis_v140_8_2 -Title: "8.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults" -Description: "Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with non_rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_key + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + WITH non_rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where not enable_rbac_authorization + WHERE + NOT enable_rbac_authorization ) - select - kvk.id as resource, - kvk.og_account_id as og_account_id, - kvk.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvk.name || - case - when v.name is null then ' RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_key kvk - left join non_rbac_vault as v on v.name = kvk.vault_name, + LEFT JOIN non_rbac_vault AS v ON v.name = kvk.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvk.subscription_id; - PrimaryTable: azure_key_vault_key - ListOfTables: - - azure_key_vault - - azure_key_vault_key - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_8_3.yaml b/compliance/controls/azure/azure_cis_v140_8_3.yaml old mode 100755 new mode 100644 index 00fae1da0..5dd0dd28a --- a/compliance/controls/azure/azure_cis_v140_8_3.yaml +++ b/compliance/controls/azure/azure_cis_v140_8_3.yaml @@ -1,45 +1,47 @@ +Description: Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set ID: azure_cis_v140_8_3 -Title: "8.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults" -Description: "Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_secret + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + WITH rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where enable_rbac_authorization + WHERE + enable_rbac_authorization ) - select - kvs.id as resource, - kvs.og_account_id as og_account_id, - kvs.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvs.name || - case - when v.name is null then ' not RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' not RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_secret kvs - left join rbac_vault as v on v.name = kvs.vault_name, + LEFT JOIN rbac_vault AS v ON v.name = kvs.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvs.subscription_id; - PrimaryTable: azure_key_vault_secret - ListOfTables: - - azure_key_vault - - azure_key_vault_secret - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_8_4.yaml b/compliance/controls/azure/azure_cis_v140_8_4.yaml old mode 100755 new mode 100644 index c231c8bb2..7bd6f3ba4 --- a/compliance/controls/azure/azure_cis_v140_8_4.yaml +++ b/compliance/controls/azure/azure_cis_v140_8_4.yaml @@ -1,16 +1,47 @@ +Description: Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set. ID: azure_cis_v140_8_4 -Title: "8.4 Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults" -Description: "Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with non_rbac_vault as (\n select\n name\n from\n azure_key_vault\n where not enable_rbac_authorization\n)\nselect\n kvs.id as resource,\n kvs.og_account_id as og_account_id,\n kvs.og_resource_id as og_resource_id,\n case\n when v.name is null then 'skip'\n when enabled and expires_at is null then 'alarm'\n else 'ok'\n end as status,\n vault_name || ' key ' || kvs.name ||\n case\n when v.name is null then ' RBAC enabled vault.'\n when enabled and expires_at is null then ' expiration date not set.'\n when not enabled then ' disabled.'\n else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.'\n end as reason\n \n \n \nfrom\n azure_key_vault_secret kvs\n left join non_rbac_vault as v on v.name = kvs.vault_name,\n azure_subscription sub\nwhere\n sub.subscription_id = kvs.subscription_id;\n" - PrimaryTable: azure_key_vault_secret ListOfTables: - azure_key_vault - azure_key_vault_secret - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + WITH non_rbac_vault AS ( + SELECT + name + FROM + azure_key_vault + WHERE + NOT enable_rbac_authorization + ) + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + vault_name || ' key ' || kvs.name || + CASE + WHEN v.name IS NULL THEN ' RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM + azure_key_vault_secret kvs + LEFT JOIN non_rbac_vault AS v + ON v.name = kvs.vault_name, + azure_subscription sub + WHERE + sub.subscription_id = kvs.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.4 Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_8_5.yaml b/compliance/controls/azure/azure_cis_v140_8_5.yaml old mode 100755 new mode 100644 index 03fb76b7c..333adeb93 --- a/compliance/controls/azure/azure_cis_v140_8_5.yaml +++ b/compliance/controls/azure/azure_cis_v140_8_5.yaml @@ -1,24 +1,24 @@ +Description: Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion. ID: azure_cis_v140_8_5 -Title: "8.5 Ensure that Resource Locks are set for mission critical Azure resources" -Description: "Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 8.5 Ensure that Resource Locks are set for mission critical Azure resources \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_8_6.yaml b/compliance/controls/azure/azure_cis_v140_8_6.yaml old mode 100755 new mode 100644 index c694574b2..a28e25b6f --- a/compliance/controls/azure/azure_cis_v140_8_6.yaml +++ b/compliance/controls/azure/azure_cis_v140_8_6.yaml @@ -1,34 +1,34 @@ +Description: The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the "Do Not Purge" and "Soft Delete" functions. ID: azure_cis_v140_8_6 -Title: "8.6 Ensure the key vault is recoverable" -Description: "The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the \\\"Do Not Purge\\\" and \\\"Soft Delete\\\" functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when soft_delete_enabled and purge_protection_enabled then 'ok' - else 'alarm' - end as status, - case - when not soft_delete_enabled and not purge_protection_enabled then name || ' "soft delete" and "do not purge" not enabled.' - when not soft_delete_enabled then name || ' "soft delete" not enabled.' - when not purge_protection_enabled then name || ' "do not purge" not enabled.' - else name || ' "soft delete" and "do not purge" enabled.' - end as reason - from - azure_key_vault kv, - azure_subscription sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN soft_delete_enabled AND purge_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT soft_delete_enabled AND NOT purge_protection_enabled THEN name || ' "soft delete" and "do not purge" not enabled.' + WHEN NOT soft_delete_enabled THEN name || ' "soft delete" not enabled.' + WHEN NOT purge_protection_enabled THEN name || ' "do not purge" not enabled.' + ELSE name || ' "soft delete" and "do not purge" enabled.' + END AS reason + FROM + azure_key_vault kv, + azure_subscription sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.6 Ensure the key vault is recoverable \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_8_7.yaml b/compliance/controls/azure/azure_cis_v140_8_7.yaml old mode 100755 new mode 100644 index ef230cf8c..c35807ca9 --- a/compliance/controls/azure/azure_cis_v140_8_7.yaml +++ b/compliance/controls/azure/azure_cis_v140_8_7.yaml @@ -1,34 +1,34 @@ +Description: Ensure that RBAC is enabled on all Azure Kubernetes Services Instances. ID: azure_cis_v140_8_7 -Title: "8.7 Enable role-based access control (RBAC) within Azure Kubernetes Services" -Description: "Ensure that RBAC is enabled on all Azure Kubernetes Services Instances." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when soft_delete_enabled and purge_protection_enabled then 'ok' - else 'alarm' - end as status, - case - when not soft_delete_enabled and not purge_protection_enabled then name || ' "soft delete" and "do not purge" not enabled.' - when not soft_delete_enabled then name || ' "soft delete" not enabled.' - when not purge_protection_enabled then name || ' "do not purge" not enabled.' - else name || ' "soft delete" and "do not purge" enabled.' - end as reason - from - azure_key_vault kv, - azure_subscription sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN soft_delete_enabled AND purge_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT soft_delete_enabled AND NOT purge_protection_enabled THEN name || ' "soft delete" and "do not purge" not enabled.' + WHEN NOT soft_delete_enabled THEN name || ' "soft delete" not enabled.' + WHEN NOT purge_protection_enabled THEN name || ' "do not purge" not enabled.' + ELSE name || ' "soft delete" and "do not purge" enabled.' + END AS reason + FROM + azure_key_vault kv, + azure_subscription sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.7 Enable role-based access control (RBAC) within Azure Kubernetes Services \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_9_1.yaml b/compliance/controls/azure/azure_cis_v140_9_1.yaml old mode 100755 new mode 100644 index 8cb24e8c0..696977b84 --- a/compliance/controls/azure/azure_cis_v140_9_1.yaml +++ b/compliance/controls/azure/azure_cis_v140_9_1.yaml @@ -1,32 +1,32 @@ +Description: Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching the API app, or authenticate those that have tokens before they reach the API app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented. ID: azure_cis_v140_9_1 -Title: "9.1 Ensure App Service Authentication is set up for apps in Azure App Service" -Description: "Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching the API app, or authenticate those that have tokens before they reach the API app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then name || ' authentication not set.' - else name || ' authentication set.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::boolean THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::boolean THEN name || ' authentication not set.' + ELSE name || ' authentication set.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.1 Ensure App Service Authentication is set up for apps in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_9_11.yaml b/compliance/controls/azure/azure_cis_v140_9_11.yaml old mode 100755 new mode 100644 index d528d7b69..9585db19d --- a/compliance/controls/azure/azure_cis_v140_9_11.yaml +++ b/compliance/controls/azure/azure_cis_v140_9_11.yaml @@ -1,24 +1,24 @@ +Description: Encryption keys, Certificate thumbprints and Managed Identity Credentials can be coded into the APP service, this renders them visible as part of the configuration, to maintain security of these keys it is better to store in an Azure Keyvault and reference them from the Keyvault. ID: azure_cis_v140_9_11 -Title: "9.11 Ensure Azure Keyvaults are used to store secrets" -Description: "Encryption keys, Certificate thumbprints and Managed Identity Credentials can be coded into the APP service, this renders them visible as part of the configuration, to maintain security of these keys it is better to store in an Azure Keyvault and reference them from the Keyvault." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.11 Ensure Azure Keyvaults are used to store secrets \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_9_2.yaml b/compliance/controls/azure/azure_cis_v140_9_2.yaml old mode 100755 new mode 100644 index 503d8f3d1..5c0c6bed6 --- a/compliance/controls/azure/azure_cis_v140_9_2.yaml +++ b/compliance/controls/azure/azure_cis_v140_9_2.yaml @@ -1,32 +1,32 @@ +Description: Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic. ID: azure_cis_v140_9_2 -Title: "9.2 Ensure web app redirects all HTTP traffic to HTTPS in Azure App Service" -Description: "Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not https_only then 'alarm' - else 'ok' - end as status, - case - when not https_only then name || ' does not redirect all HTTP traffic to HTTPS.' - else name || ' redirects all HTTP traffic to HTTPS.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT https_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT https_only THEN name || ' does not redirect all HTTP traffic to HTTPS.' + ELSE name || ' redirects all HTTP traffic to HTTPS.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.2 Ensure web app redirects all HTTP traffic to HTTPS in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_9_3.yaml b/compliance/controls/azure/azure_cis_v140_9_3.yaml old mode 100755 new mode 100644 index 322358a74..cb7b7e9f2 --- a/compliance/controls/azure/azure_cis_v140_9_3.yaml +++ b/compliance/controls/azure/azure_cis_v140_9_3.yaml @@ -1,32 +1,32 @@ +Description: The TLS(Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards, such as PCI DSS. ID: azure_cis_v140_9_3 -Title: "9.3 Ensure web app is using the latest version of TLS encryption" -Description: "The TLS(Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards, such as PCI DSS." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then 'alarm' - else 'ok' - end as status, - case - when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then name || ' not using the latest version of TLS encryption.' - else name || ' using the latest version of TLS encryption.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN name || ' not using the latest version of TLS encryption.' + ELSE name || ' using the latest version of TLS encryption.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.3 Ensure web app is using the latest version of TLS encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_9_4.yaml b/compliance/controls/azure/azure_cis_v140_9_4.yaml old mode 100755 new mode 100644 index 32be050b4..c883bb585 --- a/compliance/controls/azure/azure_cis_v140_9_4.yaml +++ b/compliance/controls/azure/azure_cis_v140_9_4.yaml @@ -1,32 +1,32 @@ +Description: Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app. ID: azure_cis_v140_9_4 -Title: "9.4 Ensure the web app has 'Client Certificates (Incoming client certificates)' set to 'On'" -Description: "Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not client_cert_enabled then 'alarm' - else 'ok' - end as status, - case - when not client_cert_enabled then name || ' incoming client certificates set to off.' - else name || ' incoming client certificates set to on.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT client_cert_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT client_cert_enabled THEN name || ' incoming client certificates set to off.' + ELSE name || ' incoming client certificates set to on.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.4 Ensure the web app has 'Client Certificates (Incoming client certificates)' set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_9_5.yaml b/compliance/controls/azure/azure_cis_v140_9_5.yaml old mode 100755 new mode 100644 index be43079f2..147c68faa --- a/compliance/controls/azure/azure_cis_v140_9_5.yaml +++ b/compliance/controls/azure/azure_cis_v140_9_5.yaml @@ -1,32 +1,32 @@ +Description: Managed service identity in App Service makes the app more secure by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in the app service, the app will connect to other Azure services securely without the need of username and passwords. ID: azure_cis_v140_9_5 -Title: "9.5 Ensure that Register with Azure Active Directory is enabled on App Service" -Description: "Managed service identity in App Service makes the app more secure by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in the app service, the app will connect to other Azure services securely without the need of username and passwords." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when identity = '{}' then 'alarm' - else 'ok' - end as status, - case - when identity = '{}' then name || ' register with azure active directory disabled.' - else name || ' register with azure active directory enabled.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN identity = '{}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity = '{}' THEN name || ' register with azure active directory disabled.' + ELSE name || ' register with azure active directory enabled.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.5 Ensure that Register with Azure Active Directory is enabled on App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_9_6.yaml b/compliance/controls/azure/azure_cis_v140_9_6.yaml old mode 100755 new mode 100644 index fe99e022f..5a1e40c96 --- a/compliance/controls/azure/azure_cis_v140_9_6.yaml +++ b/compliance/controls/azure/azure_cis_v140_9_6.yaml @@ -1,24 +1,24 @@ +Description: Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version. ID: azure_cis_v140_9_6 -Title: "9.6 Ensure that 'PHP version' is the latest, if used to run the web app" -Description: "Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.6 Ensure that 'PHP version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_9_7.yaml b/compliance/controls/azure/azure_cis_v140_9_7.yaml old mode 100755 new mode 100644 index a32635b27..e563f1470 --- a/compliance/controls/azure/azure_cis_v140_9_7.yaml +++ b/compliance/controls/azure/azure_cis_v140_9_7.yaml @@ -1,24 +1,24 @@ +Description: Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version. ID: azure_cis_v140_9_7 -Title: "9.7 Ensure that 'Python version' is the latest, if used to run the web app" -Description: "Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.7 Ensure that 'Python version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_9_8.yaml b/compliance/controls/azure/azure_cis_v140_9_8.yaml old mode 100755 new mode 100644 index 809896ac8..794adce53 --- a/compliance/controls/azure/azure_cis_v140_9_8.yaml +++ b/compliance/controls/azure/azure_cis_v140_9_8.yaml @@ -1,24 +1,28 @@ +Description: >- + Periodically, newer versions are released for Java software either due to security + flaws or to include additional functionality. Using the latest Java version for web + apps is recommended in order to take advantage of security fixes, if any, and/or new + functionalities of the newer version. ID: azure_cis_v140_9_8 -Title: "9.8 Ensure that 'Java version' is the latest, if used to run the web app" -Description: "Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.8 Ensure that 'Java version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v140_9_9.yaml b/compliance/controls/azure/azure_cis_v140_9_9.yaml old mode 100755 new mode 100644 index 69499450b..161f8b629 --- a/compliance/controls/azure/azure_cis_v140_9_9.yaml +++ b/compliance/controls/azure/azure_cis_v140_9_9.yaml @@ -1,32 +1,32 @@ +Description: Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version. ID: azure_cis_v140_9_9 -Title: "9.9 Ensure that 'HTTP Version' is the latest, if used to run the web app" -Description: "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then name || ' HTTP version not latest.' - else name || ' HTTP version is latest.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::boolean THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::boolean THEN name || ' HTTP version not latest.' + ELSE name || ' HTTP version is latest.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.9 Ensure that 'HTTP Version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_10_1.yaml b/compliance/controls/azure/azure_cis_v150_10_1.yaml old mode 100755 new mode 100644 index b94233f4d..0ce29473a --- a/compliance/controls/azure/azure_cis_v150_10_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_10_1.yaml @@ -1,24 +1,24 @@ +Description: Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion. ID: azure_cis_v150_10_1 -Title: "10.1 Ensure that Resource Locks are set for Mission-Critical Azure Resources" -Description: "Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. These locks are very useful when there is an important resource in a subscription that users should not be able to delete or change. Locks can help prevent accidental and malicious changes or deletion." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 10.1 Ensure that Resource Locks are set for Mission-Critical Azure Resources \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_10.yaml b/compliance/controls/azure/azure_cis_v150_1_10.yaml old mode 100755 new mode 100644 index 9cb87eef9..0afb981b4 --- a/compliance/controls/azure/azure_cis_v150_1_10.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_10.yaml @@ -1,19 +1,19 @@ +Description: Ensure that all administrators are notified if any other administrator resets their password. ID: azure_cis_v150_1_10 -Title: "1.10 Ensure That 'Notify all admins when other admins reset their password?' is set to 'Yes'" -Description: "Ensure that all administrators are notified if any other administrator resets their password." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.10 Ensure That 'Notify all admins when other admins reset their password?' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_11.yaml b/compliance/controls/azure/azure_cis_v150_1_11.yaml old mode 100755 new mode 100644 index fd70f278d..ff337360a --- a/compliance/controls/azure/azure_cis_v150_1_11.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_11.yaml @@ -1,19 +1,19 @@ +Description: Allow users to provide consent for selected permissions when a request is coming from a verified publisher. ID: azure_cis_v150_1_11 -Title: "1.11 Ensure That ‘Users Can Consent to Apps Accessing Company Data on Their Behalf’ Is Set To ‘Allow for Verified Publishers’" -Description: "Allow users to provide consent for selected permissions when a request is coming from a verified publisher." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.11 Ensure That ‘Users Can Consent to Apps Accessing Company Data on Their Behalf’ Is Set To ‘Allow for Verified Publishers’ \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_12.yaml b/compliance/controls/azure/azure_cis_v150_1_12.yaml old mode 100755 new mode 100644 index 64dced9ca..1b88e39dd --- a/compliance/controls/azure/azure_cis_v150_1_12.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_12.yaml @@ -1,19 +1,19 @@ +Description: Require administrators to provide consent for the apps before use. ID: azure_cis_v150_1_12 -Title: "1.12 Ensure that 'Users can consent to apps accessing company data on their behalf' is set to 'No'" -Description: "Require administrators to provide consent for the apps before use." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.12 Ensure that 'Users can consent to apps accessing company data on their behalf' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_14.yaml b/compliance/controls/azure/azure_cis_v150_1_14.yaml old mode 100755 new mode 100644 index 5fbc35fa7..58d85534c --- a/compliance/controls/azure/azure_cis_v150_1_14.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_14.yaml @@ -1,15 +1,39 @@ +Description: Require administrators or appropriately delegated users to register third-party applications. ID: azure_cis_v150_1_14 -Title: "1.14 Ensure That ‘Users Can Register Applications’ Is Set to ‘No’" -Description: "Require administrators or appropriately delegated users to register third-party applications." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with distinct_tenant as (\n select\n distinct tenant_id,\n subscription_id,\n _ctx\n from\n azure_tenant\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' then a.display_name || ' does not allow user to register applications.'\n else a.display_name || ' allows user to register applications.'\n end as reason,\n t.tenant_id\n \nfrom\n distinct_tenant as t,\n azuread_authorization_policy as a;" - PrimaryTable: azuread_authorization_policy ListOfTables: - azure_tenant - azuread_authorization_policy Parameters: [] + PrimaryTable: azuread_authorization_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, + subscription_id, + _ctx + FROM + azure_tenant + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' THEN a.display_name || ' does not allow user to register applications.' + ELSE a.display_name || ' allows user to register applications.' + END AS reason, + t.tenant_id + FROM + distinct_tenant AS t, + azuread_authorization_policy AS a; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.14 Ensure That ‘Users Can Register Applications’ Is Set to ‘No’ \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_15.yaml b/compliance/controls/azure/azure_cis_v150_1_15.yaml old mode 100755 new mode 100644 index 468010868..39cdaf1f0 --- a/compliance/controls/azure/azure_cis_v150_1_15.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_15.yaml @@ -1,19 +1,19 @@ +Description: Limit guest user permissions. ID: azure_cis_v150_1_15 -Title: "1.15 Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects'" -Description: "Limit guest user permissions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.15 Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_16.yaml b/compliance/controls/azure/azure_cis_v150_1_16.yaml old mode 100755 new mode 100644 index 17b2182a5..5d7a725f5 --- a/compliance/controls/azure/azure_cis_v150_1_16.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_16.yaml @@ -1,19 +1,19 @@ +Description: Restrict invitations to users with specific administrative roles only. ID: azure_cis_v150_1_16 -Title: "1.16 Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users'" -Description: "Restrict invitations to users with specific administrative roles only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.16 Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_17.yaml b/compliance/controls/azure/azure_cis_v150_1_17.yaml old mode 100755 new mode 100644 index 03d24110f..07ed6a66e --- a/compliance/controls/azure/azure_cis_v150_1_17.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_17.yaml @@ -1,19 +1,19 @@ +Description: Restrict access to the Azure AD administration portal to administrators only. ID: azure_cis_v150_1_17 -Title: "1.17 Ensure That 'Restrict access to Azure AD administration portal' is Set to 'Yes'" -Description: "Restrict access to the Azure AD administration portal to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.17 Ensure That 'Restrict access to Azure AD administration portal' is Set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_19.yaml b/compliance/controls/azure/azure_cis_v150_1_19.yaml old mode 100755 new mode 100644 index abc413d01..899ec4279 --- a/compliance/controls/azure/azure_cis_v150_1_19.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_19.yaml @@ -1,39 +1,39 @@ +Description: Restrict security group creation to administrators only. ID: azure_cis_v150_1_19 -Title: "1.19 Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No'" -Description: "Restrict security group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_authorization_policy + Parameters: [] + PrimaryTable: azuread_authorization_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' then 'ok' - else 'alarm' - end as status, - case - when a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' then a.display_name || ' does not allow user to create security groups.' - else a.display_name || ' allows user to create security groups.' - end as reason, + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' THEN a.display_name || ' does not allow user to create security groups.' + ELSE a.display_name || ' allows user to create security groups.' + END AS reason, t.tenant_id - from - distinct_tenant as t, - azuread_authorization_policy as a; - PrimaryTable: azuread_authorization_policy - ListOfTables: - - azure_tenant - - azuread_authorization_policy - Parameters: [] + FROM + distinct_tenant AS t, + azuread_authorization_policy AS a; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.19 Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_1_1.yaml b/compliance/controls/azure/azure_cis_v150_1_1_1.yaml old mode 100755 new mode 100644 index bfe33fc04..f56c3f05f --- a/compliance/controls/azure/azure_cis_v150_1_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_1_1.yaml @@ -1,19 +1,19 @@ +Description: Security defaults in Azure Active Directory (Azure AD) make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks. Microsoft is making security defaults available to everyone. The goal is to ensure that all organizations have a basic level of security enabled at no extra cost. You may turn on security defaults in the Azure portal. ID: azure_cis_v150_1_1_1 -Title: "1.1.1 Ensure Security Defaults is enabled on Azure Active Directory" -Description: "Security defaults in Azure Active Directory (Azure AD) make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks. Microsoft is making security defaults available to everyone. The goal is to ensure that all organizations have a basic level of security enabled at no extra cost. You may turn on security defaults in the Azure portal." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.1 Ensure Security Defaults is enabled on Azure Active Directory \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_1_2.yaml b/compliance/controls/azure/azure_cis_v150_1_1_2.yaml old mode 100755 new mode 100644 index 0899362d5..c3551b01a --- a/compliance/controls/azure/azure_cis_v150_1_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_1_2.yaml @@ -1,19 +1,19 @@ +Description: Enable multi-factor authentication for all roles, groups, and users that have write access or permissions to Azure resources. ID: azure_cis_v150_1_1_2 -Title: "1.1.2 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Privileged Users" -Description: "Enable multi-factor authentication for all roles, groups, and users that have write access or permissions to Azure resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.2 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Privileged Users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_1_3.yaml b/compliance/controls/azure/azure_cis_v150_1_1_3.yaml old mode 100755 new mode 100644 index 95b32a5f7..ed7c5eceb --- a/compliance/controls/azure/azure_cis_v150_1_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_1_3.yaml @@ -1,19 +1,19 @@ +Description: Enable multi-factor authentication for all non-privileged users. ID: azure_cis_v150_1_1_3 -Title: "1.1.3 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Non-Privileged Users" -Description: "Enable multi-factor authentication for all non-privileged users." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.3 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Non-Privileged Users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_1_4.yaml b/compliance/controls/azure/azure_cis_v150_1_1_4.yaml old mode 100755 new mode 100644 index dca298924..ad9156f83 --- a/compliance/controls/azure/azure_cis_v150_1_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_1_4.yaml @@ -1,19 +1,19 @@ +Description: Do not allow users to remember multi-factor authentication on devices. ID: azure_cis_v150_1_1_4 -Title: "1.1.4 Ensure that 'Restore multi-factor authentication on all remembered devices' is Enabled" -Description: "Do not allow users to remember multi-factor authentication on devices." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.4 Ensure that 'Restore multi-factor authentication on all remembered devices' is Enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_20.yaml b/compliance/controls/azure/azure_cis_v150_1_20.yaml old mode 100755 new mode 100644 index 553de34ff..7031f457d --- a/compliance/controls/azure/azure_cis_v150_1_20.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_20.yaml @@ -1,19 +1,19 @@ +Description: Restrict security group management to administrators only. ID: azure_cis_v150_1_20 -Title: "1.20 Ensure that 'Owners can manage group membership requests in the Access Panel' is set to 'No'" -Description: "Restrict security group management to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.20 Ensure that 'Owners can manage group membership requests in the Access Panel' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_21.yaml b/compliance/controls/azure/azure_cis_v150_1_21.yaml old mode 100755 new mode 100644 index 49b08486d..05b17224a --- a/compliance/controls/azure/azure_cis_v150_1_21.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_21.yaml @@ -1,19 +1,19 @@ +Description: Restrict Microsoft 365 group creation to administrators only. ID: azure_cis_v150_1_21 -Title: "1.21 Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No'" -Description: "Restrict Microsoft 365 group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.21 Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_22.yaml b/compliance/controls/azure/azure_cis_v150_1_22.yaml old mode 100755 new mode 100644 index 042800742..239bed273 --- a/compliance/controls/azure/azure_cis_v150_1_22.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_22.yaml @@ -1,19 +1,19 @@ +Description: Joining or registering devices to the active directory should require Multi-factor authentication. ID: azure_cis_v150_1_22 -Title: "1.22 Ensure that 'Require Multi-Factor Authentication to register or join devices with Azure AD' is set to 'Yes'" -Description: "Joining or registering devices to the active directory should require Multi-factor authentication." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.22 Ensure that 'Require Multi-Factor Authentication to register or join devices with Azure AD' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_23.yaml b/compliance/controls/azure/azure_cis_v150_1_23.yaml old mode 100755 new mode 100644 index e06621e6a..b7020863e --- a/compliance/controls/azure/azure_cis_v150_1_23.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_23.yaml @@ -1,53 +1,53 @@ +Description: Subscription ownership should not include permission to create custom owner roles. The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access. ID: azure_cis_v150_1_23 -Title: "1.23 Ensure That No Custom Subscription Owner Roles Are Created" -Description: "Subscription ownership should not include permission to create custom owner roles. The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with owner_custom_roles as ( - select + ListOfTables: + - azure_role_definition + - azure_subscription + Parameters: [] + PrimaryTable: azure_role_definition + QueryToExecute: | + WITH owner_custom_roles AS ( + SELECT role_name, role_type, title, action, _ctx, subscription_id - from + FROM azure_role_definition, - jsonb_array_elements(permissions) as s, - jsonb_array_elements_text(s -> 'actions') as action - where + jsonb_array_elements(permissions) AS s, + jsonb_array_elements_text(s -> 'actions') AS action + WHERE role_type = 'CustomRole' - and action in ('*', '*:*') + AND action IN ('*', '*:*') ) - select - cr.subscription_id as resource, - cr.og_account_id as og_account_id, - cr.og_resource_id as og_resource_id, - case - when count(*) > 0 then 'alarm' - else 'ok' - end as status, - case - when count(*) = 1 then 'There is one custom owner role.' - when count(*) > 1 then 'There are ' || count(*) || ' custom owner roles.' - else 'There are no custom owner roles.' - end as reason - from + SELECT + cr.subscription_id AS resource, + cr.og_account_id AS og_account_id, + cr.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(*) > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(*) = 1 THEN 'There is one custom owner role.' + WHEN COUNT(*) > 1 THEN 'There are ' || COUNT(*) || ' custom owner roles.' + ELSE 'There are no custom owner roles.' + END AS reason + FROM owner_custom_roles cr, azure_subscription sub - where + WHERE sub.subscription_id = cr.subscription_id - group by + GROUP BY cr.subscription_id, cr._ctx, sub.display_name; - PrimaryTable: azure_role_definition - ListOfTables: - - azure_role_definition - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.23 Ensure That No Custom Subscription Owner Roles Are Created \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_24.yaml b/compliance/controls/azure/azure_cis_v150_1_24.yaml old mode 100755 new mode 100644 index 15bbd7fe2..cf01e61dc --- a/compliance/controls/azure/azure_cis_v150_1_24.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_24.yaml @@ -1,19 +1,19 @@ +Description: Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration. ID: azure_cis_v150_1_24 -Title: "1.24 Ensure a Custom Role is Assigned Permissions for Administering Resource Locks" -Description: "Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.24 Ensure a Custom Role is Assigned Permissions for Administering Resource Locks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_25.yaml b/compliance/controls/azure/azure_cis_v150_1_25.yaml old mode 100755 new mode 100644 index 25aca9953..97fcb086e --- a/compliance/controls/azure/azure_cis_v150_1_25.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_25.yaml @@ -1,19 +1,19 @@ +Description: Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Azure Active Directories. ID: azure_cis_v150_1_25 -Title: "1.25 Ensure That ‘Subscription Entering AAD Directory’ and ‘Subscription Leaving AAD Directory’ Is Set To ‘Permit No One’" -Description: "Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Azure Active Directories." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.25 Ensure That ‘Subscription Entering AAD Directory’ and ‘Subscription Leaving AAD Directory’ Is Set To ‘Permit No One’ \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_2_1.yaml b/compliance/controls/azure/azure_cis_v150_1_2_1.yaml old mode 100755 new mode 100644 index aff4727b1..4de4708e1 --- a/compliance/controls/azure/azure_cis_v150_1_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_2_1.yaml @@ -1,19 +1,19 @@ +Description: Azure Active Directory Conditional Access allows an organization to configure Named locations and configure whether those locations are trusted or untrusted. These settings provide organizations the means to specify Geographical locations for use in conditional access policies, or define actual IP addresses and IP ranges and whether or not those IP addresses and/or ranges are trusted by the organization. ID: azure_cis_v150_1_2_1 -Title: "1.2.1 Ensure Trusted Locations Are Defined" -Description: "Azure Active Directory Conditional Access allows an organization to configure Named locations and configure whether those locations are trusted or untrusted. These settings provide organizations the means to specify Geographical locations for use in conditional access policies, or define actual IP addresses and IP ranges and whether or not those IP addresses and/or ranges are trusted by the organization." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.1 Ensure Trusted Locations Are Defined \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_2_2.yaml b/compliance/controls/azure/azure_cis_v150_1_2_2.yaml old mode 100755 new mode 100644 index 394b10a7b..e4d40c9be --- a/compliance/controls/azure/azure_cis_v150_1_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_2_2.yaml @@ -1,19 +1,19 @@ +Description: Conditional Access Policies can be used to block access from geographic locations that are deemed out-of-scope for your organization or application. The scope and variables for this policy should be carefully examined and defined. ID: azure_cis_v150_1_2_2 -Title: "1.2.2 Ensure that an exclusionary Geographic Access Policy is considered" -Description: "Conditional Access Policies can be used to block access from geographic locations that are deemed out-of-scope for your organization or application. The scope and variables for this policy should be carefully examined and defined." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.2 Ensure that an exclusionary Geographic Access Policy is considered \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_2_3.yaml b/compliance/controls/azure/azure_cis_v150_1_2_3.yaml old mode 100755 new mode 100644 index 791b90db1..dcc113fb9 --- a/compliance/controls/azure/azure_cis_v150_1_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_2_3.yaml @@ -1,19 +1,19 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login. ID: azure_cis_v150_1_2_3 -Title: "1.2.3 Ensure that A Multi-factor Authentication Policy Exists for Administrative Groups" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.3 Ensure that A Multi-factor Authentication Policy Exists for Administrative Groups \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_2_4.yaml b/compliance/controls/azure/azure_cis_v150_1_2_4.yaml old mode 100755 new mode 100644 index 906ad668a..343028d03 --- a/compliance/controls/azure/azure_cis_v150_1_2_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_2_4.yaml @@ -1,19 +1,19 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins. ID: azure_cis_v150_1_2_4 -Title: "1.2.4 Ensure that A Multi-factor Authentication Policy Exists for All Users" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.4 Ensure that A Multi-factor Authentication Policy Exists for All Users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_2_5.yaml b/compliance/controls/azure/azure_cis_v150_1_2_5.yaml old mode 100755 new mode 100644 index 5f0ff3e9c..34d546a87 --- a/compliance/controls/azure/azure_cis_v150_1_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_2_5.yaml @@ -1,19 +1,19 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login. ID: azure_cis_v150_1_2_5 -Title: "1.2.5 Ensure Multi-factor Authentication is Required for Risky Sign-ins" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.5 Ensure Multi-factor Authentication is Required for Risky Sign-ins \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_2_6.yaml b/compliance/controls/azure/azure_cis_v150_1_2_6.yaml old mode 100755 new mode 100644 index b737ceb0a..6a7579ce3 --- a/compliance/controls/azure/azure_cis_v150_1_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_2_6.yaml @@ -1,15 +1,39 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication(MFA) process on logins. ID: azure_cis_v150_1_2_6 -Title: "1.2.6 Ensure Multi-factor Authentication is Required for Azure Management" -Description: "For designated users, they will be prompted to use their multi-factor authentication(MFA) process on logins." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with distinct_tenant as (\n select\n distinct tenant_id,\n subscription_id,\n _ctx\n from\n azure_tenant\n)\nselect\n p.id as resource,\n p.og_account_id as og_account_id,\n p.og_resource_id as og_resource_id,\n case\n when p.built_in_controls @> '[\"mfa\"]' then 'ok'\n else 'alarm'\n end as status,\n case\n when p.built_in_controls @> '[\"mfa\"]' then p.display_name || ' MFA enabled.'\n else p.display_name || ' MFA disabled.'\n end as reason,\n t.tenant_id\n \nfrom\n distinct_tenant as t,\n azuread_conditional_access_policy as p;" - PrimaryTable: azuread_conditional_access_policy ListOfTables: - azure_tenant - azuread_conditional_access_policy Parameters: [] + PrimaryTable: azuread_conditional_access_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, + subscription_id, + _ctx + FROM + azure_tenant + ) + SELECT + p.id AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.built_in_controls @> '["mfa"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.built_in_controls @> '["mfa"]' THEN p.display_name || ' MFA enabled.' + ELSE p.display_name || ' MFA disabled.' + END AS reason, + t.tenant_id + FROM + distinct_tenant AS t, + azuread_conditional_access_policy AS p; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.2.6 Ensure Multi-factor Authentication is Required for Azure Management \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_3.yaml b/compliance/controls/azure/azure_cis_v150_1_3.yaml old mode 100755 new mode 100644 index 890de33b3..0d7ae5777 --- a/compliance/controls/azure/azure_cis_v150_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_3.yaml @@ -1,19 +1,19 @@ +Description: This recommendation extends guest access review by utilizing the Azure AD Privileged Identity Management feature provided in Azure AD Premium P2. Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user. ID: azure_cis_v150_1_3 -Title: "1.3 Ensure Access Review is Set Up for External Users in Azure AD Privileged Identity Management" -Description: "This recommendation extends guest access review by utilizing the Azure AD Privileged Identity Management feature provided in Azure AD Premium P2. Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources a a guest user." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.3 Ensure Access Review is Set Up for External Users in Azure AD Privileged Identity Management \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_4.yaml b/compliance/controls/azure/azure_cis_v150_1_4.yaml old mode 100755 new mode 100644 index 12dcbbca9..945686e14 --- a/compliance/controls/azure/azure_cis_v150_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_4.yaml @@ -1,15 +1,43 @@ +Description: Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user. Guest users in every subscription should be reviewed on a regular basis to ensure that inactive and unneeded accounts are removed. ID: azure_cis_v150_1_4 -Title: "1.4 Ensure Guest Users Are Reviewed on a Regular Basis" -Description: "Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user. Guest users in every subscription should be review on a regular basis to ensure that inactive and unneeded accounts are removed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with distinct_tenant as (\n select\n distinct tenant_id,\n subscription_id,\n _ctx\n from\n azure_tenant\n)\nselect\n u.display_name as resource,\n u.og_account_id as og_account_id,\n u.og_resource_id as og_resource_id,\n case\n when not account_enabled then 'alarm'\n when u.created_date_time::timestamp <= (current_date - interval '30' day) then 'alarm'\n else 'ok'\n end as status,\n case\n when not account_enabled then 'Guest user ''' || u.display_name || ''' inactive.'\n else 'Guest user ''' || u.display_name || ''' was created ' || extract(day from current_timestamp - u.created_date_time::timestamp) || ' days ago.'\n end as reason,\n t.tenant_id\n \nfrom\n azuread_user as u\n left join distinct_tenant as t on t.tenant_id = u.tenant_id\nwhere\n u.user_type = 'Guest';" - PrimaryTable: azuread_user ListOfTables: - azuread_user - azure_tenant Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, + subscription_id, + _ctx + FROM + azure_tenant + ) + SELECT + u.display_name AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN NOT account_enabled THEN 'alarm' + WHEN u.created_date_time::timestamp <= (current_date - INTERVAL '30' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT account_enabled THEN 'Guest user ''' || u.display_name || ''' inactive.' + ELSE 'Guest user ''' || u.display_name || ''' was created ' || EXTRACT(DAY FROM current_timestamp - u.created_date_time::timestamp) || ' days ago.' + END AS reason, + t.tenant_id + FROM + azuread_user AS u + LEFT JOIN + distinct_tenant AS t ON t.tenant_id = u.tenant_id + WHERE + u.user_type = 'Guest'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.4 Ensure Guest Users Are Reviewed on a Regular Basis \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_5.yaml b/compliance/controls/azure/azure_cis_v150_1_5.yaml old mode 100755 new mode 100644 index 83f40809a..7769d30af --- a/compliance/controls/azure/azure_cis_v150_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_5.yaml @@ -1,19 +1,19 @@ +Description: Do not allow users to remember multi-factor authentication on devices. ID: azure_cis_v150_1_5 -Title: "1.5 Ensure that 'Allow users to remember multi-factor authentication on devices they trust' is 'Disabled'" -Description: "Do not allow users to remember multi-factor authentication on devices." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.5 Ensure that 'Allow users to remember multi-factor authentication on devices they trust' is 'Disabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_6.yaml b/compliance/controls/azure/azure_cis_v150_1_6.yaml old mode 100755 new mode 100644 index 2135d6f0b..bd238aeb2 --- a/compliance/controls/azure/azure_cis_v150_1_6.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_6.yaml @@ -1,19 +1,19 @@ +Description: Ensures that two alternate forms of identification are provided before allowing a password reset. ID: azure_cis_v150_1_6 -Title: "1.6 Ensure That 'Number of methods required to reset' is set to '2'" -Description: "Ensures that two alternate forms of identification are provided before allowing a password reset." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.6 Ensure That 'Number of methods required to reset' is set to '2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_7.yaml b/compliance/controls/azure/azure_cis_v150_1_7.yaml old mode 100755 new mode 100644 index 126d107da..fafc8391c --- a/compliance/controls/azure/azure_cis_v150_1_7.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_7.yaml @@ -1,19 +1,19 @@ +Description: Microsoft Azure creates a default bad password policy that is already applied to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Azure AD Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers. Please see the list in default values on the specifics of this policy. ID: azure_cis_v150_1_7 -Title: "1.7 Ensure that a Custom Bad Password List is set to 'Enforce' for your Organization" -Description: "Microsoft Azure creates a default bad password policy that is already applied to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Azure AD Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers. Please see the list in default values on the specifics of this policy." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.7 Ensure that a Custom Bad Password List is set to 'Enforce' for your Organization \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_8.yaml b/compliance/controls/azure/azure_cis_v150_1_8.yaml old mode 100755 new mode 100644 index ea8babd4e..462ba1ea4 --- a/compliance/controls/azure/azure_cis_v150_1_8.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_8.yaml @@ -1,19 +1,19 @@ +Description: Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0. ID: azure_cis_v150_1_8 -Title: "1.8 Ensure that 'Number of days before users are asked to reconfirm their authentication information' is not set to '0'" -Description: "Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.8 Ensure that 'Number of days before users are asked to reconfirm their authentication information' is not set to '0' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_1_9.yaml b/compliance/controls/azure/azure_cis_v150_1_9.yaml old mode 100755 new mode 100644 index b7b18de84..b5abb3243 --- a/compliance/controls/azure/azure_cis_v150_1_9.yaml +++ b/compliance/controls/azure/azure_cis_v150_1_9.yaml @@ -1,19 +1,19 @@ +Description: Ensure that users are notified on their primary and secondary emails on password resets. ID: azure_cis_v150_1_9 -Title: "1.9 Ensure that 'Notify users on password resets?' is set to 'Yes'" -Description: "Ensure that users are notified on their primary and secondary emails on password resets." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.9 Ensure that 'Notify users on password resets?' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_1.yaml b/compliance/controls/azure/azure_cis_v150_2_1_1.yaml old mode 100755 new mode 100644 index f1490d458..eecbe13b8 --- a/compliance/controls/azure/azure_cis_v150_2_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_1.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v150_2_1_1 -Title: "2.1.1 Ensure That Microsoft Defender for Servers Is Set to 'On'" -Description: "Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Servers.' - else 'Azure Defender off for Servers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'VirtualMachines'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Servers.' + ELSE 'Azure Defender off for Servers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'VirtualMachines'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.1 Ensure That Microsoft Defender for Servers Is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_10.yaml b/compliance/controls/azure/azure_cis_v150_2_1_10.yaml old mode 100755 new mode 100644 index d2b3946a8..86ec2ce0f --- a/compliance/controls/azure/azure_cis_v150_2_1_10.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_10.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v150_2_1_10 -Title: "2.1.10 Ensure That Microsoft Defender for Key Vault Is Set To 'On'" -Description: "Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Key Vaults.' - else 'Azure Defender off for Key Vaults.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'KeyVaults'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Key Vaults.' + ELSE 'Azure Defender off for Key Vaults.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'KeyVaults'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.10 Ensure That Microsoft Defender for Key Vault Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_11.yaml b/compliance/controls/azure/azure_cis_v150_2_1_11.yaml old mode 100755 new mode 100644 index 7f471125d..a832b3a1e --- a/compliance/controls/azure/azure_cis_v150_2_1_11.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_11.yaml @@ -1,32 +1,33 @@ +Description: Microsoft Defender for DNS scans all network traffic exiting from within a subscription. ID: azure_cis_v150_2_1_11 -Title: "2.1.11 Ensure That Microsoft Defender for DNS Is Set To 'On'" -Description: "Microsoft Defender for DNS scans all network traffic exiting from within a subscription." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for DNS.' - else 'Azure Defender off for DNS.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'Dns'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for DNS.' + ELSE 'Azure Defender off for DNS.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'Dns'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.11 Ensure That Microsoft Defender for DNS Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_12.yaml b/compliance/controls/azure/azure_cis_v150_2_1_12.yaml old mode 100755 new mode 100644 index 22f1adc2a..cab34c400 --- a/compliance/controls/azure/azure_cis_v150_2_1_12.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_12.yaml @@ -1,24 +1,24 @@ +Description: Microsoft Defender for IoT acts as a central security hub for IoT devices within your organization. ID: azure_cis_v150_2_1_12 -Title: "2.1.12 Ensure That Microsoft Defender for IoT Is Set To 'On'" -Description: "Microsoft Defender for IoT acts as a central security hub for IoT devices within your organization." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.1.12 Ensure That Microsoft Defender for IoT Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_13.yaml b/compliance/controls/azure/azure_cis_v150_2_1_13.yaml old mode 100755 new mode 100644 index 039a21d62..4cf147958 --- a/compliance/controls/azure/azure_cis_v150_2_1_13.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_13.yaml @@ -1,32 +1,33 @@ +Description: Microsoft Defender for Resource Manager scans incoming administrative requests to change your infrastructure from both CLI and the Azure portal. ID: azure_cis_v150_2_1_13 -Title: "2.1.13 Ensure That Microsoft Defender for Resource Manager Is Set To 'On'" -Description: "Microsoft Defender for Resource Manager scans incoming administrative requests to change your infrastructure from both CLI and the Azure portal." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Resource Manager.' - else 'Azure Defender off for Resource Manager.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'Arm'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Resource Manager.' + ELSE 'Azure Defender off for Resource Manager.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'Arm'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.13 Ensure That Microsoft Defender for Resource Manager Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_2.yaml b/compliance/controls/azure/azure_cis_v150_2_1_2.yaml old mode 100755 new mode 100644 index 6b2086429..e9aed3435 --- a/compliance/controls/azure/azure_cis_v150_2_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_2.yaml @@ -1,32 +1,35 @@ +Description: Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v150_2_1_2 -Title: "2.1.2 Ensure That Microsoft Defender for App Services Is Set To 'On'" -Description: "Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for App Services.' - else 'Azure Defender off for App Services.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'AppServices'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for App Services.' + ELSE 'Azure Defender off for App Services.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'AppServices'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.2 Ensure That Microsoft Defender for App Services Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_3.yaml b/compliance/controls/azure/azure_cis_v150_2_1_3.yaml old mode 100755 new mode 100644 index 79c9c629e..70655f626 --- a/compliance/controls/azure/azure_cis_v150_2_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_3.yaml @@ -1,51 +1,51 @@ +Description: Turning on Microsoft Defender for Databases enables threat detection for the instances running your database software. This provides threat intelligence, anomaly detection, and behavior analytics in the Azure Microsoft Defender for Cloud. Instead of being enabled on services like Platform as a Service (PaaS), this implementation will run within your instances as Infrastructure as a Service (IaaS) on the Operating Systems hosting your databases. ID: azure_cis_v150_2_1_3 -Title: "2.1.3 Ensure That Microsoft Defender for Databases Is Set To 'On'" -Description: "Turning on Microsoft Defender for Databases enables threat detection for the instances running your database software. This provides threat intelligence, anomaly detection, and behavior analytics in the Azure Microsoft Defender for Cloud. Instead of being enabled on services like Platform as a Service (PaaS), this implementation will run within your instances as Infrastructure as a Service (IaaS) on the Operating Systems hosting your databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with defender_list as ( - select - json_object_agg(name, pricing_tier) as data, + ListOfTables: + - azure_security_center_subscription_pricing + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH defender_list AS ( + SELECT + json_object_agg(name, pricing_tier) AS data, subscription_id - from + FROM azure_security_center_subscription_pricing - where - name = any(ARRAY ['CosmosDbs', 'OpenSourceRelationalDatabases', 'SqlServerVirtualMachines', 'SqlServers']) - group by + WHERE + name = ANY(ARRAY ['CosmosDbs', 'OpenSourceRelationalDatabases', 'SqlServerVirtualMachines', 'SqlServers']) + GROUP BY subscription_id ) - select - sub.id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN data ->> 'CosmosDbs' = 'Standard' - and data ->> 'OpenSourceRelationalDatabases' = 'Standard' - and data ->> 'SqlServerVirtualMachines' = 'Standard' - and data ->> 'SqlServers' = 'Standard' - then 'ok' - else 'alarm' - end as status, - case - when + AND data ->> 'OpenSourceRelationalDatabases' = 'Standard' + AND data ->> 'SqlServerVirtualMachines' = 'Standard' + AND data ->> 'SqlServers' = 'Standard' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN data ->> 'CosmosDbs' = 'Standard' - and data ->> 'OpenSourceRelationalDatabases' = 'Standard' - and data ->> 'SqlServerVirtualMachines' = 'Standard' - and data ->> 'SqlServers' = 'Standard' - then 'Azure Defender on for Databases.' - else 'Azure Defender off for Databases.' - end as reason - from - azure_subscription as sub - left join defender_list as l on l.subscription_id = sub.subscription_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_subscription_pricing - - azure_subscription - Parameters: [] + AND data ->> 'OpenSourceRelationalDatabases' = 'Standard' + AND data ->> 'SqlServerVirtualMachines' = 'Standard' + AND data ->> 'SqlServers' = 'Standard' + THEN 'Azure Defender on for Databases.' + ELSE 'Azure Defender off for Databases.' + END AS reason + FROM + azure_subscription AS sub + LEFT JOIN defender_list AS l ON l.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.3 Ensure That Microsoft Defender for Databases Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_4.yaml b/compliance/controls/azure/azure_cis_v150_2_1_4.yaml old mode 100755 new mode 100644 index 089401c08..2bb849628 --- a/compliance/controls/azure/azure_cis_v150_2_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_4.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v150_2_1_4 -Title: "2.1.4 Ensure That Microsoft Defender for Azure SQL Databases Is Set To 'On'" -Description: "Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for SQL database servers.' - else 'Azure Defender off for SQL database servers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'SqlServers'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL database servers.' + ELSE 'Azure Defender off for SQL database servers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServers'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.4 Ensure That Microsoft Defender for Azure SQL Databases Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_5.yaml b/compliance/controls/azure/azure_cis_v150_2_1_5.yaml old mode 100755 new mode 100644 index 480c39472..2d73f0776 --- a/compliance/controls/azure/azure_cis_v150_2_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_5.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v150_2_1_5 -Title: "2.1.5 Ensure That Microsoft Defender for SQL Servers on Machines Is Set To 'On'" -Description: "Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for SQL servers on machines.' - else 'Azure Defender off for SQL servers on machines.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'SqlServerVirtualMachines'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL servers on machines.' + ELSE 'Azure Defender off for SQL servers on machines.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServerVirtualMachines'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.5 Ensure That Microsoft Defender for SQL Servers on Machines Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_6.yaml b/compliance/controls/azure/azure_cis_v150_2_1_6.yaml old mode 100755 new mode 100644 index 8af0a4bd0..b6b6da9c7 --- a/compliance/controls/azure/azure_cis_v150_2_1_6.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_6.yaml @@ -1,32 +1,32 @@ +Description: Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v150_2_1_6 -Title: "2.1.6 Ensure That Microsoft Defender for Open-Source Relational Databases Is Set To 'On'" -Description: "Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Open Source Relational Databases.' - else 'Azure Defender off for Open Source Relational Databases.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'OpenSourceRelationalDatabases'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Open Source Relational Databases.' + ELSE 'Azure Defender off for Open Source Relational Databases.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'OpenSourceRelationalDatabases'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.6 Ensure That Microsoft Defender for Open-Source Relational Databases Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_7.yaml b/compliance/controls/azure/azure_cis_v150_2_1_7.yaml old mode 100755 new mode 100644 index 07689275d..83c9a95d5 --- a/compliance/controls/azure/azure_cis_v150_2_1_7.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_7.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v150_2_1_7 -Title: "2.1.7 Ensure That Microsoft Defender for Storage Is Set To 'On'" -Description: "Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Storage.' - else 'Azure Defender off for Storage.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'StorageAccounts'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Storage.' + ELSE 'Azure Defender off for Storage.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'StorageAccounts'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.7 Ensure That Microsoft Defender for Storage Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_8.yaml b/compliance/controls/azure/azure_cis_v150_2_1_8.yaml old mode 100755 new mode 100644 index 2a0fa9951..97e201cc1 --- a/compliance/controls/azure/azure_cis_v150_2_1_8.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_8.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Containers enables threat detection for Container Registries including Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v150_2_1_8 -Title: "2.1.8 Ensure That Microsoft Defender for Containers Is Set To 'On'" -Description: "Turning on Microsoft Defender for Containers enables threat detection for Container Registries including Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Container Registry.' - else 'Azure Defender off for Container Registry.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'ContainerRegistry'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Container Registry.' + ELSE 'Azure Defender off for Container Registry.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'ContainerRegistry'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.8 Ensure That Microsoft Defender for Containers Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_1_9.yaml b/compliance/controls/azure/azure_cis_v150_2_1_9.yaml old mode 100755 new mode 100644 index 72f39daa5..0845c815d --- a/compliance/controls/azure/azure_cis_v150_2_1_9.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_1_9.yaml @@ -1,32 +1,35 @@ +Description: Microsoft Defender for Cosmos DB scans all incoming network requests for changes to your virtual machine. ID: azure_cis_v150_2_1_9 -Title: "2.1.9 Ensure That Microsoft Defender for Cosmos DB Is Set To 'On'" -Description: "Microsoft Defender for Cosmos DB scans all incoming network requests for changes to your virtual machine." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Cosmos DB.' - else 'Azure Defender off for Cosmos DB.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'CosmosDbs'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Cosmos DB.' + ELSE 'Azure Defender off for Cosmos DB.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'CosmosDbs'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.9 Ensure That Microsoft Defender for Cosmos DB Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_2_1.yaml b/compliance/controls/azure/azure_cis_v150_2_2_1.yaml old mode 100755 new mode 100644 index 2346791a7..8f3a75d7a --- a/compliance/controls/azure/azure_cis_v150_2_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_2_1.yaml @@ -1,30 +1,33 @@ +Description: Enable automatic provisioning of the monitoring agent to collect security data. ID: azure_cis_v150_2_2_1 -Title: "2.2.1 Ensure that Auto provisioning of 'Log Analytics agent for Azure VMs' is Set to 'On'" -Description: "Enable automatic provisioning of the monitoring agent to collect security data." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_prov.id as resource, - sc_prov.og_account_id as og_account_id, - sc_prov.og_resource_id as og_resource_id, - case - when auto_provision = 'On' then 'ok' - else 'alarm' - end as status, - case - when auto_provision = 'On' then 'Automatic provisioning of monitoring agent is on.' - else 'Automatic provisioning of monitoring agent is off.' - end as reason - from - azure_security_center_auto_provisioning sc_prov - right join azure_subscription sub on sc_prov.subscription_id = sub.subscription_id; - PrimaryTable: azure_security_center_auto_provisioning ListOfTables: - azure_security_center_auto_provisioning - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_auto_provisioning + QueryToExecute: | + SELECT + sc_prov.id AS resource, + sc_prov.og_account_id AS og_account_id, + sc_prov.og_resource_id AS og_resource_id, + CASE + WHEN auto_provision = 'On' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_provision = 'On' THEN 'Automatic provisioning of monitoring agent is on.' + ELSE 'Automatic provisioning of monitoring agent is off.' + END AS reason + FROM + azure_security_center_auto_provisioning sc_prov + RIGHT JOIN + azure_subscription sub + ON + sc_prov.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.2.1 Ensure that Auto provisioning of 'Log Analytics agent for Azure VMs' is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_2_2.yaml b/compliance/controls/azure/azure_cis_v150_2_2_2.yaml old mode 100755 new mode 100644 index ef744b061..c5dda0644 --- a/compliance/controls/azure/azure_cis_v150_2_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_2_2.yaml @@ -1,24 +1,24 @@ +Description: Enable automatic provisioning of vulnerability assessment for machines on both Azure and hybrid (Arc enabled) machines. ID: azure_cis_v150_2_2_2 -Title: "2.2.2 Ensure that Auto provisioning of 'Vulnerability assessment for machines' is Set to 'On'" -Description: "Enable automatic provisioning of vulnerability assessment for machines on both Azure and hybrid (Arc enabled) machines." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.2.2 Ensure that Auto provisioning of 'Vulnerability assessment for machines' is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_2_3.yaml b/compliance/controls/azure/azure_cis_v150_2_2_3.yaml old mode 100755 new mode 100644 index 075f9f5b9..201a293d0 --- a/compliance/controls/azure/azure_cis_v150_2_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_2_3.yaml @@ -1,24 +1,24 @@ +Description: Enable automatic provisioning of the Microsoft Defender for Containers components. ID: azure_cis_v150_2_2_3 -Title: "2.2.3 Ensure that Auto provisioning of 'Microsoft Defender for Containers components' is Set to 'On'" -Description: "Enable automatic provisioning of the Microsoft Defender for Containers components." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.2.3 Ensure that Auto provisioning of 'Microsoft Defender for Containers components' is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_3_1.yaml b/compliance/controls/azure/azure_cis_v150_2_3_1.yaml old mode 100755 new mode 100644 index 7d799dc02..08d645f06 --- a/compliance/controls/azure/azure_cis_v150_2_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_3_1.yaml @@ -1,42 +1,40 @@ +Description: Enable security alert emails to subscription owners. ID: azure_cis_v150_2_3_1 -Title: "2.3.1 Ensure That 'All users with the following roles' is set to 'Owner'" -Description: "Enable security alert emails to subscription owners." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with contact_info as ( - select - count(*) filter (where alerts_to_admins = 'On') as admin_alert_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alerts_to_admins = 'On') AS admin_alert_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when admin_alert_count > 0 then 'ok' - else 'alarm' - end as status, - case - when admin_alert_count > 0 then '"All users with the following roles" set to Owner' - else '"All users with the following roles" not set to Owner.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN admin_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN admin_alert_count > 0 THEN '"All users with the following roles" set to Owner' + ELSE '"All users with the following roles" not set to Owner.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - ``` - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.3.1 Ensure That 'All users with the following roles' is set to 'Owner' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_3_2.yaml b/compliance/controls/azure/azure_cis_v150_2_3_2.yaml old mode 100755 new mode 100644 index 58da8043c..c257959f3 --- a/compliance/controls/azure/azure_cis_v150_2_3_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_3_2.yaml @@ -1,46 +1,44 @@ +Description: Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address. ID: azure_cis_v150_2_3_2 -Title: "2.3.2 Ensure 'Additional email addresses' is Configured with a Security Contact Email" -Description: "Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with contact_info as ( - select - jsonb_agg(email) filter (where name = 'default' and email != '') as default_email, - count(*) filter (where name != 'default') as non_default_count, - count(*) filter (where name = 'default') as default_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_security_center_contact + QueryToExecute: | + WITH contact_info AS ( + SELECT + JSONB_AGG(email) FILTER (WHERE name = 'default' AND email != '') AS default_email, + COUNT(*) FILTER (WHERE name != 'default') AS non_default_count, + COUNT(*) FILTER (WHERE name = 'default') AS default_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when non_default_count > 0 then 'ok' - when default_count = 1 and jsonb_array_length(default_email) != 0 then 'ok' - else 'alarm' - end as status, - case - when non_default_count > 0 then 'Additional email addresses configured.' - when default_count = 1 and default_email is not null then'Additional email addresses configured.' - else 'Additional email addresses not configured.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN non_default_count > 0 THEN 'ok' + WHEN default_count = 1 AND JSONB_ARRAY_LENGTH(default_email) != 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN non_default_count > 0 THEN 'Additional email addresses configured.' + WHEN default_count = 1 AND default_email IS NOT NULL THEN 'Additional email addresses configured.' + ELSE 'Additional email addresses not configured.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - ``` - PrimaryTable: azure_security_center_contact - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.3.2 Ensure 'Additional email addresses' is Configured with a Security Contact Email \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_3_3.yaml b/compliance/controls/azure/azure_cis_v150_2_3_3.yaml old mode 100755 new mode 100644 index 2151569a5..c21bdfc73 --- a/compliance/controls/azure/azure_cis_v150_2_3_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_3_3.yaml @@ -1,40 +1,40 @@ +Description: Enables emailing security alerts to the subscription owner or other designated security contact. ID: azure_cis_v150_2_3_3 -Title: "2.3.3 Ensure That 'Notify about alerts with the following severity' is Set to 'High'" -Description: "Enables emailing security alerts to the subscription owner or other designated security contact." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with contact_info as ( - select - count(*) filter (where alert_notifications = 'On') as notification_alert_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alert_notifications = 'On') AS notification_alert_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when notification_alert_count > 0 then 'ok' - else 'alarm' - end as status, - case - when notification_alert_count > 0 then '"Notify about alerts with the following severity" set to High.' - else '"Notify about alerts with the following severity" not set to High.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN notification_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN notification_alert_count > 0 THEN '"Notify about alerts with the following severity" set to High.' + ELSE '"Notify about alerts with the following severity" not set to High.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.3.3 Ensure That 'Notify about alerts with the following severity' is Set to 'High' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_4_1.yaml b/compliance/controls/azure/azure_cis_v150_2_4_1.yaml old mode 100755 new mode 100644 index 22a85c25f..3a159cbef --- a/compliance/controls/azure/azure_cis_v150_2_4_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_4_1.yaml @@ -1,32 +1,32 @@ +Description: This integration setting enables Microsoft Defender for Cloud Apps (formerly 'Microsoft Cloud App Security' or 'MCAS' - see additional info) to communicate with Microsoft Defender for Cloud. ID: azure_cis_v150_2_4_1 -Title: "2.4.1 Ensure that Microsoft Defender for Cloud Apps integration with Microsoft Defender for Cloud is Selected" -Description: "This integration setting enables Microsoft Defender for Cloud Apps (formerly 'Microsoft Cloud App Security' or 'MCAS' - see additional info) to communicate with Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_sett.id as resource, - sc_sett.og_account_id as og_account_id, - sc_sett.og_resource_id as og_resource_id, - case - when enabled then 'ok' - else 'alarm' - end as status, - case - when enabled then 'Windows Defender ATP (WDATP) integrated with Security Center.' - else 'Windows Defender ATP (WDATP) not integrated with Security Center.' - end as reason - from - azure_security_center_setting sc_sett - right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id - where - name = 'MCAS'; - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Windows Defender ATP (WDATP) integrated with Security Center.' + ELSE 'Windows Defender ATP (WDATP) not integrated with Security Center.' + END AS reason + FROM + azure_security_center_setting sc_sett + RIGHT JOIN azure_subscription sub ON sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'MCAS'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.4.1 Ensure that Microsoft Defender for Cloud Apps integration with Microsoft Defender for Cloud is Selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_4_2.yaml b/compliance/controls/azure/azure_cis_v150_2_4_2.yaml old mode 100755 new mode 100644 index 0dcebd9e2..173e01778 --- a/compliance/controls/azure/azure_cis_v150_2_4_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_4_2.yaml @@ -1,32 +1,33 @@ +Description: This integration setting enables Microsoft Defender for Endpoint (formerly 'Advanced Threat Protection' or 'ATP' or 'WDATP' - see additional info) to communicate with Microsoft Defender for Cloud. ID: azure_cis_v150_2_4_2 -Title: "2.4.2 Ensure that Microsoft Defender for Endpoint integration with Microsoft Defender for Cloud is selected" -Description: "This integration setting enables Microsoft Defender for Endpoint (formerly 'Advanced Threat Protection' or 'ATP' or 'WDATP' - see additional info) to communicate with Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_sett.id as resource, - sc_sett.og_account_id as og_account_id, - sc_sett.og_resource_id as og_resource_id, - case - when enabled then 'ok' - else 'alarm' - end as status, - case - when enabled then 'Microsoft Cloud App Security (MCAS) integrated with Security Center.' - else 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.' - end as reason - from - azure_security_center_setting sc_sett - right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id - where - name = 'WDATP'; - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Microsoft Cloud App Security (MCAS) integrated with Security Center.' + ELSE 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.' + END AS reason + FROM + azure_security_center_setting sc_sett + RIGHT JOIN + azure_subscription sub ON sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'WDATP'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.4.2 Ensure that Microsoft Defender for Endpoint integration with Microsoft Defender for Cloud is selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_5.yaml b/compliance/controls/azure/azure_cis_v150_2_5.yaml old mode 100755 new mode 100644 index 03da88499..66747fb2c --- a/compliance/controls/azure/azure_cis_v150_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_5.yaml @@ -1,24 +1,24 @@ +Description: Ensure that the latest OS patches for all virtual machines are applied. ID: azure_cis_v150_2_5 -Title: "2.5 Ensure that Microsoft Defender Recommendation for 'Apply system updates' status is 'Completed'" -Description: "Ensure that the latest OS patches for all virtual machines are applied." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.5 Ensure that Microsoft Defender Recommendation for 'Apply system updates' status is 'Completed' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_2_6.yaml b/compliance/controls/azure/azure_cis_v150_2_6.yaml old mode 100755 new mode 100644 index fc5ca061c..3b53bf6da --- a/compliance/controls/azure/azure_cis_v150_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v150_2_6.yaml @@ -1,15 +1,50 @@ +Description: None of the settings offered by ASC Default policy should be set to effect Disabled. ID: azure_cis_v150_2_6 -Title: "2.6 Ensure Any of the ASC Default Policy Settings are Not Set to 'Disabled'" -Description: "None of the settings offered by ASC Default policy should be set to effect Disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with policy_assignment_parameters as (\n select\n id,\n name,\n key,\n parameters -> key ->> 'value' as value,\n subscription_id\n from\n azure_policy_assignment,\n jsonb_object_keys(parameters) as key\n where\n name = 'SecurityCenterBuiltIn'\n)\nselect\n sub.id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(value = 'Disabled') > 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when count(value = 'Disabled') > 0 then 'Settings disabled for ' || count(*) filter (where value = 'Disabled') || ' parameters.'\n else 'Settings enabled for all the parameters.'\n end as reason\n \n \nfrom\n policy_assignment_parameters pol_assignment\n right join azure_subscription sub on pol_assignment.subscription_id = sub.subscription_id\ngroup by\n sub.id,\n pol_assignment.id,\n sub._ctx,\n sub.subscription_id,\n pol_assignment.subscription_id,\n sub.display_name;" - PrimaryTable: azure_policy_assignment ListOfTables: - azure_policy_assignment - azure_subscription Parameters: [] + PrimaryTable: azure_policy_assignment + QueryToExecute: | + WITH policy_assignment_parameters AS ( + SELECT + id, + name, + key, + parameters -> key ->> 'value' AS value, + subscription_id + FROM + azure_policy_assignment, + jsonb_object_keys(parameters) AS key + WHERE + name = 'SecurityCenterBuiltIn' + ) + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(value = 'Disabled') > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(value = 'Disabled') > 0 THEN 'Settings disabled for ' || COUNT(*) FILTER (WHERE value = 'Disabled') || ' parameters.' + ELSE 'Settings enabled for all the parameters.' + END AS reason + FROM + policy_assignment_parameters pol_assignment + RIGHT JOIN azure_subscription sub ON pol_assignment.subscription_id = sub.subscription_id + GROUP BY + sub.id, + pol_assignment.id, + sub._ctx, + sub.subscription_id, + pol_assignment.subscription_id, + sub.display_name Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.6 Ensure Any of the ASC Default Policy Settings are Not Set to 'Disabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_1.yaml b/compliance/controls/azure/azure_cis_v150_3_1.yaml old mode 100755 new mode 100644 index d87969de6..4e5e5b86c --- a/compliance/controls/azure/azure_cis_v150_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_1.yaml @@ -1,32 +1,32 @@ +Description: Enable data encryption in transit. ID: azure_cis_v150_3_1 -Title: "3.1 Ensure that 'Secure transfer required' is set to 'Enabled'" -Description: "Enable data encryption in transit." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not enable_https_traffic_only then 'alarm' - else 'ok' - end as status, - case - when not enable_https_traffic_only then sa.name || ' encryption in transit not enabled.' - else sa.name || ' encryption in transit enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT enable_https_traffic_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT enable_https_traffic_only THEN sa.name || ' encryption in transit not enabled.' + ELSE sa.name || ' encryption in transit enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.1 Ensure that 'Secure transfer required' is set to 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_10.yaml b/compliance/controls/azure/azure_cis_v150_3_10.yaml old mode 100755 new mode 100644 index 3be45cae0..a8a2971e3 --- a/compliance/controls/azure/azure_cis_v150_3_10.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_10.yaml @@ -1,42 +1,42 @@ +Description: Use private endpoints for your Azure Storage accounts to allow clients and services to securely access data located over a network via an encrypted Private Link. To do this, the private endpoint uses an IP address from the VNet for each service. Network traffic between disparate services securely traverses encrypted over the VNet. This VNet can also link addressing space, extending your network and accessing resources on it. Similarly, it can be a tunnel through public networks to connect remote infrastructures together. This creates further security through segmenting network traffic and preventing outside sources from accessing it. ID: azure_cis_v150_3_10 -Title: "3.10 Ensure Private Endpoints are used to access Storage Accounts" -Description: "Use private endpoints for your Azure Storage accounts to allow clients and services to securely access data located over a network via an encrypted Private Link. To do this, the private endpoint uses an IP address from the VNet for each service. Network traffic between disparate services securely traverses encrypted over the VNet. This VNet can also link addressing space, extending your network and accessing resources on it. Similarly, it can be a tunnel through public networks to connect remote infrastructures together. This creates further security through segmenting network traffic and preventing outside sources from accessing it." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with storage_account_connection as ( - select - distinct a.id - from - azure_storage_account as a, - jsonb_array_elements(private_endpoint_connections) as connection - where - connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' - ) - select - distinct a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when s.id is null then 'alarm' - else 'ok' - end as status, - case - when s.id is null then a.name || ' not uses private link.' - else a.name || ' uses private link.' - end as reason - from - azure_storage_account as a - left join storage_account_connection as s on a.id = s.id, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + WITH storage_account_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_storage_account AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + DISTINCT a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN s.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason + FROM + azure_storage_account AS a + LEFT JOIN storage_account_connection AS s ON a.id = s.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.10 Ensure Private Endpoints are used to access Storage Accounts \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_11.yaml b/compliance/controls/azure/azure_cis_v150_3_11.yaml old mode 100755 new mode 100644 index ff9d1de0e..2ad5508cc --- a/compliance/controls/azure/azure_cis_v150_3_11.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_11.yaml @@ -1,32 +1,32 @@ +Description: The Azure Storage blobs contain data like ePHI or Financial, which can be secret or personal. Data that is erroneously modified or deleted by an application or other storage account user will cause data loss or unavailability. It is recommended that both Azure Containers with attached Blob Storage and standalone containers with Blob Storage be made recoverable by enabling the soft delete configuration. This is to save and recover data when blobs or blob snapshots are deleted. ID: azure_cis_v150_3_11 -Title: "3.11 Ensure Soft Delete is Enabled for Azure Containers and Blob Storage" -Description: "The Azure Storage blobs contain data like ePHI or Financial, which can be secret or personal. Data that is erroneously modified or deleted by an application or other storage account user will cause data loss or unavailability. It is recommended that both Azure Containers with attached Blob Storage and standalone containers with Blob Storage be made recoverable by enabling the soft delete configuration. This is to save and recover data when blobs or blob snapshots are deleted." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not blob_soft_delete_enabled then 'alarm' - else 'ok' - end as status, - case - when not blob_soft_delete_enabled then sa.name || ' blobs soft delete disabled.' - else sa.name || ' blobs soft delete enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT blob_soft_delete_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT blob_soft_delete_enabled THEN sa.name || ' blobs soft delete disabled.' + ELSE sa.name || ' blobs soft delete enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.11 Ensure Soft Delete is Enabled for Azure Containers and Blob Storage \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_12.yaml b/compliance/controls/azure/azure_cis_v150_3_12.yaml old mode 100755 new mode 100644 index 793d6c9e8..fe263b278 --- a/compliance/controls/azure/azure_cis_v150_3_12.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_12.yaml @@ -1,32 +1,32 @@ +Description: Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys. ID: azure_cis_v150_3_12 -Title: "3.12 Ensure Storage for Critical Data are Encrypted with Customer Managed Keys" -Description: "Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when sa.encryption_key_source = 'Microsoft.Storage' then 'alarm' - else 'ok' - end as status, - case - when sa.encryption_key_source = 'Microsoft.Storage' then sa.name || ' not encrypted with CMK.' - else sa.name || ' encrypted with CMK.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN sa.name || ' not encrypted with CMK.' + ELSE sa.name || ' encrypted with CMK.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.12 Ensure Storage for Critical Data are Encrypted with Customer Managed Keys \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_14.yaml b/compliance/controls/azure/azure_cis_v150_3_14.yaml old mode 100755 new mode 100644 index e6875e939..fbb3c415b --- a/compliance/controls/azure/azure_cis_v150_3_14.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_14.yaml @@ -1,38 +1,38 @@ +Description: 'Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.' ID: azure_cis_v150_3_14 -Title: "3.14 Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' Requests" -Description: "Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when table_logging_write and table_logging_read and table_logging_delete then 'ok' - else 'alarm' - end as status, - case - when table_logging_write and table_logging_read and table_logging_delete - then sa.name || ' table service logging enabled for read, write, delete requests.' - else sa.name || ' table service logging not enabled for: ' || - concat_ws(', ', - case when not table_logging_write then 'write' end, - case when not table_logging_read then 'read' end, - case when not table_logging_delete then 'delete' end - ) || ' requests.' - end as reason - from - azure_storage_account as sa, - azure_subscription as sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN table_logging_write AND table_logging_read AND table_logging_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN table_logging_write AND table_logging_read AND table_logging_delete + THEN sa.name || ' table service logging enabled for read, write, delete requests.' + ELSE sa.name || ' table service logging not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT table_logging_write THEN 'write' END, + CASE WHEN NOT table_logging_read THEN 'read' END, + CASE WHEN NOT table_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.14 Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' Requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_15.yaml b/compliance/controls/azure/azure_cis_v150_3_15.yaml old mode 100755 new mode 100644 index 28dd73465..9f8c3ad04 --- a/compliance/controls/azure/azure_cis_v150_3_15.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_15.yaml @@ -1,34 +1,34 @@ +Description: In some cases, Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2. ID: azure_cis_v150_3_15 -Title: "3.15 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2'" -Description: "In some cases, Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when minimum_tls_version = 'TLSEnforcementDisabled' then 'alarm' - when minimum_tls_version = 'TLS1_2' then 'ok' - else 'alarm' - end as status, - case - when minimum_tls_version = 'TLSEnforcementDisabled' then sa.name || ' TLS enforcement is disabled.' - when minimum_tls_version = 'TLS1_2' then sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' - else sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN minimum_tls_version = 'TLSEnforcementDisabled' THEN 'alarm' + WHEN minimum_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_tls_version = 'TLSEnforcementDisabled' THEN sa.name || ' TLS enforcement is disabled.' + WHEN minimum_tls_version = 'TLS1_2' THEN sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + ELSE sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.15 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_2.yaml b/compliance/controls/azure/azure_cis_v150_3_2.yaml old mode 100755 new mode 100644 index d7c6c0b13..77a2fb46c --- a/compliance/controls/azure/azure_cis_v150_3_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_2.yaml @@ -1,32 +1,32 @@ +Description: Enabling double encryption at the hardware level on top of the default software encryption for Storage Accounts accessing Azure storage solutions. ID: azure_cis_v150_3_2 -Title: "3.2 Ensure that 'Enable Infrastructure Encryption' for Each Storage Account in Azure Storage is Set to ‘enabled’" -Description: "Enabling double encryption at the hardware level on top of the default software encryption for Storage Accounts accessing Azure storage solutions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when require_infrastructure_encryption then 'ok' - else 'alarm' - end as status, - case - when require_infrastructure_encryption then name || ' infrastructure encryption enabled.' - else name || ' infrastructure encryption disabled.' - end as reason - from - azure_storage_account as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN require_infrastructure_encryption THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN require_infrastructure_encryption THEN name || ' infrastructure encryption enabled.' + ELSE name || ' infrastructure encryption disabled.' + END AS reason + FROM + azure_storage_account AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.2 Ensure that 'Enable Infrastructure Encryption' for Each Storage Account in Azure Storage is Set to ‘enabled’ \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_3.yaml b/compliance/controls/azure/azure_cis_v150_3_3.yaml old mode 100755 new mode 100644 index f6090331b..361000b76 --- a/compliance/controls/azure/azure_cis_v150_3_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_3.yaml @@ -1,24 +1,24 @@ +Description: Access Keys authenticate application access requests to data contained in Storage Accounts. A periodic rotation of these keys is recommended to ensure that potentially compromised keys cannot result in a long-term exploitable credential. The Rotation Reminder is an automatic reminder feature for a manual procedure. ID: azure_cis_v150_3_3 -Title: "3.3 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account" -Description: "Access Keys authenticate application access requests to data contained in Storage Accounts. A periodic rotation of these keys is recommended to ensure that potentially compromised keys cannot result in a long-term exploitable credential. The Rotation Reminder is an automatic reminder feature for a manual procedure." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.3 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_4.yaml b/compliance/controls/azure/azure_cis_v150_3_4.yaml old mode 100755 new mode 100644 index f45670a44..aaec4f111 --- a/compliance/controls/azure/azure_cis_v150_3_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_4.yaml @@ -1,24 +1,24 @@ +Description: For increased security, regenerate storage account access keys periodically. ID: azure_cis_v150_3_4 -Title: "3.4 Ensure that Storage Account Access Keys are Periodically Regenerated" -Description: "For increased security, regenerate storage account access keys periodically." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.4 Ensure that Storage Account Access Keys are Periodically Regenerated \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_5.yaml b/compliance/controls/azure/azure_cis_v150_3_5.yaml old mode 100755 new mode 100644 index 6bf4140c1..adb77708e --- a/compliance/controls/azure/azure_cis_v150_3_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_5.yaml @@ -1,38 +1,38 @@ +Description: 'The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information, and the sizes of the request and response messages.' ID: azure_cis_v150_3_5 -Title: "3.5 Ensure Storage Logging is Enabled for Queue Service for 'Read', 'Write', and 'Delete' request" -Description: "The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information, and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when queue_logging_read and queue_logging_write and queue_logging_delete then 'ok' - else 'alarm' - end as status, - case - when queue_logging_read and queue_logging_write and queue_logging_delete - then sa.name || ' queue service logging enabled for read, write, delete requests.' - else sa.name || ' queue service logging not enabled for: ' || - concat_ws(', ', - case when not queue_logging_write then 'write' end, - case when not queue_logging_read then 'read' end, - case when not queue_logging_delete then 'delete' end - ) || ' requests.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete + THEN sa.name || ' queue service logging enabled for read, write, delete requests.' + ELSE sa.name || ' queue service logging not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT queue_logging_write THEN 'write' END, + CASE WHEN NOT queue_logging_read THEN 'read' END, + CASE WHEN NOT queue_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.5 Ensure Storage Logging is Enabled for Queue Service for 'Read', 'Write', and 'Delete' request \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_6.yaml b/compliance/controls/azure/azure_cis_v150_3_6.yaml old mode 100755 new mode 100644 index 52b4cfbbf..4c4b7dae8 --- a/compliance/controls/azure/azure_cis_v150_3_6.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_6.yaml @@ -1,24 +1,24 @@ +Description: Expire shared access signature tokens within an hour. ID: azure_cis_v150_3_6 -Title: "3.6 Ensure that Shared Access Signature Tokens Expire Within an Hour" -Description: "Expire shared access signature tokens within an hour." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.6 Ensure that Shared Access Signature Tokens Expire Within an Hour \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_7.yaml b/compliance/controls/azure/azure_cis_v150_3_7.yaml old mode 100755 new mode 100644 index 80a066963..d8141da46 --- a/compliance/controls/azure/azure_cis_v150_3_7.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_7.yaml @@ -1,33 +1,33 @@ +Description: Disallowing public access for a storage account overrides the public access settings for individual containers in that storage account. ID: azure_cis_v150_3_7 -Title: "3.7 Ensure that 'Public access level' is disabled for storage accounts with blob containers" -Description: "Disallowing public access for a storage account overrides the public access settings for individual containers in that storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - container.id as resource, - container.og_account_id as og_account_id, - container.og_resource_id as og_resource_id, - case - when not account.allow_blob_public_access and container.public_access = 'None' then 'ok' - else 'alarm' - end as status, - case - when not account.allow_blob_public_access and container.public_access = 'None' - then account.name || ' container ' || container.name || ' doesn''t allow anonymous access.' - else account.name || ' container ' || container.name || ' allows anonymous access.' - end as reason - from - azure_storage_container container - join azure_storage_account account on container.account_name = account.name - join azure_subscription sub on sub.subscription_id = account.subscription_id; - PrimaryTable: azure_storage_container ListOfTables: - azure_storage_container - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_container + QueryToExecute: | + SELECT + container.id AS resource, + container.og_account_id AS og_account_id, + container.og_resource_id AS og_resource_id, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' + THEN account.name || ' container ' || container.name || ' doesn''t allow anonymous access.' + ELSE account.name || ' container ' || container.name || ' allows anonymous access.' + END AS reason + FROM + azure_storage_container container + JOIN azure_storage_account account ON container.account_name = account.name + JOIN azure_subscription sub ON sub.subscription_id = account.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.7 Ensure that 'Public access level' is disabled for storage accounts with blob containers \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_8.yaml b/compliance/controls/azure/azure_cis_v150_3_8.yaml old mode 100755 new mode 100644 index b6bfb60f7..2f60fed1b --- a/compliance/controls/azure/azure_cis_v150_3_8.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_8.yaml @@ -1,32 +1,32 @@ +Description: Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed. ID: azure_cis_v150_3_8 -Title: "3.8 Ensure Default Network Access Rule for Storage Accounts is Set to Deny" -Description: "Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when sa.network_rule_default_action = 'Allow' then 'alarm' - else 'ok' - end as status, - case - when sa.network_rule_default_action = 'Allow' then name || ' allows traffic from all networks.' - else name || ' allows traffic from specific networks.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN name || ' allows traffic from all networks.' + ELSE name || ' allows traffic from specific networks.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.8 Ensure Default Network Access Rule for Storage Accounts is Set to Deny \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_3_9.yaml b/compliance/controls/azure/azure_cis_v150_3_9.yaml old mode 100755 new mode 100644 index 34769dd53..ccc00bb52 --- a/compliance/controls/azure/azure_cis_v150_3_9.yaml +++ b/compliance/controls/azure/azure_cis_v150_3_9.yaml @@ -1,32 +1,32 @@ +Description: 'Some Azure services that interact with storage accounts operate from networks that can''t be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account. If the Allow trusted Azure services exception is enabled, the following services are granted access to the storage account: Azure Backup, Azure Site Recovery, Azure DevTest Labs, Azure Event Grid, Azure Event Hubs, Azure Networking, Azure Monitor, and Azure SQL Data Warehouse (when registered in the subscription).' ID: azure_cis_v150_3_9 -Title: "3.9 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access" -Description: "Some Azure services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account. If the Allow trusted Azure services exception is enabled, the following services are granted access to the storage account: Azure Backup, Azure Site Recovery, Azure DevTest Labs, Azure Event Grid, Azure Event Hubs, Azure Networking, Azure Monitor, and Azure SQL Data Warehouse (when registered in the subscription)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when network_rule_bypass not like '%AzureServices%' then 'alarm' - else 'ok' - end as status, - case - when network_rule_bypass not like '%AzureServices%' then sa.name || ' trusted Microsoft services not enabled.' - else sa.name || ' trusted Microsoft services enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN sa.name || ' trusted Microsoft services not enabled.' + ELSE sa.name || ' trusted Microsoft services enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.9 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_1_2.yaml b/compliance/controls/azure/azure_cis_v150_4_1_2.yaml old mode 100755 new mode 100644 index 35ddc37c5..5df9264c0 --- a/compliance/controls/azure/azure_cis_v150_4_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_1_2.yaml @@ -1,36 +1,36 @@ +Description: Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP). ID: azure_cis_v150_4_1_2 -Title: "4.1.2 Ensure no Azure SQL Databases allow ingress from 0.0.0.0/0 (ANY IP)" -Description: "Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' - or firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' - then 'alarm' - else 'ok' - end as status, - case - when firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' - or firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' - then s.title || ' allows ingress 0.0.0.0/0 or any ip over internet.' - else s.title || ' not allows ingress 0.0.0.0/0 or any ip over internet.' - end as reason - from - azure_sql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN s.title || ' allows ingress 0.0.0.0/0 or any IP over the internet.' + ELSE s.title || ' does not allow ingress 0.0.0.0/0 or any IP over the internet.' + END AS reason + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.2 Ensure no Azure SQL Databases allow ingress from 0.0.0.0/0 (ANY IP) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_1_4.yaml b/compliance/controls/azure/azure_cis_v150_4_1_4.yaml old mode 100755 new mode 100644 index 3a1d69a60..d7afbfdbe --- a/compliance/controls/azure/azure_cis_v150_4_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_1_4.yaml @@ -1,15 +1,32 @@ +Description: Use Azure Active Directory Authentication for authentication with SQL Database to manage credentials in a single place. ID: azure_cis_v150_4_1_4 -Title: "4.1.4 Ensure that Azure Active Directory Admin is Configured for SQL Servers" -Description: "Use Azure Active Directory Authentication for authentication with SQL Database to manage credentials in a single place." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when server_azure_ad_administrator is null then 'alarm'\n else 'ok'\n end as status,\n case\n when server_azure_ad_administrator is null then name || ' Azure AD authentication not configured.'\n else name || ' Azure AD authentication configured.'\n end as reason\n \nfrom\n azure_sql_server s,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN server_azure_ad_administrator IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN server_azure_ad_administrator IS NULL THEN name || ' Azure AD authentication not configured.' + ELSE name || ' Azure AD authentication configured.' + END AS reason + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.4 Ensure that Azure Active Directory Admin is Configured for SQL Servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_1_5.yaml b/compliance/controls/azure/azure_cis_v150_4_1_5.yaml old mode 100755 new mode 100644 index 365a22d68..817d4f181 --- a/compliance/controls/azure/azure_cis_v150_4_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_1_5.yaml @@ -1,33 +1,37 @@ +Description: Enable Transparent Data Encryption on every SQL server. ID: azure_cis_v150_4_1_5 -Title: "4.1.5 Ensure that 'Data encryption' is set to 'On' on a SQL Database" -Description: "Enable Transparent Data Encryption on every SQL server." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.database_id resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then s.title || ' transparent data encryption enabled.' - else s.title || ' transparent data encryption disabled.' - end as reason - from - azure_sql_database as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id - and s.name <> 'master'; - PrimaryTable: azure_sql_database ListOfTables: - azure_sql_database - azure_subscription Parameters: [] + PrimaryTable: azure_sql_database + QueryToExecute: | + SELECT + s.database_id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' + OR transparent_data_encryption ->> 'state' = 'Enabled' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' + OR transparent_data_encryption ->> 'state' = 'Enabled' + THEN s.title || ' transparent data encryption enabled.' + ELSE s.title || ' transparent data encryption disabled.' + END AS reason + FROM + azure_sql_database AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id + AND s.name <> 'master'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.5 Ensure that 'Data encryption' is set to 'On' on a SQL Database \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_3_1.yaml b/compliance/controls/azure/azure_cis_v150_4_3_1.yaml old mode 100755 new mode 100644 index 5ed5af6eb..9fb6c862e --- a/compliance/controls/azure/azure_cis_v150_4_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_3_1.yaml @@ -1,32 +1,32 @@ +Description: Enable SSL connection on PostgreSQL Servers. ID: azure_cis_v150_4_3_1 -Title: "4.3.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for PostgreSQL Database Server" -Description: "Enable SSL connection on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when ssl_enforcement = 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when ssl_enforcement = 'Disabled' then name || ' SSL connection disabled.' - else name || ' SSL connection enabled.' - end as reason - from - azure_postgresql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN name || ' SSL connection disabled.' + ELSE name || ' SSL connection enabled.' + END AS reason + FROM + azure_postgresql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_3_7.yaml b/compliance/controls/azure/azure_cis_v150_4_3_7.yaml old mode 100755 new mode 100644 index 8b2e2688d..f9acc5bea --- a/compliance/controls/azure/azure_cis_v150_4_3_7.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_3_7.yaml @@ -1,24 +1,24 @@ +Description: Disable access from Azure services to PostgreSQL Database Server. ID: azure_cis_v150_4_3_7 -Title: "4.3.7 Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled" -Description: "Disable access from Azure services to PostgreSQL Database Server." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 4.3.7 Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_3_8.yaml b/compliance/controls/azure/azure_cis_v150_4_3_8.yaml old mode 100755 new mode 100644 index 932afab06..598f5a25e --- a/compliance/controls/azure/azure_cis_v150_4_3_8.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_3_8.yaml @@ -1,32 +1,32 @@ +Description: Enable encryption at rest for PostgreSQL Databases. ID: azure_cis_v150_4_3_8 -Title: "4.3.8 Ensure 'Infrastructure double encryption' for PostgreSQL Database Server is 'Enabled'" -Description: "Enable encryption at rest for PostgreSQL Databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when infrastructure_encryption = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when infrastructure_encryption = 'Enabled' then name || ' infrastructure encryption enabled.' - else name || ' infrastructure encryption disabled.' - end as reason - from - azure_postgresql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN name || ' infrastructure encryption enabled.' + ELSE name || ' infrastructure encryption disabled.' + END AS reason + FROM + azure_postgresql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.8 Ensure 'Infrastructure double encryption' for PostgreSQL Database Server is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_4_1.yaml b/compliance/controls/azure/azure_cis_v150_4_4_1.yaml old mode 100755 new mode 100644 index 22421121b..01bb1c2ef --- a/compliance/controls/azure/azure_cis_v150_4_4_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_4_1.yaml @@ -1,32 +1,32 @@ +Description: Enable SSL connection on MySQL Servers. ID: azure_cis_v150_4_4_1 -Title: "4.4.1 Ensure 'Enforce SSL connection' is set to 'Enabled' for Standard MySQL Database Server" -Description: "Enable SSL connection on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when ssl_enforcement = 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when ssl_enforcement = 'Disabled' then s.name || ' SSL connection disabled.' - else s.name || ' SSL connection enabled.' - end as reason - from - azure_mysql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN s.name || ' SSL connection disabled.' + ELSE s.name || ' SSL connection enabled.' + END AS reason + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.1 Ensure 'Enforce SSL connection' is set to 'Enabled' for Standard MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_4_2.yaml b/compliance/controls/azure/azure_cis_v150_4_4_2.yaml old mode 100755 new mode 100644 index 8978bf2c9..e6a38a54f --- a/compliance/controls/azure/azure_cis_v150_4_4_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_4_2.yaml @@ -1,34 +1,34 @@ +Description: Ensure TLS version on MySQL flexible servers is set to the default value. ID: azure_cis_v150_4_4_2 -Title: "4.4.2 Ensure 'TLS Version' is set to 'TLSV1.2' for MySQL flexible Database Server" -Description: "Ensure TLS version on MySQL flexible servers is set to the default value." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when minimal_tls_version = 'TLSEnforcementDisabled' then 'alarm' - when minimal_tls_version = 'TLS1_2' then 'ok' - else 'alarm' - end as status, - case - when minimal_tls_version = 'TLSEnforcementDisabled' then s.name || ' TLS enforcement is disabled.' - when minimal_tls_version = 'TLS1_2' then s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' - else s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' - end as reason - from - azure_mysql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN minimal_tls_version = 'TLSEnforcementDisabled' THEN 'alarm' + WHEN minimal_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimal_tls_version = 'TLSEnforcementDisabled' THEN s.name || ' TLS enforcement is disabled.' + WHEN minimal_tls_version = 'TLS1_2' THEN s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' + ELSE s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' + END AS reason + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.2 Ensure 'TLS Version' is set to 'TLSV1.2' for MySQL flexible Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_4_3.yaml b/compliance/controls/azure/azure_cis_v150_4_4_3.yaml old mode 100755 new mode 100644 index 5049b2839..749c3768a --- a/compliance/controls/azure/azure_cis_v150_4_4_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_4_3.yaml @@ -1,34 +1,34 @@ +Description: Enable audit_log_enabled on MySQL Servers. ID: azure_cis_v150_4_4_3 -Title: "4.4.3 Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL Database Server" -Description: "Enable audit_log_enabled on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm' - else 'ok' - end as status, - case - when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter audit_log_enabled off.' - else s.name || ' server parameter audit_log_enabled on.' - end as reason - from - azure_mysql_server as s, - jsonb_array_elements(server_configurations) config, - azure_subscription sub - where - config ->> 'Name' = 'audit_log_enabled' - and sub.subscription_id = s.subscription_id; - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter audit_log_enabled off.' + ELSE s.name || ' server parameter audit_log_enabled on.' + END AS reason + FROM + azure_mysql_server AS s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'audit_log_enabled' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.3 Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_5_1.yaml b/compliance/controls/azure/azure_cis_v150_4_5_1.yaml old mode 100755 new mode 100644 index 07b803827..b898300bd --- a/compliance/controls/azure/azure_cis_v150_4_5_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_5_1.yaml @@ -1,34 +1,34 @@ -ID: azure_cis_v150_4_5_1 -Title: "4.5.1 Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks" Description: "" +ID: azure_cis_v150_4_5_1 +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when public_network_access = 'Disabled' then 'ok' - when public_network_access = 'Enabled' and is_virtual_network_filter_enabled = 'true' then 'ok' - else 'alarm' - end as status, - case - when public_network_access = 'Disabled' then a.name || ' public network access disabled.' - when public_network_access = 'Enabled' and is_virtual_network_filter_enabled = 'true' then a.name || ' virtual network filter enabled.' - else a.name || ' virtual network filter disabled.' - end as reason - from - azure_cosmosdb_account as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Disabled' THEN 'ok' + WHEN public_network_access = 'Enabled' AND is_virtual_network_filter_enabled = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN public_network_access = 'Disabled' THEN a.name || ' public network access disabled.' + WHEN public_network_access = 'Enabled' AND is_virtual_network_filter_enabled = 'true' THEN a.name || ' virtual network filter enabled.' + ELSE a.name || ' virtual network filter disabled.' + END AS reason + FROM + azure_cosmosdb_account AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.5.1 Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_4_5_2.yaml b/compliance/controls/azure/azure_cis_v150_4_5_2.yaml old mode 100755 new mode 100644 index 5dd2b2418..a0e8b20dd --- a/compliance/controls/azure/azure_cis_v150_4_5_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_4_5_2.yaml @@ -1,42 +1,42 @@ +Description: Based on business needs or criticality of data/databases hosted on a SQL server, it is recommended that the TDE protector is encrypted by a key that is managed by the data owner (Customer-managed key). ID: azure_cis_v150_4_5_2 -Title: "4.5.2 Ensure That Private Endpoints Are Used Where Possible" -Description: "Based on business needs or criticality of data/databases hosted a SQL server, it is recommended that the TDE protector is encrypted by a key that is managed by the data owner (Customer-managed key)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with cosmosdb_private_connection as ( - select - distinct a.id - from - azure_cosmosdb_account as a, - jsonb_array_elements(private_endpoint_connections) as connection - where - connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' - ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when c.id is null then 'alarm' - else 'ok' - end as status, - case - when c.id is null then a.name || ' not uses private link.' - else a.name || ' uses private link.' - end as reason - from - azure_cosmosdb_account as a - left join cosmosdb_private_connection as c on c.id = a.id, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + WITH cosmosdb_private_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_cosmosdb_account AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason + FROM + azure_cosmosdb_account AS a + LEFT JOIN cosmosdb_private_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.5.2 Ensure That Private Endpoints Are Used Where Possible \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_1_1.yaml b/compliance/controls/azure/azure_cis_v150_5_1_1.yaml old mode 100755 new mode 100644 index 3fe61c95b..6c4b0e9df --- a/compliance/controls/azure/azure_cis_v150_5_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_1_1.yaml @@ -1,24 +1,24 @@ +Description: Enable Diagnostic settings for exporting activity logs. Diagnostic settings are available for each individual resource within a subscription. Settings should be configured for all appropriate resources for your environment. ID: azure_cis_v150_5_1_1 -Title: "5.1.1 Ensure that a 'Diagnostics Setting' exists" -Description: "Enable Diagnostic settings for exporting activity logs. Diagnostic settings are available for each individual resource within a subscription. Settings should be configured for all appropriate resources for your environment." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.1 Ensure that a 'Diagnostics Setting' exists \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_1_2.yaml b/compliance/controls/azure/azure_cis_v150_5_1_2.yaml old mode 100755 new mode 100644 index cab0fa68b..b53c9b55f --- a/compliance/controls/azure/azure_cis_v150_5_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_1_2.yaml @@ -1,58 +1,58 @@ +Description: 'A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: ''Ensure that a ''Diagnostic Setting'' exists.'' The diagnostic setting should be configured to log the appropriate activities from the control/management plane.' ID: azure_cis_v150_5_1_2 -Title: "5.1.2 Ensure Diagnostic Setting captures appropriate categories" -Description: "A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: 'Ensure that a 'Diagnostic Setting' exists.' The diagnostic setting should be configured to log the appropriate activities from the control/management plane." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with enabled_settings as ( - select + ListOfTables: + - azure_diagnostic_setting + - azure_subscription + Parameters: [] + PrimaryTable: azure_diagnostic_setting + QueryToExecute: | + WITH enabled_settings AS ( + SELECT name, id, _ctx, resource_group, subscription_id, - count(*) filter (where l ->> 'enabled' = 'true' - and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy') - ) as valid_category_count, - string_agg(l ->> 'category', ', ') filter (where l ->> 'enabled' = 'true' - and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy') - ) as valid_categories - from + COUNT(*) FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy') + ) AS valid_category_count, + STRING_AGG(l ->> 'category', ', ') FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy') + ) AS valid_categories + FROM azure_diagnostic_setting, - jsonb_array_elements(logs) as l - group by + jsonb_array_elements(logs) AS l + GROUP BY name, id, _ctx, resource_group, subscription_id ) - select - sett.id as resource, - sett.og_account_id as og_account_id, - sett.og_resource_id as og_resource_id, - case - when valid_category_count = 4 then 'ok' - else 'alarm' - end as status, - case - when valid_category_count = 4 - then name || ' logs enabled for required categories administrative, security, alert and policy.' - when valid_category_count > 0 - then sett.name || ' logs enabled for ' || valid_categories || ' categories.' - else sett.name || ' logs not enabled for categories administrative, security, alert and policy.' - end as reason - from + SELECT + sett.id AS resource, + sett.og_account_id AS og_account_id, + sett.og_resource_id AS og_resource_id, + CASE + WHEN valid_category_count = 4 THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN valid_category_count = 4 + THEN name || ' logs enabled for required categories Administrative, Security, Alert, and Policy.' + WHEN valid_category_count > 0 + THEN sett.name || ' logs enabled for ' || valid_categories || ' categories.' + ELSE sett.name || ' logs not enabled for categories Administrative, Security, Alert, and Policy.' + END AS reason + FROM enabled_settings sett, azure_subscription sub - where + WHERE sub.subscription_id = sett.subscription_id; - PrimaryTable: azure_diagnostic_setting - ListOfTables: - - azure_diagnostic_setting - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.2 Ensure Diagnostic Setting captures appropriate categories \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_1_3.yaml b/compliance/controls/azure/azure_cis_v150_5_1_3.yaml old mode 100755 new mode 100644 index 274569b17..22858f00a --- a/compliance/controls/azure/azure_cis_v150_5_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_1_3.yaml @@ -1,34 +1,34 @@ +Description: The storage account container containing the activity log export should not be publicly accessible. ID: azure_cis_v150_5_1_3 -Title: "5.1.3 Ensure the storage container storing the activity logs is not publicly accessible" -Description: "The storage account container containing the activity log export should not be publicly accessible." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc.id as resource, - sc.og_account_id as og_account_id, - sc.og_resource_id as og_resource_id, - case - when public_access != 'None' then 'alarm' - else 'ok' - end as status, - case - when public_access != 'None' - then account_name || ' container insights-operational-logs storing activity logs publicly accessible.' - else account_name || ' container insights-operational-logs storing activity logs not publicly accessible.' - end as reason - from - azure_storage_container sc, - azure_subscription sub - where - name = 'insights-operational-logs' - and sub.subscription_id = sc.subscription_id; - PrimaryTable: azure_storage_container ListOfTables: - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_container + QueryToExecute: | + SELECT + sc.id AS resource, + sc.og_account_id AS og_account_id, + sc.og_resource_id AS og_resource_id, + CASE + WHEN public_access != 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_access != 'None' + THEN account_name || ' container insights-operational-logs storing activity logs publicly accessible.' + ELSE account_name || ' container insights-operational-logs storing activity logs not publicly accessible.' + END AS reason + FROM + azure_storage_container sc, + azure_subscription sub + WHERE + name = 'insights-operational-logs' + AND sub.subscription_id = sc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.3 Ensure the storage container storing the activity logs is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_1_5.yaml b/compliance/controls/azure/azure_cis_v150_5_1_5.yaml old mode 100755 new mode 100644 index 0af235c14..9d31c554e --- a/compliance/controls/azure/azure_cis_v150_5_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_1_5.yaml @@ -1,49 +1,49 @@ +Description: Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available. ID: azure_cis_v150_5_1_5 -Title: "5.1.5 Ensure that logging for Azure KeyVault is 'Enabled'" -Description: "Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with logging_details as ( - select - name as key_vault_name - from + ListOfTables: + - azure_key_vault + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + WITH logging_details AS ( + SELECT + name AS key_vault_name + FROM azure_key_vault, jsonb_array_elements(diagnostic_settings) setting, jsonb_array_elements(setting -> 'properties' -> 'logs') log - where - diagnostic_settings is not null - and setting -> 'properties' ->> 'storageAccountId' <> '' - and (log ->> 'enabled') :: boolean - and log ->> 'category' = 'AuditEvent' - and (log -> 'retentionPolicy') :: JSONB ? 'days' + WHERE + diagnostic_settings IS NOT NULL + AND setting -> 'properties' ->> 'storageAccountId' <> '' + AND (log ->> 'enabled')::boolean + AND log ->> 'category' = 'AuditEvent' + AND (log -> 'retentionPolicy')::JSONB ? 'days' ) - select - v.id as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when v.diagnostic_settings is null then 'alarm' - when l.key_vault_name not like concat('%', v.name, '%') then 'alarm' - else 'ok' - end as status, - case - when v.diagnostic_settings is null then v.name || ' logging not enabled.' - when l.key_vault_name not like concat('%', v.name, '%') then v.name || ' logging not enabled.' - else v.name || ' logging enabled.' - end as reason - from + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason + FROM azure_key_vault v, logging_details l, azure_subscription sub - where + WHERE sub.subscription_id = v.subscription_id; - PrimaryTable: azure_key_vault - ListOfTables: - - azure_key_vault - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.5 Ensure that logging for Azure KeyVault is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_1_6.yaml b/compliance/controls/azure/azure_cis_v150_5_1_6.yaml old mode 100755 new mode 100644 index 58c56c0ee..8f9fcbc81 --- a/compliance/controls/azure/azure_cis_v150_5_1_6.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_1_6.yaml @@ -1,24 +1,24 @@ +Description: Ensure that network flow logs are captured and fed into a central log analytics workspace. ID: azure_cis_v150_5_1_6 -Title: "5.1.6 Ensure that Network Security Group Flow logs are captured and sent to Log Analytics" -Description: "Ensure that network flow logs are captured and fed into a central log analytics workspace." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.6 Ensure that Network Security Group Flow logs are captured and sent to Log Analytics \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_1_7.yaml b/compliance/controls/azure/azure_cis_v150_5_1_7.yaml old mode 100755 new mode 100644 index f8cc57848..42ec787be --- a/compliance/controls/azure/azure_cis_v150_5_1_7.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_1_7.yaml @@ -1,24 +1,24 @@ +Description: Enable AppServiceHTTPLogs diagnostic log category for Azure App Service instances to ensure all http requests are captured and centrally logged. ID: azure_cis_v150_5_1_7 -Title: "5.1.7 Ensure that logging for Azure AppService 'AppServiceHTTPLogs' is enabled." -Description: "Enable AppServiceHTTPLogs diagnostic log category for Azure App Service instances to ensure all http requests are captured and centrally logged." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.7 Ensure that logging for Azure AppService 'AppServiceHTTPLogs' is enabled. \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_2_1.yaml b/compliance/controls/azure/azure_cis_v150_5_2_1.yaml old mode 100755 new mode 100644 index a540f12d1..45dc6df28 --- a/compliance/controls/azure/azure_cis_v150_5_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_2_1.yaml @@ -1,53 +1,53 @@ +Description: Create an activity log alert for the Create Policy Assignment event. ID: azure_cis_v150_5_2_1 -Title: "5.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment" -Description: "Create an activity log alert for the Create Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' - limit 1 + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' + LIMIT 1 ) - select - a.subscription_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create policy assignment event.' - else 'Activity log alert does not exists for create policy assignment event.' - end as reason - from + SELECT + a.subscription_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create policy assignment event.' + ELSE 'Activity log alert does not exist for create policy assignment event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY a.subscription_id, sub.subscription_id, sub._ctx, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_2_10.yaml b/compliance/controls/azure/azure_cis_v150_5_2_10.yaml old mode 100755 new mode 100644 index fd3411cf2..f0a7a4c78 --- a/compliance/controls/azure/azure_cis_v150_5_2_10.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_2_10.yaml @@ -1,62 +1,58 @@ +Description: Create an activity log alert for the Delete Public IP Address rule. ID: azure_cis_v150_5_2_10 -Title: "5.2.10 Ensure that Activity Log Alert exists for Delete Public IP Address rule" -Description: "Create an activity log alert for the Delete Public IP Address rule." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/delete"}]' - ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - ) + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/delete"}]') + OR + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Delete Public IP Address rule.' - else 'Activity Log Alert does not exists for Delete Public IP Address rule.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Delete Public IP Address rule.' + ELSE 'Activity Log Alert does not exist for Delete Public IP Address rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.10 Ensure that Activity Log Alert exists for Delete Public IP Address rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_2_2.yaml b/compliance/controls/azure/azure_cis_v150_5_2_2.yaml old mode 100755 new mode 100644 index 9d8777d39..fb1705743 --- a/compliance/controls/azure/azure_cis_v150_5_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_2_2.yaml @@ -1,52 +1,52 @@ +Description: Create an activity log alert for the Delete Policy Assignment event. ID: azure_cis_v150_5_2_2 -Title: "5.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment" -Description: "Create an activity log alert for the Delete Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/delete"}]' - limit 1 + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/delete"}]' + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete policy assignment event.' - else 'Activity log alert does not exists for delete policy assignment event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete policy assignment event.' + ELSE 'Activity log alert does not exist for delete policy assignment event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_2_3.yaml b/compliance/controls/azure/azure_cis_v150_5_2_3.yaml old mode 100755 new mode 100644 index 3146c3b2d..dab11913a --- a/compliance/controls/azure/azure_cis_v150_5_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_2_3.yaml @@ -1,62 +1,62 @@ +Description: Create an Activity Log Alert for the Create or Update Network Security Group event. ID: azure_cis_v150_5_2_3 -Title: "5.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group" -Description: "Create an Activity Log Alert for the Create or Update Network Security Group event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Network Security Group event.' - else 'Activity log alert does not exists for create or update Network Security Group event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Network Security Group event.' + ELSE 'Activity log alert does not exist for create or update Network Security Group event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_2_4.yaml b/compliance/controls/azure/azure_cis_v150_5_2_4.yaml old mode 100755 new mode 100644 index e60a87950..f031a6347 --- a/compliance/controls/azure/azure_cis_v150_5_2_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_2_4.yaml @@ -1,63 +1,63 @@ +Description: Create an activity log alert for the Delete Network Security Group event. ID: azure_cis_v150_5_2_4 -Title: "5.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group" -Description: "Create an activity log alert for the Delete Network Security Group event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id, jsonb_array_length(alert.condition -> 'allOf') - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' - ) - or + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' + ) + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Network Security Group event.' - else 'Activity log alert does not exists for delete Network Security Group event.' - end as reason - from - azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by - sub._ctx, - sub.subscription_id, - sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Network Security Group event.' + ELSE 'Activity log alert does not exist for delete Network Security Group event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_2_5.yaml b/compliance/controls/azure/azure_cis_v150_5_2_5.yaml old mode 100755 new mode 100644 index 6b0fa4edf..3f4cd11d5 --- a/compliance/controls/azure/azure_cis_v150_5_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_2_5.yaml @@ -1,62 +1,62 @@ +Description: Create an activity log alert for the Create or Update Security Solution event. ID: azure_cis_v150_5_2_5 -Title: "5.2.5 Ensure that Activity Log Alert exists for Create or Update Security Solution" -Description: "Create an activity log alert for the Create or Update Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field":"operationName", "equals": "Microsoft.Security/securitySolutions/write"}]' + AND alert.condition -> 'allOf' @> '[{"field":"operationName", "equals": "Microsoft.Security/securitySolutions/write"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Security Solution event.' - else 'Activity log alert does not exists for create or update Security Solution event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Security Solution event.' + ELSE 'Activity log alert does not exist for create or update Security Solution event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.5 Ensure that Activity Log Alert exists for Create or Update Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_2_6.yaml b/compliance/controls/azure/azure_cis_v150_5_2_6.yaml old mode 100755 new mode 100644 index b5ef7d140..e0fa4e106 --- a/compliance/controls/azure/azure_cis_v150_5_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_2_6.yaml @@ -1,15 +1,62 @@ +Description: Create an activity log alert for the Delete Security Solution event. ID: azure_cis_v150_5_2_6 -Title: "5.2.6 Ensure that Activity Log Alert exists for Delete Security Solution" -Description: "Create an activity log alert for the Delete Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and (\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Security\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Security/securitySolutions/delete\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Security\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.security/securitysolutions\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Security Solution event.'\n else 'Activity log alert does not exists for delete Security Solution event.'\n end as reason\n \nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub._ctx,\n sub.subscription_id,\n sub.display_name;" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/delete"}]' + ) + OR + ( + alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Security Solution event.' + ELSE 'Activity log alert does not exists for delete Security Solution event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.6 Ensure that Activity Log Alert exists for Delete Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_2_7.yaml b/compliance/controls/azure/azure_cis_v150_5_2_7.yaml old mode 100755 new mode 100644 index f73a1ec19..870a6a693 --- a/compliance/controls/azure/azure_cis_v150_5_2_7.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_2_7.yaml @@ -1,63 +1,59 @@ +Description: Create an activity log alert for the Create or Update SQL Server Firewall Rule event. ID: azure_cis_v150_5_2_7 -Title: "5.2.7 Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule" -Description: "Create an activity log alert for the Create or Update SQL Server Firewall Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as - ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/write"}]' - ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - ) + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/write"}]') + OR + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Create or Update SQL Server Firewall Rule.' - else 'Activity Log Alert does not exists for Create or Update SQL Server Firewall Rule.' - end as reason - from + + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Create or Update SQL Server Firewall Rule.' + ELSE 'Activity Log Alert does not exist for Create or Update SQL Server Firewall Rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.7 Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_2_8.yaml b/compliance/controls/azure/azure_cis_v150_5_2_8.yaml old mode 100755 new mode 100644 index 802822202..e93322b40 --- a/compliance/controls/azure/azure_cis_v150_5_2_8.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_2_8.yaml @@ -1,61 +1,58 @@ +Description: Create an activity log alert for the 'Delete SQL Server Firewall Rule.' ID: azure_cis_v150_5_2_8 -Title: "5.2.8 Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule" -Description: "Create an activity log alert for the 'Delete SQL Server Firewall Rule.'" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/delete"}]' ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - ) + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/delete"}]') + OR + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Delete SQL Server Firewall Rule.' - else 'Activity Log Alert does not exists for Delete SQL Server Firewall Rule.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Delete SQL Server Firewall Rule.' + ELSE 'Activity Log Alert does not exist for Delete SQL Server Firewall Rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.8 Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_2_9.yaml b/compliance/controls/azure/azure_cis_v150_5_2_9.yaml old mode 100755 new mode 100644 index a84c9aa8b..5a4ebd80b --- a/compliance/controls/azure/azure_cis_v150_5_2_9.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_2_9.yaml @@ -1,65 +1,61 @@ +Description: Create an activity log alert for the Create or Update Public IP Addresses rule. ID: azure_cis_v150_5_2_9 -Title: "5.2.9 Ensure that Activity Log Alert exists for Create or Update Public IP Address rule" -Description: "Create an activity log alert for the Create or Update Public IP Addresses rule." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with alert_rule as - ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/write"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/write"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Create or Update Public IP Address rule.' - else 'Activity Log Alert does not exists for Create or Update Public IP Address rule.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Create or Update Public IP Address rule.' + ELSE 'Activity Log Alert does not exist for Create or Update Public IP Address rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name; - ``` - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.9 Ensure that Activity Log Alert exists for Create or Update Public IP Address rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_5_3.yaml b/compliance/controls/azure/azure_cis_v150_5_3.yaml old mode 100755 new mode 100644 index f871cba65..f8b9d66b4 --- a/compliance/controls/azure/azure_cis_v150_5_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_5_3.yaml @@ -1,24 +1,24 @@ +Description: Resource Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself; for example, reading or updating a secret from a Key Vault. ID: azure_cis_v150_5_3 -Title: "5.3 Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it" -Description: "Resource Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself; for example, reading or updating a secret from a Key Vault." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.3 Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_6_1.yaml b/compliance/controls/azure/azure_cis_v150_6_1.yaml old mode 100755 new mode 100644 index 0cd2a139c..4c1b5f99b --- a/compliance/controls/azure/azure_cis_v150_6_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_6_1.yaml @@ -1,54 +1,54 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required. ID: azure_cis_v150_6_1 -Title: "6.1 Ensure that RDP from the internet access is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('3389', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 3389 - and split_part(dport, '-', 2) :: integer >= 3389 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('3389', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::integer <= 3389 + AND split_part(dport, '-', 2)::integer >= 3389 ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts RDP access from internet.' - else sg.title || ' allows RDP access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts RDP access from internet.' + ELSE sg.title || ' allows RDP access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.1 Ensure that RDP from the internet access is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_6_2.yaml b/compliance/controls/azure/azure_cis_v150_6_2.yaml old mode 100755 new mode 100644 index 46b96f668..262ce8932 --- a/compliance/controls/azure/azure_cis_v150_6_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_6_2.yaml @@ -1,54 +1,54 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required. ID: azure_cis_v150_6_2 -Title: "6.2 Ensure that SSH access from the internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('22', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 22 - and split_part(dport, '-', 2) :: integer >= 22 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('22', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::integer <= 22 + AND split_part(dport, '-', 2)::integer >= 22 ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts SSH access from internet.' - else sg.title || ' allows SSH access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts SSH access from internet.' + ELSE sg.title || ' allows SSH access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.2 Ensure that SSH access from the internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_6_3.yaml b/compliance/controls/azure/azure_cis_v150_6_3.yaml old mode 100755 new mode 100644 index cf0dc2670..8f6d05587 --- a/compliance/controls/azure/azure_cis_v150_6_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_6_3.yaml @@ -1,59 +1,59 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required. ID: azure_cis_v150_6_3 -Title: "6.3 Ensure that UDP access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and sg -> 'properties' ->> 'protocol' = 'UDP' - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' = 'UDP' + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( dport = '*' - or ( - dport like '%-%' - and ( - 53 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 123 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 161 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 389 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 1900 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer + OR ( + dport LIKE '%-%' + AND ( + 53 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 123 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 161 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 389 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 1900 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts UDP services from internet.' - else sg.title || ' allows UDP services from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts UDP services from internet.' + ELSE sg.title || ' allows UDP services from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.3 Ensure that UDP access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_6_4.yaml b/compliance/controls/azure/azure_cis_v150_6_4.yaml old mode 100755 new mode 100644 index cb5dfb8f3..e9c681ebf --- a/compliance/controls/azure/azure_cis_v150_6_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_6_4.yaml @@ -1,23 +1,28 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured. ID: azure_cis_v150_6_4 -Title: "6.4 Ensure that HTTP(S) access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select distinct - name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT DISTINCT + name AS sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and sg -> 'properties' ->> 'protocol' ilike 'TCP' - and sip in - ( + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' ILIKE 'TCP' + AND sip IN ( '*', '0.0.0.0', '0.0.0.0/0', @@ -26,43 +31,31 @@ Query: '/0', '/0' ) - and - ( - dport in - ( - '80', - '*' - ) - or - ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 80 - and split_part(dport, '-', 2) :: integer >= 80 + AND ( + dport IN ('80', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::integer <= 80 + AND split_part(dport, '-', 2)::integer >= 80 ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts HTTPS access from internet.' - else sg.title || ' allows HTTPS access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts HTTPS access from internet.' + ELSE sg.title || ' allows HTTPS access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.4 Ensure that HTTP(S) access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_7_1.yaml b/compliance/controls/azure/azure_cis_v150_7_1.yaml old mode 100755 new mode 100644 index 311c8ff1e..5c99bc85f --- a/compliance/controls/azure/azure_cis_v150_7_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_7_1.yaml @@ -1,32 +1,32 @@ +Description: Migrate BLOB based VHD's to Managed Disks on Virtual Machines to exploit the default features of this configuration. ID: azure_cis_v150_7_1 -Title: "7.1 Ensure Virtual Machines are utilizing Managed Disks" -Description: "Migrate BLOB based VHD's to Managed Disks on Virtual Machines to exploit the default features of this configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - vm.id as resource, - vm.og_account_id as og_account_id, - vm.og_resource_id as og_resource_id, - case - when managed_disk_id is null then 'alarm' - else 'ok' - end as status, - case - when managed_disk_id is null then vm.name || ' VM not utilizing managed disks.' - else vm.name || ' VM utilizing managed disks.' - end as reason - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where - sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN managed_disk_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN managed_disk_id IS NULL THEN vm.name || ' VM not utilizing managed disks.' + ELSE vm.name || ' VM utilizing managed disks.' + END AS reason + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.1 Ensure Virtual Machines are utilizing Managed Disks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_7_2.yaml b/compliance/controls/azure/azure_cis_v150_7_2.yaml old mode 100755 new mode 100644 index 5ef4e9906..12ed91ac2 --- a/compliance/controls/azure/azure_cis_v150_7_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_7_2.yaml @@ -1,33 +1,33 @@ +Description: Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE or Server Side Encryption(SSE). ID: azure_cis_v150_7_2 -Title: "7.2 Ensure that 'OS and Data' disks are encrypted with Customer Managed Key (CMK)" -Description: "Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE or Server Side Encryption(SSE)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.' - else disk.name || ' not encrypted with CMK.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state = 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state = 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.2 Ensure that 'OS and Data' disks are encrypted with Customer Managed Key (CMK) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_7_3.yaml b/compliance/controls/azure/azure_cis_v150_7_3.yaml old mode 100755 new mode 100644 index 03c5208f9..0cffa4cd6 --- a/compliance/controls/azure/azure_cis_v150_7_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_7_3.yaml @@ -1,33 +1,33 @@ +Description: Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK). ID: azure_cis_v150_7_3 -Title: "7.3 Ensure that 'Unattached disks' are encrypted with CMK" -Description: "Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.' - else disk.name || ' not encrypted with CMK.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state != 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state != 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.3 Ensure that 'Unattached disks' are encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_7_4.yaml b/compliance/controls/azure/azure_cis_v150_7_4.yaml old mode 100755 new mode 100644 index d40067831..02500a340 --- a/compliance/controls/azure/azure_cis_v150_7_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_7_4.yaml @@ -1,24 +1,24 @@ +Description: For added security only install organization-approved extensions on VMs. ID: azure_cis_v150_7_4 -Title: "7.4 Ensure that only approved extensions are installed" -Description: "For added security only install organization-approved extensions on VMs." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.4 Ensure that only approved extensions are installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_7_5.yaml b/compliance/controls/azure/azure_cis_v150_7_5.yaml old mode 100755 new mode 100644 index 16c1963da..0724cafa3 --- a/compliance/controls/azure/azure_cis_v150_7_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_7_5.yaml @@ -1,24 +1,24 @@ +Description: Install endpoint protection for all virtual machines. ID: azure_cis_v150_7_5 -Title: "7.5 Ensure that the endpoint protection for all Virtual Machines is installed" -Description: "Install endpoint protection for all virtual machines." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.5 Ensure that the endpoint protection for all Virtual Machines is installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_7_6.yaml b/compliance/controls/azure/azure_cis_v150_7_6.yaml old mode 100755 new mode 100644 index 8b0ccd13a..b27d75609 --- a/compliance/controls/azure/azure_cis_v150_7_6.yaml +++ b/compliance/controls/azure/azure_cis_v150_7_6.yaml @@ -1,24 +1,24 @@ +Description: VHD (Virtual Hard Disks) are stored in blob storage and are the old-style disks that were attached to Virtual Machines. The blob VHD was then leased to the VM. By default, storage accounts are not encrypted, and Microsoft Defender will then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK. This should be turned on for storage accounts containing VHDs. ID: azure_cis_v150_7_6 -Title: "7.6 Ensure that VHD's are encrypted" -Description: "VHD (Virtual Hard Disks) are stored in blob storage and are the old-style disks that were attached to Virtual Machines. The blob VHD was then leased to the VM. By default, storage accounts are not encrypted, and Microsoft Defender will then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK. This should be turned on for storage accounts containing VHDs." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.6 Ensure that VHD's are encrypted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_8_1.yaml b/compliance/controls/azure/azure_cis_v150_8_1.yaml old mode 100755 new mode 100644 index 9e0a5c47a..ee10f4eb6 --- a/compliance/controls/azure/azure_cis_v150_8_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_8_1.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set. ID: azure_cis_v150_8_1 -Title: "8.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults" -Description: "Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_key + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + WITH rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where enable_rbac_authorization + WHERE + enable_rbac_authorization ) - select - kvk.id as resource, - kvk.og_account_id as og_account_id, - kvk.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvk.name || - case - when v.name is null then ' not RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' not RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_key kvk - left join rbac_vault as v on v.name = kvk.vault_name, + LEFT JOIN rbac_vault AS v ON v.name = kvk.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvk.subscription_id; - PrimaryTable: azure_key_vault_key - ListOfTables: - - azure_key_vault - - azure_key_vault_key - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_8_2.yaml b/compliance/controls/azure/azure_cis_v150_8_2.yaml old mode 100755 new mode 100644 index 9d56aa112..5d08afb7d --- a/compliance/controls/azure/azure_cis_v150_8_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_8_2.yaml @@ -1,45 +1,47 @@ +Description: Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set. ID: azure_cis_v150_8_2 -Title: "8.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults" -Description: "Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with non_rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_key + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + WITH non_rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where not enable_rbac_authorization + WHERE + NOT enable_rbac_authorization ) - select - kvk.id as resource, - kvk.og_account_id as og_account_id, - kvk.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvk.name || - case - when v.name is null then ' RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_key kvk - left join non_rbac_vault as v on v.name = kvk.vault_name, + LEFT JOIN non_rbac_vault AS v ON v.name = kvk.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvk.subscription_id; - PrimaryTable: azure_key_vault_key - ListOfTables: - - azure_key_vault - - azure_key_vault_key - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_8_3.yaml b/compliance/controls/azure/azure_cis_v150_8_3.yaml old mode 100755 new mode 100644 index ab9f498a9..01da7159e --- a/compliance/controls/azure/azure_cis_v150_8_3.yaml +++ b/compliance/controls/azure/azure_cis_v150_8_3.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set. ID: azure_cis_v150_8_3 -Title: "8.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults" -Description: "Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_secret + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + WITH rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where enable_rbac_authorization + WHERE + enable_rbac_authorization ) - select - kvs.id as resource, - kvs.og_account_id as og_account_id, - kvs.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvs.name || - case - when v.name is null then ' not RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' not RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_secret kvs - left join rbac_vault as v on v.name = kvs.vault_name, + LEFT JOIN rbac_vault AS v ON v.name = kvs.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvs.subscription_id; - PrimaryTable: azure_key_vault_secret - ListOfTables: - - azure_key_vault - - azure_key_vault_secret - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_8_4.yaml b/compliance/controls/azure/azure_cis_v150_8_4.yaml old mode 100755 new mode 100644 index bcce67b7c..5a5a51386 --- a/compliance/controls/azure/azure_cis_v150_8_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_8_4.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set. ID: azure_cis_v150_8_4 -Title: "8.4 Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults" -Description: "Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with non_rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_secret + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + WITH non_rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where not enable_rbac_authorization + WHERE + NOT enable_rbac_authorization ) - select - kvs.id as resource, - kvs.og_account_id as og_account_id, - kvs.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvs.name || - case - when v.name is null then ' RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_secret kvs - left join non_rbac_vault as v on v.name = kvs.vault_name, + LEFT JOIN non_rbac_vault AS v ON v.name = kvs.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvs.subscription_id; - PrimaryTable: azure_key_vault_secret - ListOfTables: - - azure_key_vault - - azure_key_vault_secret - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.4 Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_8_5.yaml b/compliance/controls/azure/azure_cis_v150_8_5.yaml old mode 100755 new mode 100644 index 65da8f4ff..a3f2b06fc --- a/compliance/controls/azure/azure_cis_v150_8_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_8_5.yaml @@ -1,34 +1,37 @@ +Description: The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the "Do Not Purge" and "Soft Delete" functions. ID: azure_cis_v150_8_5 -Title: "8.5 Ensure the key vault is recoverable" -Description: "The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the \\\"Do Not Purge\\\" and \\\"Soft Delete\\\" functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when soft_delete_enabled and purge_protection_enabled then 'ok' - else 'alarm' - end as status, - case - when not soft_delete_enabled and not purge_protection_enabled then name || ' "soft delete" and "do not purge" not enabled.' - when not soft_delete_enabled then name || ' "soft delete" not enabled.' - when not purge_protection_enabled then name || ' "do not purge" not enabled.' - else name || ' "soft delete" and "do not purge" enabled.' - end as reason - from - azure_key_vault kv, - azure_subscription sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN soft_delete_enabled AND purge_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT soft_delete_enabled AND NOT purge_protection_enabled + THEN name || ' "soft delete" and "do not purge" not enabled.' + WHEN NOT soft_delete_enabled + THEN name || ' "soft delete" not enabled.' + WHEN NOT purge_protection_enabled + THEN name || ' "do not purge" not enabled.' + ELSE name || ' "soft delete" and "do not purge" enabled.' + END AS reason + FROM + azure_key_vault kv, + azure_subscription sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.5 Ensure the key vault is recoverable \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_8_6.yaml b/compliance/controls/azure/azure_cis_v150_8_6.yaml old mode 100755 new mode 100644 index 8964626ed..30d216fb3 --- a/compliance/controls/azure/azure_cis_v150_8_6.yaml +++ b/compliance/controls/azure/azure_cis_v150_8_6.yaml @@ -1,32 +1,32 @@ +Description: Role assignments disappear when a Key Vault has been deleted (soft-delete) and recovered. Afterwards it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services. ID: azure_cis_v150_8_6 -Title: "8.6 Enable Role Based Access Control for Azure Key Vault" -Description: "Role assignments disappear when a Key Vault has been deleted (soft- delete) and recovered. Afterwards it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when enable_rbac_authorization then 'ok' - else 'alarm' - end as status, - case - when enable_rbac_authorization then name || ' has RBAC enabled.' - else name || ' have RBAC disabled.' - end as reason - from - azure_key_vault as kv, - azure_subscription as sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN enable_rbac_authorization THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_rbac_authorization THEN name || ' has RBAC enabled.' + ELSE name || ' have RBAC disabled.' + END AS reason + FROM + azure_key_vault AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.6 Enable Role Based Access Control for Azure Key Vault \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_8_8.yaml b/compliance/controls/azure/azure_cis_v150_8_8.yaml old mode 100755 new mode 100644 index 11edb8c70..18e5ab3ef --- a/compliance/controls/azure/azure_cis_v150_8_8.yaml +++ b/compliance/controls/azure/azure_cis_v150_8_8.yaml @@ -1,24 +1,24 @@ +Description: Automatic Key Rotation is available in Public Preview. The currently supported applications are Key Vault, Managed Disks, and Storage accounts accessing keys within Key Vault. The number of supported applications will incrementally increase. ID: azure_cis_v150_8_8 -Title: "8.8 Ensure Automatic Key Rotation is Enabled Within Azure Key Vault for the Supported Services" -Description: "Automatic Key Rotation is available in Public Preview. The currently supported applications are Key Vault, Managed Disks, and Storage accounts accessing keys within Key Vault. The number of supported applications will incrementally increased." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 8.8 Ensure Automatic Key Rotation is Enabled Within Azure Key Vault for the Supported Services \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_9_1.yaml b/compliance/controls/azure/azure_cis_v150_9_1.yaml old mode 100755 new mode 100644 index db94e4c6d..14b75f2b8 --- a/compliance/controls/azure/azure_cis_v150_9_1.yaml +++ b/compliance/controls/azure/azure_cis_v150_9_1.yaml @@ -1,32 +1,32 @@ +Description: Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching the API app, or authenticate those that have tokens before they reach the API app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented. ID: azure_cis_v150_9_1 -Title: "9.1 Ensure App Service Authentication is set up for apps in Azure App Service" -Description: "Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching the API app, or authenticate those that have tokens before they reach the API app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then name || ' authentication not set.' - else name || ' authentication set.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::BOOLEAN THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::BOOLEAN THEN name || ' authentication not set.' + ELSE name || ' authentication set.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.1 Ensure App Service Authentication is set up for apps in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_9_11.yaml b/compliance/controls/azure/azure_cis_v150_9_11.yaml old mode 100755 new mode 100644 index 2b8a6245a..2c41a1d1c --- a/compliance/controls/azure/azure_cis_v150_9_11.yaml +++ b/compliance/controls/azure/azure_cis_v150_9_11.yaml @@ -1,24 +1,24 @@ +Description: Encryption keys, Certificate thumbprints and Managed Identity Credentials can be coded into the APP service, this renders them visible as part of the configuration. To maintain security of these keys, it is better to store them in an Azure Keyvault and reference them from the Keyvault. ID: azure_cis_v150_9_11 -Title: "9.11 Ensure Azure Keyvaults are used to store secrets" -Description: "Encryption keys, Certificate thumbprints and Managed Identity Credentials can be coded into the APP service, this renders them visible as part of the configuration, to maintain security of these keys it is better to store in an Azure Keyvault and reference them from the Keyvault." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.11 Ensure Azure Keyvaults are used to store secrets \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_9_2.yaml b/compliance/controls/azure/azure_cis_v150_9_2.yaml old mode 100755 new mode 100644 index 1bd7a335a..c3730c2a9 --- a/compliance/controls/azure/azure_cis_v150_9_2.yaml +++ b/compliance/controls/azure/azure_cis_v150_9_2.yaml @@ -1,32 +1,32 @@ +Description: Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic. ID: azure_cis_v150_9_2 -Title: "9.2 Ensure web app redirects all HTTP traffic to HTTPS in Azure App Service" -Description: "Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not https_only then 'alarm' - else 'ok' - end as status, - case - when not https_only then name || ' does not redirect all HTTP traffic to HTTPS.' - else name || ' redirects all HTTP traffic to HTTPS.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT https_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT https_only THEN name || ' does not redirect all HTTP traffic to HTTPS.' + ELSE name || ' redirects all HTTP traffic to HTTPS.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.2 Ensure web app redirects all HTTP traffic to HTTPS in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_9_4.yaml b/compliance/controls/azure/azure_cis_v150_9_4.yaml old mode 100755 new mode 100644 index fe7686852..b3c2f38e9 --- a/compliance/controls/azure/azure_cis_v150_9_4.yaml +++ b/compliance/controls/azure/azure_cis_v150_9_4.yaml @@ -1,32 +1,32 @@ +Description: Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app. ID: azure_cis_v150_9_4 -Title: "9.4 Ensure the web app has 'Client Certificates (Incoming client certificates)' set to 'On'" -Description: "Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not client_cert_enabled then 'alarm' - else 'ok' - end as status, - case - when not client_cert_enabled then name || ' incoming client certificates set to off.' - else name || ' incoming client certificates set to on.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT client_cert_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT client_cert_enabled THEN name || ' incoming client certificates set to off.' + ELSE name || ' incoming client certificates set to on.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.4 Ensure the web app has 'Client Certificates (Incoming client certificates)' set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_9_5.yaml b/compliance/controls/azure/azure_cis_v150_9_5.yaml old mode 100755 new mode 100644 index 1fe4f6b4b..25361d0ee --- a/compliance/controls/azure/azure_cis_v150_9_5.yaml +++ b/compliance/controls/azure/azure_cis_v150_9_5.yaml @@ -1,32 +1,32 @@ +Description: Managed service identity in App Service makes the app more secure by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in the app service, the app will connect to other Azure services securely without the need of username and passwords. ID: azure_cis_v150_9_5 -Title: "9.5 Ensure that Register with Azure Active Directory is enabled on App Service" -Description: "Managed service identity in App Service makes the app more secure by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in the app service, the app will connect to other Azure services securely without the need of username and passwords." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when identity = '{}' then 'alarm' - else 'ok' - end as status, - case - when identity = '{}' then name || ' register with azure active directory disabled.' - else name || ' register with azure active directory enabled.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN identity = '{}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity = '{}' THEN name || ' register with Azure Active Directory disabled.' + ELSE name || ' register with Azure Active Directory enabled.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.5 Ensure that Register with Azure Active Directory is enabled on App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_9_6.yaml b/compliance/controls/azure/azure_cis_v150_9_6.yaml old mode 100755 new mode 100644 index acbe74103..ebb5df845 --- a/compliance/controls/azure/azure_cis_v150_9_6.yaml +++ b/compliance/controls/azure/azure_cis_v150_9_6.yaml @@ -1,24 +1,24 @@ +Description: Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version. ID: azure_cis_v150_9_6 -Title: "9.6 Ensure that 'PHP version' is the latest, if used to run the web app" -Description: "Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.6 Ensure that 'PHP version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_9_7.yaml b/compliance/controls/azure/azure_cis_v150_9_7.yaml old mode 100755 new mode 100644 index 951a6ed04..ff05cbc2d --- a/compliance/controls/azure/azure_cis_v150_9_7.yaml +++ b/compliance/controls/azure/azure_cis_v150_9_7.yaml @@ -1,24 +1,24 @@ +Description: Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version. ID: azure_cis_v150_9_7 -Title: "9.7 Ensure that 'Python version' is the latest stable version, if used to run the web app" -Description: "Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.7 Ensure that 'Python version' is the latest stable version, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_9_8.yaml b/compliance/controls/azure/azure_cis_v150_9_8.yaml old mode 100755 new mode 100644 index e0fc48339..43227e861 --- a/compliance/controls/azure/azure_cis_v150_9_8.yaml +++ b/compliance/controls/azure/azure_cis_v150_9_8.yaml @@ -1,24 +1,24 @@ +Description: Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version. ID: azure_cis_v150_9_8 -Title: "9.8 Ensure that 'Java version' is the latest, if used to run the web app" -Description: "Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.8 Ensure that 'Java version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v150_9_9.yaml b/compliance/controls/azure/azure_cis_v150_9_9.yaml old mode 100755 new mode 100644 index 314b96601..aaa149aa5 --- a/compliance/controls/azure/azure_cis_v150_9_9.yaml +++ b/compliance/controls/azure/azure_cis_v150_9_9.yaml @@ -1,32 +1,32 @@ +Description: Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version. ID: azure_cis_v150_9_9 -Title: "9.9 Ensure that 'HTTP Version' is the latest, if used to run the web app" -Description: "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then name || ' HTTP version not latest.' - else name || ' HTTP version is latest.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::boolean THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::boolean THEN name || ' HTTP version not latest.' + ELSE name || ' HTTP version is latest.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.9 Ensure that 'HTTP Version' is the latest, if used to run the web app \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_10_1.yaml b/compliance/controls/azure/azure_cis_v200_10_1.yaml old mode 100755 new mode 100644 index a71b8a59b..10bb7b896 --- a/compliance/controls/azure/azure_cis_v200_10_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_10_1.yaml @@ -1,24 +1,24 @@ +Description: Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. ID: azure_cis_v200_10_1 -Title: "10.1 Ensure that Resource Locks are set for Mission-Critical Azure Resources" -Description: "Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 10.1 Ensure that Resource Locks are set for Mission-Critical Azure Resources \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_10.yaml b/compliance/controls/azure/azure_cis_v200_1_10.yaml old mode 100755 new mode 100644 index e46ca768f..8325f0a88 --- a/compliance/controls/azure/azure_cis_v200_1_10.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_10.yaml @@ -1,19 +1,19 @@ +Description: Ensure that all Global Administrators are notified if any other administrator resets their password. ID: azure_cis_v200_1_10 -Title: "1.10 Ensure That 'Notify all admins when other admins reset their password?' is set to 'Yes'" -Description: "Ensure that all Global Administrators are notified if any other administrator resets their password." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.10 Ensure That 'Notify all admins when other admins reset their password?' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_12.yaml b/compliance/controls/azure/azure_cis_v200_1_12.yaml old mode 100755 new mode 100644 index 18f6d9a6d..8b645b021 --- a/compliance/controls/azure/azure_cis_v200_1_12.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_12.yaml @@ -1,19 +1,19 @@ +Description: Allow users to provide consent for selected permissions when a request is coming from a verified publisher. ID: azure_cis_v200_1_12 -Title: "1.12 Ensure 'User consent for applications' Is Set To 'Allow for Verified Publishers'" -Description: "Allow users to provide consent for selected permissions when a request is coming from a verified publisher." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.12 Ensure 'User consent for applications' Is Set To 'Allow for Verified Publishers' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_13.yaml b/compliance/controls/azure/azure_cis_v200_1_13.yaml old mode 100755 new mode 100644 index f581d2cb1..db0d2b4a6 --- a/compliance/controls/azure/azure_cis_v200_1_13.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_13.yaml @@ -1,19 +1,19 @@ +Description: Require administrators to provide consent for the apps before use. ID: azure_cis_v200_1_13 -Title: "1.13 Ensure that 'Users can add gallery apps to My Apps' is set to 'No'" -Description: "Require administrators to provide consent for the apps before use." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.13 Ensure that 'Users can add gallery apps to My Apps' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_14.yaml b/compliance/controls/azure/azure_cis_v200_1_14.yaml old mode 100755 new mode 100644 index 40d998045..d3037d202 --- a/compliance/controls/azure/azure_cis_v200_1_14.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_14.yaml @@ -1,39 +1,39 @@ +Description: Require administrators or appropriately delegated users to register third-party applications. ID: azure_cis_v200_1_14 -Title: "1.14 Ensure That 'Users Can Register Applications' Is Set to 'No'" -Description: "Require administrators or appropriately delegated users to register third-party applications." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_authorization_policy + Parameters: [] + PrimaryTable: azuread_authorization_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' then 'ok' - else 'alarm' - end as status, - case - when a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' then a.display_name || ' does not allow user to register applications.' - else a.display_name || ' allows user to register applications.' - end as reason, + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' THEN a.display_name || ' does not allow user to register applications.' + ELSE a.display_name || ' allows user to register applications.' + END AS reason, t.tenant_id - from - distinct_tenant as t, - azuread_authorization_policy as a; - PrimaryTable: azuread_authorization_policy - ListOfTables: - - azure_tenant - - azuread_authorization_policy - Parameters: [] + FROM + distinct_tenant AS t, + azuread_authorization_policy AS a; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.14 Ensure That 'Users Can Register Applications' Is Set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_15.yaml b/compliance/controls/azure/azure_cis_v200_1_15.yaml old mode 100755 new mode 100644 index e46ca6a42..b842de9fb --- a/compliance/controls/azure/azure_cis_v200_1_15.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_15.yaml @@ -1,19 +1,19 @@ +Description: Limit guest user permissions. ID: azure_cis_v200_1_15 -Title: "1.15 Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects'" -Description: "Limit guest user permissions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.15 Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_16.yaml b/compliance/controls/azure/azure_cis_v200_1_16.yaml old mode 100755 new mode 100644 index 99d6026e9..a7788bc30 --- a/compliance/controls/azure/azure_cis_v200_1_16.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_16.yaml @@ -1,19 +1,19 @@ +Description: Restrict invitations to users with specific administrative roles only. ID: azure_cis_v200_1_16 -Title: "1.16 Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users'" -Description: "Restrict invitations to users with specific administrative roles only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.16 Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_17.yaml b/compliance/controls/azure/azure_cis_v200_1_17.yaml old mode 100755 new mode 100644 index 04273b3a6..0a936f7f0 --- a/compliance/controls/azure/azure_cis_v200_1_17.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_17.yaml @@ -1,19 +1,19 @@ +Description: Restrict access to the Azure AD administration portal to administrators only. ID: azure_cis_v200_1_17 -Title: "1.17 Ensure That 'Restrict access to Azure AD administration portal' is Set to 'Yes'" -Description: "Restrict access to the Azure AD administration portal to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.17 Ensure That 'Restrict access to Azure AD administration portal' is Set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_18.yaml b/compliance/controls/azure/azure_cis_v200_1_18.yaml old mode 100755 new mode 100644 index 5ee99346d..30c53591d --- a/compliance/controls/azure/azure_cis_v200_1_18.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_18.yaml @@ -1,19 +1,19 @@ +Description: Restricts group creation to administrators with permissions only. ID: azure_cis_v200_1_18 -Title: "1.18 Ensure that 'Restrict user ability to access groups features in the Access Pane' is Set to 'Yes'" -Description: "Restricts group creation to administrators with permissions only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.18 Ensure that 'Restrict user ability to access groups features in the Access Pane' is Set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_19.yaml b/compliance/controls/azure/azure_cis_v200_1_19.yaml old mode 100755 new mode 100644 index 47174b617..26edb6ffd --- a/compliance/controls/azure/azure_cis_v200_1_19.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_19.yaml @@ -1,15 +1,39 @@ +Description: Restrict security group creation to administrators only. ID: azure_cis_v200_1_19 -Title: "1.19 Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No'" -Description: "Restrict security group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with distinct_tenant as (\n select\n distinct tenant_id,\n subscription_id,\n _ctx\n from\n azure_tenant\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' then a.display_name || ' does not allow user to create security groups.'\n else a.display_name || ' allows user to create security groups.'\n end as reason,\n t.tenant_id \nfrom\n distinct_tenant as t,\n azuread_authorization_policy as a;" - PrimaryTable: azuread_authorization_policy ListOfTables: - azure_tenant - azuread_authorization_policy Parameters: [] + PrimaryTable: azuread_authorization_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT DISTINCT + tenant_id, + subscription_id, + _ctx + FROM + azure_tenant + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' THEN a.display_name || ' does not allow user to create security groups.' + ELSE a.display_name || ' allows user to create security groups.' + END AS reason, + t.tenant_id + FROM + distinct_tenant AS t, + azuread_authorization_policy AS a; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.19 Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_1_1.yaml b/compliance/controls/azure/azure_cis_v200_1_1_1.yaml old mode 100755 new mode 100644 index 301a5b99c..ea90dbcd4 --- a/compliance/controls/azure/azure_cis_v200_1_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_1_1.yaml @@ -1,19 +1,19 @@ +Description: Security defaults in Azure Active Directory (Azure AD) make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks. Security defaults is available to everyone. The goal is to ensure that all organizations have a basic level of security enabled at no extra cost. You may turn on security defaults in the Azure portal. ID: azure_cis_v200_1_1_1 -Title: "1.1.1 Ensure Security Defaults is enabled on Azure Active Directory" -Description: "Security defaults in Azure Active Directory (Azure AD) make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks. Security defaults is available to everyone. The goal is to ensure that all organizations have a basic level of security enabled at no extra cost. You may turn on security defaults in the Azure portal." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.1 Ensure Security Defaults is enabled on Azure Active Directory \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_1_2.yaml b/compliance/controls/azure/azure_cis_v200_1_1_2.yaml old mode 100755 new mode 100644 index 0509ffe49..2bad754c2 --- a/compliance/controls/azure/azure_cis_v200_1_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_1_2.yaml @@ -1,19 +1,19 @@ +Description: Enable multi-factor authentication for all roles, groups, and users that have write access or permissions to Azure resources. ID: azure_cis_v200_1_1_2 -Title: "1.1.2 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Privileged Users" -Description: "Enable multi-factor authentication for all roles, groups, and users that have write access or permissions to Azure resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.2 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Privileged Users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_1_3.yaml b/compliance/controls/azure/azure_cis_v200_1_1_3.yaml old mode 100755 new mode 100644 index 7cdf1534f..256338a24 --- a/compliance/controls/azure/azure_cis_v200_1_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_1_3.yaml @@ -1,19 +1,19 @@ +Description: Enable multi-factor authentication for all non-privileged users. ID: azure_cis_v200_1_1_3 -Title: "1.1.3 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Non-Privileged Users" -Description: "Enable multi-factor authentication for all non-privileged users." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.3 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Non-Privileged Users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_1_4.yaml b/compliance/controls/azure/azure_cis_v200_1_1_4.yaml old mode 100755 new mode 100644 index f913c13d2..0bf957ac3 --- a/compliance/controls/azure/azure_cis_v200_1_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_1_4.yaml @@ -1,19 +1,19 @@ +Description: Do not allow users to remember multi-factor authentication on devices. ID: azure_cis_v200_1_1_4 -Title: "1.1.4 Ensure that 'Allow users to remember multi-factor authentication on devices they trust' is Disabled" -Description: "Do not allow users to remember multi-factor authentication on devices." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.4 Ensure that 'Allow users to remember multi-factor authentication on devices they trust' is Disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_20.yaml b/compliance/controls/azure/azure_cis_v200_1_20.yaml old mode 100755 new mode 100644 index de42aeb12..dd8cf4cb6 --- a/compliance/controls/azure/azure_cis_v200_1_20.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_20.yaml @@ -1,19 +1,19 @@ +Description: Restrict security group management to administrators only. ID: azure_cis_v200_1_20 -Title: "1.20 Ensure that 'Owners can manage group membership requests in the Access Panel' is set to 'No'" -Description: "Restrict security group management to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.20 Ensure that 'Owners can manage group membership requests in the Access Panel' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_21.yaml b/compliance/controls/azure/azure_cis_v200_1_21.yaml old mode 100755 new mode 100644 index 5213f892c..63e623264 --- a/compliance/controls/azure/azure_cis_v200_1_21.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_21.yaml @@ -1,19 +1,19 @@ +Description: Restrict Microsoft 365 group creation to administrators only. ID: azure_cis_v200_1_21 -Title: "1.21 Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No'" -Description: "Restrict Microsoft 365 group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.21 Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_22.yaml b/compliance/controls/azure/azure_cis_v200_1_22.yaml old mode 100755 new mode 100644 index 39e8beb20..00162d379 --- a/compliance/controls/azure/azure_cis_v200_1_22.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_22.yaml @@ -1,19 +1,19 @@ +Description: Joining or registering devices to the active directory should require Multi-factor authentication. ID: azure_cis_v200_1_22 -Title: "1.22 Ensure that 'Require Multi-Factor Authentication to register or join devices with Azure AD' is set to 'Yes'" -Description: "Joining or registering devices to the active directory should require Multi-factor authentication." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.22 Ensure that 'Require Multi-Factor Authentication to register or join devices with Azure AD' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_23.yaml b/compliance/controls/azure/azure_cis_v200_1_23.yaml old mode 100755 new mode 100644 index 2875cf29d..a9cd2aeb5 --- a/compliance/controls/azure/azure_cis_v200_1_23.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_23.yaml @@ -1,53 +1,53 @@ +Description: The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access. ID: azure_cis_v200_1_23 -Title: "1.23 Ensure That No Custom Subscription Administrator Roles Exist" -Description: "The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with owner_custom_roles as ( - select + ListOfTables: + - azure_role_definition + - azure_subscription + Parameters: [] + PrimaryTable: azure_role_definition + QueryToExecute: | + WITH owner_custom_roles AS ( + SELECT role_name, role_type, title, action, _ctx, subscription_id - from + FROM azure_role_definition, - jsonb_array_elements(permissions) as s, - jsonb_array_elements_text(s -> 'actions') as action - where + jsonb_array_elements(permissions) AS s, + jsonb_array_elements_text(s -> 'actions') AS action + WHERE role_type = 'CustomRole' - and action in ('*', '*:*') + AND action IN ('*', '*:*') ) - select - cr.subscription_id as resource, - cr.og_account_id as og_account_id, - cr.og_resource_id as og_resource_id, - case - when count(*) > 0 then 'alarm' - else 'ok' - end as status, - case - when count(*) = 1 then 'There is one custom owner role.' - when count(*) > 1 then 'There are ' || count(*) || ' custom owner roles.' - else 'There are no custom owner roles.' - end as reason - from + SELECT + cr.subscription_id AS resource, + cr.og_account_id AS og_account_id, + cr.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(*) > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(*) = 1 THEN 'There is one custom owner role.' + WHEN COUNT(*) > 1 THEN 'There are ' || COUNT(*) || ' custom owner roles.' + ELSE 'There are no custom owner roles.' + END AS reason + FROM owner_custom_roles cr, azure_subscription sub - where + WHERE sub.subscription_id = cr.subscription_id - group by + GROUP BY cr.subscription_id, cr._ctx, sub.display_name; - PrimaryTable: azure_role_definition - ListOfTables: - - azure_role_definition - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.23 Ensure That No Custom Subscription Administrator Roles Exist \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_24.yaml b/compliance/controls/azure/azure_cis_v200_1_24.yaml old mode 100755 new mode 100644 index 3529f0ed7..254e06d4d --- a/compliance/controls/azure/azure_cis_v200_1_24.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_24.yaml @@ -1,19 +1,19 @@ +Description: Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration. ID: azure_cis_v200_1_24 -Title: "1.24 Ensure a Custom Role is Assigned Permissions for Administering Resource Locks" -Description: "Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.24 Ensure a Custom Role is Assigned Permissions for Administering Resource Locks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_25.yaml b/compliance/controls/azure/azure_cis_v200_1_25.yaml old mode 100755 new mode 100644 index 31a3e488d..67086bb67 --- a/compliance/controls/azure/azure_cis_v200_1_25.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_25.yaml @@ -1,19 +1,19 @@ +Description: Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Azure Active Directories. ID: azure_cis_v200_1_25 -Title: "1.25 Ensure That 'Subscription Entering AAD Directory' and 'Subscription Leaving AAD Directory' Is Set To 'Permit No One'" -Description: "Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Azure Active Directories." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.25 Ensure That 'Subscription Entering AAD Directory' and 'Subscription Leaving AAD Directory' Is Set To 'Permit No One' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_2_1.yaml b/compliance/controls/azure/azure_cis_v200_1_2_1.yaml old mode 100755 new mode 100644 index fa3f30df6..5c5d5c4d8 --- a/compliance/controls/azure/azure_cis_v200_1_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_2_1.yaml @@ -1,19 +1,19 @@ +Description: Azure Active Directory Conditional Access allows an organization to configure Named locations and configure whether those locations are trusted or untrusted. These settings provide organizations the means to specify Geographical locations for use in conditional access policies, or define actual IP addresses and IP ranges and whether or not those IP addresses and/or ranges are trusted by the organization. ID: azure_cis_v200_1_2_1 -Title: "1.2.1 Ensure Trusted Locations Are Defined" -Description: "Azure Active Directory Conditional Access allows an organization to configure Named locations and configure whether those locations are trusted or untrusted. These settings provide organizations the means to specify Geographical locations for use in conditional access policies, or define actual IP addresses and IP ranges and whether or not those IP addresses and/or ranges are trusted by the organization." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.1 Ensure Trusted Locations Are Defined \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_2_2.yaml b/compliance/controls/azure/azure_cis_v200_1_2_2.yaml old mode 100755 new mode 100644 index 2e843f1c8..207572803 --- a/compliance/controls/azure/azure_cis_v200_1_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_2_2.yaml @@ -1,19 +1,19 @@ +Description: Conditional Access Policies can be used to block access from geographic locations that are deemed out-of-scope for your organization or application. The scope and variables for this policy should be carefully examined and defined. ID: azure_cis_v200_1_2_2 -Title: "1.2.2 Ensure that an exclusionary Geographic Access Policy is considered" -Description: "Conditional Access Policies can be used to block access from geographic locations that are deemed out-of-scope for your organization or application. The scope and variables for this policy should be carefully examined and defined." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.2 Ensure that an exclusionary Geographic Access Policy is considered \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_2_3.yaml b/compliance/controls/azure/azure_cis_v200_1_2_3.yaml old mode 100755 new mode 100644 index bba71fdfa..4af70e75e --- a/compliance/controls/azure/azure_cis_v200_1_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_2_3.yaml @@ -1,19 +1,19 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login. ID: azure_cis_v200_1_2_3 -Title: "1.2.3 Ensure that A Multi-factor Authentication Policy Exists for Administrative Groups" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.3 Ensure that A Multi-factor Authentication Policy Exists for Administrative Groups \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_2_4.yaml b/compliance/controls/azure/azure_cis_v200_1_2_4.yaml old mode 100755 new mode 100644 index 0b1d135b9..bb1ff1d55 --- a/compliance/controls/azure/azure_cis_v200_1_2_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_2_4.yaml @@ -1,19 +1,19 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins. ID: azure_cis_v200_1_2_4 -Title: "1.2.4 Ensure that A Multi-factor Authentication Policy Exists for All Users" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.4 Ensure that A Multi-factor Authentication Policy Exists for All Users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_2_5.yaml b/compliance/controls/azure/azure_cis_v200_1_2_5.yaml old mode 100755 new mode 100644 index 870a44e5b..f2d03ea43 --- a/compliance/controls/azure/azure_cis_v200_1_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_2_5.yaml @@ -1,19 +1,19 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login. ID: azure_cis_v200_1_2_5 -Title: "1.2.5 Ensure Multi-factor Authentication is Required for Risky Sign-ins" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.5 Ensure Multi-factor Authentication is Required for Risky Sign-ins \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_2_6.yaml b/compliance/controls/azure/azure_cis_v200_1_2_6.yaml old mode 100755 new mode 100644 index 027a8b9cb..d115a5c08 --- a/compliance/controls/azure/azure_cis_v200_1_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_2_6.yaml @@ -1,39 +1,39 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins. ID: azure_cis_v200_1_2_6 -Title: "1.2.6 Ensure Multi-factor Authentication is Required for Azure Management" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_conditional_access_policy + Parameters: [] + PrimaryTable: azuread_conditional_access_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - p.id as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when p.built_in_controls @> '["mfa"]' then 'ok' - else 'alarm' - end as status, - case - when p.built_in_controls @> '["mfa"]' then p.display_name || ' MFA enabled.' - else p.display_name || ' MFA disabled.' - end as reason, + SELECT + p.id AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.built_in_controls @> '["mfa"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.built_in_controls @> '["mfa"]' THEN p.display_name || ' MFA enabled.' + ELSE p.display_name || ' MFA disabled.' + END AS reason, t.tenant_id - from - distinct_tenant as t, - azuread_conditional_access_policy as p; - PrimaryTable: azuread_conditional_access_policy - ListOfTables: - - azure_tenant - - azuread_conditional_access_policy - Parameters: [] + FROM + distinct_tenant AS t, + azuread_conditional_access_policy AS p; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.2.6 Ensure Multi-factor Authentication is Required for Azure Management \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_3.yaml b/compliance/controls/azure/azure_cis_v200_1_3.yaml old mode 100755 new mode 100644 index 2e8cc1ad0..81884599f --- a/compliance/controls/azure/azure_cis_v200_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_3.yaml @@ -1,19 +1,19 @@ +Description: Require administrators or appropriately delegated users to create new tenants. ID: azure_cis_v200_1_3 -Title: "1.3 Ensure that 'Users can create Azure AD Tenants' is set to 'No'" -Description: "Require administrators or appropriately delegated users to create new tenants." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.3 Ensure that 'Users can create Azure AD Tenants' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_4.yaml b/compliance/controls/azure/azure_cis_v200_1_4.yaml old mode 100755 new mode 100644 index 49efa8090..f7179d1db --- a/compliance/controls/azure/azure_cis_v200_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_4.yaml @@ -1,19 +1,19 @@ +Description: This recommendation extends guest access review by utilizing the Azure AD Privileged Identity Management feature provided in Azure AD Premium P2. Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. ID: azure_cis_v200_1_4 -Title: "1.4 Ensure Access Review is Set Up for External Users in Azure AD Privileged Identity Management" -Description: "This recommendation extends guest access review by utilizing the Azure AD Privileged Identity Management feature provided in Azure AD Premium P2. Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.4 Ensure Access Review is Set Up for External Users in Azure AD Privileged Identity Management \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_5.yaml b/compliance/controls/azure/azure_cis_v200_1_5.yaml old mode 100755 new mode 100644 index 4922e49cd..f337fc48a --- a/compliance/controls/azure/azure_cis_v200_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_5.yaml @@ -1,42 +1,42 @@ +Description: Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user. Guest users in every subscription should be review on a regular basis to ensure that inactive and unneeded accounts are removed. ID: azure_cis_v200_1_5 -Title: "1.5 Ensure Guest Users Are Reviewed on a Regular Basis" -Description: "Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user. Guest users in every subscription should be review on a regular basis to ensure that inactive and unneeded accounts are removed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_user + Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - u.display_name as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when not account_enabled then 'alarm' - when u.created_date_time::timestamp <= (current_date - interval '30' day) then 'alarm' - else 'ok' - end as status, - case - when not account_enabled then 'Guest user ''' || u.display_name || ''' inactive.' - else 'Guest user ''' || u.display_name || ''' was created ' || extract(day from current_timestamp - u.created_date_time::timestamp) || ' days ago.' - end as reason, + SELECT + u.display_name AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN NOT account_enabled THEN 'alarm' + WHEN u.created_date_time::timestamp <= (CURRENT_DATE - INTERVAL '30' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT account_enabled THEN 'Guest user ''' || u.display_name || ''' inactive.' + ELSE 'Guest user ''' || u.display_name || ''' was created ' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - u.created_date_time::timestamp) || ' days ago.' + END AS reason, t.tenant_id - from - azuread_user as u - left join distinct_tenant as t on t.tenant_id = u.tenant_id - where + FROM + azuread_user AS u + LEFT JOIN distinct_tenant AS t ON t.tenant_id = u.tenant_id + WHERE u.user_type = 'Guest'; - PrimaryTable: azuread_user - ListOfTables: - - azure_tenant - - azuread_user - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.5 Ensure Guest Users Are Reviewed on a Regular Basis \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_6.yaml b/compliance/controls/azure/azure_cis_v200_1_6.yaml old mode 100755 new mode 100644 index 4816d0fd5..518965441 --- a/compliance/controls/azure/azure_cis_v200_1_6.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_6.yaml @@ -1,19 +1,19 @@ +Description: Ensures that two alternate forms of identification are provided before allowing a password reset. ID: azure_cis_v200_1_6 -Title: "1.6 Ensure That 'Number of methods required to reset' is set to '2'" -Description: "Ensures that two alternate forms of identification are provided before allowing a password reset." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.6 Ensure That 'Number of methods required to reset' is set to '2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_7.yaml b/compliance/controls/azure/azure_cis_v200_1_7.yaml old mode 100755 new mode 100644 index 3bfcb4e34..b9e12c49b --- a/compliance/controls/azure/azure_cis_v200_1_7.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_7.yaml @@ -1,19 +1,19 @@ +Description: Microsoft Azure provides a Global Banned Password policy that applies to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Azure AD Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers. Please see the list in default values on the specifics of this policy. To further password security, it is recommended to further define a custom banned password policy. ID: azure_cis_v200_1_7 -Title: "1.7 Ensure that a Custom Bad Password List is set to 'Enforce' for your Organization" -Description: "Microsoft Azure provides a Global Banned Password policy that applies to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Azure AD Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers. Please see the list in default values on the specifics of this policy. To further password security, it is recommended to further define a custom banned password policy." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.7 Ensure that a Custom Bad Password List is set to 'Enforce' for your Organization \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_8.yaml b/compliance/controls/azure/azure_cis_v200_1_8.yaml old mode 100755 new mode 100644 index 09da61b62..970a4c031 --- a/compliance/controls/azure/azure_cis_v200_1_8.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_8.yaml @@ -1,19 +1,19 @@ +Description: Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0. ID: azure_cis_v200_1_8 -Title: "1.8 Ensure that 'Number of days before users are asked to re- confirm their authentication information' is not set to '0'" -Description: "Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.8 Ensure that 'Number of days before users are asked to re-confirm their authentication information' is not set to '0' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_1_9.yaml b/compliance/controls/azure/azure_cis_v200_1_9.yaml old mode 100755 new mode 100644 index d0f7bc4ce..210236c9a --- a/compliance/controls/azure/azure_cis_v200_1_9.yaml +++ b/compliance/controls/azure/azure_cis_v200_1_9.yaml @@ -1,19 +1,19 @@ +Description: Ensure that users are notified on their primary and secondary emails on password resets. ID: azure_cis_v200_1_9 -Title: "1.9 Ensure that 'Notify users on password resets?' is set to 'Yes'" -Description: "Ensure that users are notified on their primary and secondary emails on password resets." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.9 Ensure that 'Notify users on password resets?' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_1.yaml b/compliance/controls/azure/azure_cis_v200_2_1_1.yaml old mode 100755 new mode 100644 index 286fc85b1..409e2fd2c --- a/compliance/controls/azure/azure_cis_v200_2_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_1.yaml @@ -1,32 +1,35 @@ +Description: Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v200_2_1_1 -Title: "2.1.1 Ensure That Microsoft Defender for Servers Is Set to 'On'" -Description: "Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Servers.' - else 'Azure Defender off for Servers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'VirtualMachines'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Servers.' + ELSE 'Azure Defender off for Servers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'VirtualMachines'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.1 Ensure That Microsoft Defender for Servers Is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_11.yaml b/compliance/controls/azure/azure_cis_v200_2_1_11.yaml old mode 100755 new mode 100644 index 7724cb4aa..cd0967d68 --- a/compliance/controls/azure/azure_cis_v200_2_1_11.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_11.yaml @@ -1,32 +1,35 @@ +Description: Microsoft Defender for DNS scans all network traffic exiting from within a subscription. ID: azure_cis_v200_2_1_11 -Title: "2.1.11 Ensure That Microsoft Defender for DNS Is Set To 'On'" -Description: "Microsoft Defender for DNS scans all network traffic exiting from within a subscription." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for DNS.' - else 'Azure Defender off for DNS.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'Dns'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for DNS.' + ELSE 'Azure Defender off for DNS.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'Dns'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.11 Ensure That Microsoft Defender for DNS Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_12.yaml b/compliance/controls/azure/azure_cis_v200_2_1_12.yaml old mode 100755 new mode 100644 index 69cf0c87c..de7195bed --- a/compliance/controls/azure/azure_cis_v200_2_1_12.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_12.yaml @@ -1,24 +1,24 @@ +Description: Microsoft Defender for Resource Manager scans incoming administrative requests to change your infrastructure from both CLI and the Azure portal. ID: azure_cis_v200_2_1_12 -Title: "2.1.12 Ensure That Microsoft Defender for Resource Manager Is Set To 'On'" -Description: "Microsoft Defender for Resource Manager scans incoming administrative requests to change your infrastructure from both CLI and the Azure portal." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.1.12 Ensure That Microsoft Defender for Resource Manager Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_13.yaml b/compliance/controls/azure/azure_cis_v200_2_1_13.yaml old mode 100755 new mode 100644 index 9d104387a..df49bc3aa --- a/compliance/controls/azure/azure_cis_v200_2_1_13.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_13.yaml @@ -1,24 +1,24 @@ +Description: Ensure that the latest OS patches for all virtual machines are applied. ID: azure_cis_v200_2_1_13 -Title: "2.1.13 Ensure that Microsoft Defender Recommendation for 'Apply system updates' status is 'Completed'" -Description: "Ensure that the latest OS patches for all virtual machines are applied." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.1.13 Ensure that Microsoft Defender Recommendation for 'Apply system updates' status is 'Completed' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_14.yaml b/compliance/controls/azure/azure_cis_v200_2_1_14.yaml old mode 100755 new mode 100644 index 500e11026..5181d2e41 --- a/compliance/controls/azure/azure_cis_v200_2_1_14.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_14.yaml @@ -1,38 +1,46 @@ +Description: None of the settings offered by ASC Default policy should be set to effect Disabled. ID: azure_cis_v200_2_1_14 -Title: "2.1.14 Ensure Any of the ASC Default Policy Settings are Not Set to 'Disabled'" -Description: "None of the settings offered by ASC Default policy should be set to effect Disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with policy_assignment_parameters as ( - select + ListOfTables: + - azure_policy_assignment + - azure_subscription + Parameters: [] + PrimaryTable: azure_policy_assignment + QueryToExecute: | + WITH policy_assignment_parameters AS ( + SELECT id, name, key, - parameters -> key ->> 'value' as value, + parameters -> key ->> 'value' AS value, subscription_id - from + FROM azure_policy_assignment, - jsonb_object_keys(parameters) as key - where + jsonb_object_keys(parameters) AS key + WHERE name = 'SecurityCenterBuiltIn' ) - select - sub.id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(value = 'Disabled') > 0 then 'alarm' - else 'ok' - end as status, - case - when count(value = 'Disabled') > 0 then 'Settings disabled for ' || count(*) filter (where value = 'Disabled') || ' parameters.' - else 'Settings enabled for all the parameters.' - end as reason - from + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(value = 'Disabled') > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(value = 'Disabled') > 0 THEN + 'Settings disabled for ' || COUNT(*) FILTER (WHERE value = 'Disabled') || ' parameters.' + ELSE 'Settings enabled for all the parameters.' + END AS reason + FROM policy_assignment_parameters pol_assignment - right join azure_subscription sub on pol_assignment.subscription_id = sub.subscription_id - group by + RIGHT JOIN + azure_subscription sub ON pol_assignment.subscription_id = sub.subscription_id + GROUP BY sub.id, pol_assignment.id, sub._ctx, @@ -41,12 +49,6 @@ Query: sub.display_name, sub.og_account_id, sub.og_resource_id; - PrimaryTable: azure_policy_assignment - ListOfTables: - - azure_policy_assignment - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.14 Ensure Any of the ASC Default Policy Settings are Not Set to 'Disabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_15.yaml b/compliance/controls/azure/azure_cis_v200_2_1_15.yaml old mode 100755 new mode 100644 index b60185ed2..4b7a0ca79 --- a/compliance/controls/azure/azure_cis_v200_2_1_15.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_15.yaml @@ -1,30 +1,32 @@ +Description: Enable automatic provisioning of the monitoring agent to collect security data. ID: azure_cis_v200_2_1_15 -Title: "2.1.15 Ensure that Auto provisioning of 'Log Analytics agent for Azure VMs' is Set to 'On'" -Description: "Enable automatic provisioning of the monitoring agent to collect security data." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_prov.id as resource, - sc_prov.og_account_id as og_account_id, - sc_prov.og_resource_id as og_resource_id, - case - when auto_provision = 'On' then 'ok' - else 'alarm' - end as status, - case - when auto_provision = 'On' then 'Automatic provisioning of monitoring agent is on.' - else 'Automatic provisioning of monitoring agent is off.' - end as reason - from - azure_security_center_auto_provisioning sc_prov - right join azure_subscription sub on sc_prov.subscription_id = sub.subscription_id; - PrimaryTable: azure_security_center_auto_provisioning ListOfTables: - azure_security_center_auto_provisioning - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_auto_provisioning + QueryToExecute: | + SELECT + sc_prov.id AS resource, + sc_prov.og_account_id AS og_account_id, + sc_prov.og_resource_id AS og_resource_id, + CASE + WHEN auto_provision = 'On' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_provision = 'On' THEN 'Automatic provisioning of monitoring agent is on.' + ELSE 'Automatic provisioning of monitoring agent is off.' + END AS reason + FROM + azure_security_center_auto_provisioning sc_prov + RIGHT JOIN + azure_subscription sub + ON sc_prov.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.15 Ensure that Auto provisioning of 'Log Analytics agent for Azure VMs' is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_16.yaml b/compliance/controls/azure/azure_cis_v200_2_1_16.yaml old mode 100755 new mode 100644 index 04d40957c..e477ddd3d --- a/compliance/controls/azure/azure_cis_v200_2_1_16.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_16.yaml @@ -1,24 +1,24 @@ +Description: Enable automatic provisioning of vulnerability assessment for machines on both Azure and hybrid (Arc enabled) machines. ID: azure_cis_v200_2_1_16 -Title: "2.1.16 Ensure that Auto provisioning of 'Vulnerability assessment for machines' is Set to 'On'" -Description: "Enable automatic provisioning of vulnerability assessment for machines on both Azure and hybrid (Arc enabled) machines." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.1.16 Ensure that Auto provisioning of 'Vulnerability assessment for machines' is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_17.yaml b/compliance/controls/azure/azure_cis_v200_2_1_17.yaml old mode 100755 new mode 100644 index 5cfdc44da..eb652b477 --- a/compliance/controls/azure/azure_cis_v200_2_1_17.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_17.yaml @@ -1,24 +1,24 @@ +Description: Enable automatic provisioning of the Microsoft Defender for Containers components. ID: azure_cis_v200_2_1_17 -Title: "2.1.17 Ensure that Auto provisioning of 'Microsoft Defender for Containers components' is Set to 'On'" -Description: "Enable automatic provisioning of the Microsoft Defender for Containers components." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.1.17 Ensure that Auto provisioning of 'Microsoft Defender for Containers components' is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_18.yaml b/compliance/controls/azure/azure_cis_v200_2_1_18.yaml old mode 100755 new mode 100644 index 23e0713ae..2b9697419 --- a/compliance/controls/azure/azure_cis_v200_2_1_18.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_18.yaml @@ -1,40 +1,40 @@ +Description: Enable security alert emails to subscription owners. ID: azure_cis_v200_2_1_18 -Title: "2.1.18 Ensure That 'All users with the following roles' is set to 'Owner'" -Description: "Enable security alert emails to subscription owners." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with contact_info as ( - select - count(*) filter (where alerts_to_admins = 'On') as admin_alert_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alerts_to_admins = 'On') AS admin_alert_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when admin_alert_count > 0 then 'ok' - else 'alarm' - end as status, - case - when admin_alert_count > 0 then '"All users with the following roles" set to Owner' - else '"All users with the following roles" not set to Owner.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN admin_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN admin_alert_count > 0 THEN '"All users with the following roles" set to Owner' + ELSE '"All users with the following roles" not set to Owner.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.18 Ensure That 'All users with the following roles' is set to 'Owner' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_19.yaml b/compliance/controls/azure/azure_cis_v200_2_1_19.yaml old mode 100755 new mode 100644 index 44dca2a56..724bd45b0 --- a/compliance/controls/azure/azure_cis_v200_2_1_19.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_19.yaml @@ -1,44 +1,45 @@ +Description: Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address. ID: azure_cis_v200_2_1_19 -Title: "2.1.19 Ensure 'Additional email addresses' is Configured with a Security Contact Email" -Description: "Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with contact_info as ( - select - jsonb_agg(email) filter (where name = 'default' and email != '') as default_email, - count(*) filter (where name != 'default') as non_default_count, - count(*) filter (where name = 'default') as default_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + jsonb_agg(email) FILTER (WHERE name = 'default' AND email != '') AS default_email, + COUNT(*) FILTER (WHERE name != 'default') AS non_default_count, + COUNT(*) FILTER (WHERE name = 'default') AS default_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when non_default_count > 0 then 'ok' - when default_count = 1 and jsonb_array_length(default_email) != 0 then 'ok' - else 'alarm' - end as status, - case - when non_default_count > 0 then 'Additional email addresses configured.' - when default_count = 1 and default_email is not null then'Additional email addresses configured.' - else 'Additional email addresses not configured.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN non_default_count > 0 THEN 'ok' + WHEN default_count = 1 AND jsonb_array_length(default_email) != 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN non_default_count > 0 THEN 'Additional email addresses configured.' + WHEN default_count = 1 AND default_email IS NOT NULL THEN 'Additional email addresses configured.' + ELSE 'Additional email addresses not configured.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN + contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.19 Ensure 'Additional email addresses' is Configured with a Security Contact Email \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_2.yaml b/compliance/controls/azure/azure_cis_v200_2_1_2.yaml old mode 100755 new mode 100644 index f2a4f68a1..5273020b6 --- a/compliance/controls/azure/azure_cis_v200_2_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_2.yaml @@ -1,32 +1,32 @@ +Description: Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v200_2_1_2 -Title: "2.1.2 Ensure That Microsoft Defender for App Services Is Set To 'On'" -Description: "Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for App Services.' - else 'Azure Defender off for App Services.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'AppServices'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for App Services.' + ELSE 'Azure Defender off for App Services.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'AppServices'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.2 Ensure That Microsoft Defender for App Services Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_20.yaml b/compliance/controls/azure/azure_cis_v200_2_1_20.yaml old mode 100755 new mode 100644 index 8dbfece22..3072290af --- a/compliance/controls/azure/azure_cis_v200_2_1_20.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_20.yaml @@ -1,15 +1,40 @@ +Description: Enables emailing security alerts to the subscription owner or other designated security contact. ID: azure_cis_v200_2_1_20 -Title: "2.1.20 Ensure That 'Notify about alerts with the following severity' is Set to 'High'" -Description: "Enables emailing security alerts to the subscription owner or other designated security contact." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with contact_info as (\n select\n count(*) filter (where alert_notifications = 'On') as notification_alert_count,\n subscription_id\n from\n azure_security_center_contact\n group by\n subscription_id\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when notification_alert_count > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when notification_alert_count > 0 then '\"Notify about alerts with the following severity\" set to High.'\n else '\"Notify about alerts with the following severity\" not set to High.'\n end as reason\n \n \nfrom\n azure_subscription sub\n left join contact_info ci on sub.subscription_id = ci.subscription_id;" - PrimaryTable: azure_subscription ListOfTables: - azure_security_center_contact - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alert_notifications = 'On') AS notification_alert_count, + subscription_id + FROM + azure_security_center_contact + GROUP BY + subscription_id + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN notification_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN notification_alert_count > 0 THEN '"Notify about alerts with the following severity" set to High.' + ELSE '"Notify about alerts with the following severity" not set to High.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.20 Ensure That 'Notify about alerts with the following severity' is Set to 'High' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_21.yaml b/compliance/controls/azure/azure_cis_v200_2_1_21.yaml old mode 100755 new mode 100644 index 2e2fbc043..9158b3457 --- a/compliance/controls/azure/azure_cis_v200_2_1_21.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_21.yaml @@ -1,32 +1,35 @@ +Description: This integration setting enables Microsoft Defender for Cloud Apps (formerly 'Microsoft Cloud App Security' or 'MCAS' - see additional info) to communicate with Microsoft Defender for Cloud. ID: azure_cis_v200_2_1_21 -Title: "2.1.21 Ensure that Microsoft Defender for Cloud Apps integration with Microsoft Defender for Cloud is Selected" -Description: "This integration setting enables Microsoft Defender for Cloud Apps (formerly 'Microsoft Cloud App Security' or 'MCAS' - see additional info) to communicate with Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_sett.id as resource, - sc_sett.og_account_id as og_account_id, - sc_sett.og_resource_id as og_resource_id, - case - when enabled then 'ok' - else 'alarm' - end as status, - case - when enabled then 'Windows Defender ATP (WDATP) integrated with Security Center.' - else 'Windows Defender ATP (WDATP) not integrated with Security Center.' - end as reason - from - azure_security_center_setting sc_sett - right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id - where - name = 'MCAS'; - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Windows Defender ATP (WDATP) integrated with Security Center.' + ELSE 'Windows Defender ATP (WDATP) not integrated with Security Center.' + END AS reason + FROM + azure_security_center_setting sc_sett + RIGHT JOIN + azure_subscription sub + ON + sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'MCAS'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.21 Ensure that Microsoft Defender for Cloud Apps integration with Microsoft Defender for Cloud is Selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_22.yaml b/compliance/controls/azure/azure_cis_v200_2_1_22.yaml old mode 100755 new mode 100644 index 6e47db776..91746e328 --- a/compliance/controls/azure/azure_cis_v200_2_1_22.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_22.yaml @@ -1,15 +1,32 @@ +Description: This integration setting enables Microsoft Defender for Endpoint (formerly 'Advanced Threat Protection' or 'ATP' or 'WDATP' - see additional info) to communicate with Microsoft Defender for Cloud. ID: azure_cis_v200_2_1_22 -Title: "2.1.22 Ensure that Microsoft Defender for Endpoint integration with Microsoft Defender for Cloud is selected" -Description: "This integration setting enables Microsoft Defender for Endpoint (formerly 'Advanced Threat Protection' or 'ATP' or 'WDATP' - see additional info) to communicate with Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sc_sett.id as resource,\n sc_sett.og_account_id as og_account_id,\n sc_sett.og_resource_id as og_resource_id,\n case\n when enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when enabled then 'Microsoft Cloud App Security (MCAS) integrated with Security Center.'\n else 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.'\n end as reason\n \nfrom\n azure_security_center_setting sc_sett\n right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id\nwhere\n name = 'WDATP';" - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Microsoft Cloud App Security (MCAS) integrated with Security Center.' + ELSE 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.' + END AS reason + FROM + azure_security_center_setting sc_sett + RIGHT JOIN azure_subscription sub ON sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'WDATP'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.22 Ensure that Microsoft Defender for Endpoint integration with Microsoft Defender for Cloud is selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_3.yaml b/compliance/controls/azure/azure_cis_v200_2_1_3.yaml old mode 100755 new mode 100644 index 551c71872..ae453458d --- a/compliance/controls/azure/azure_cis_v200_2_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_3.yaml @@ -1,51 +1,51 @@ +Description: Turning on Microsoft Defender for Databases enables threat detection for the instances running your database software. This provides threat intelligence, anomaly detection, and behavior analytics in the Azure Microsoft Defender for Cloud. Instead of being enabled on services like Platform as a Service (PaaS), this implementation will run within your instances as Infrastructure as a Service (IaaS) on the Operating Systems hosting your databases. ID: azure_cis_v200_2_1_3 -Title: "2.1.3 Ensure That Microsoft Defender for Databases Is Set To 'On'" -Description: "Turning on Microsoft Defender for Databases enables threat detection for the instances running your database software. This provides threat intelligence, anomaly detection, and behavior analytics in the Azure Microsoft Defender for Cloud. Instead of being enabled on services like Platform as a Service (PaaS), this implementation will run within your instances as Infrastructure as a Service (IaaS) on the Operating Systems hosting your databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with defender_list as ( - select - json_object_agg(name, pricing_tier) as data, + ListOfTables: + - azure_security_center_subscription_pricing + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH defender_list AS ( + SELECT + json_object_agg(name, pricing_tier) AS data, subscription_id - from + FROM azure_security_center_subscription_pricing - where - name = any(ARRAY ['CosmosDbs', 'OpenSourceRelationalDatabases', 'SqlServerVirtualMachines', 'SqlServers']) - group by + WHERE + name = ANY(ARRAY ['CosmosDbs', 'OpenSourceRelationalDatabases', 'SqlServerVirtualMachines', 'SqlServers']) + GROUP BY subscription_id ) - select - sub.id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN data ->> 'CosmosDbs' = 'Standard' - and data ->> 'OpenSourceRelationalDatabases' = 'Standard' - and data ->> 'SqlServerVirtualMachines' = 'Standard' - and data ->> 'SqlServers' = 'Standard' - then 'ok' - else 'alarm' - end as status, - case - when + AND data ->> 'OpenSourceRelationalDatabases' = 'Standard' + AND data ->> 'SqlServerVirtualMachines' = 'Standard' + AND data ->> 'SqlServers' = 'Standard' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN data ->> 'CosmosDbs' = 'Standard' - and data ->> 'OpenSourceRelationalDatabases' = 'Standard' - and data ->> 'SqlServerVirtualMachines' = 'Standard' - and data ->> 'SqlServers' = 'Standard' - then 'Azure Defender on for Databases.' - else 'Azure Defender off for Databases.' - end as reason - from - azure_subscription as sub - left join defender_list as l on l.subscription_id = sub.subscription_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_subscription_pricing - - azure_subscription - Parameters: [] + AND data ->> 'OpenSourceRelationalDatabases' = 'Standard' + AND data ->> 'SqlServerVirtualMachines' = 'Standard' + AND data ->> 'SqlServers' = 'Standard' + THEN 'Azure Defender on for Databases.' + ELSE 'Azure Defender off for Databases.' + END AS reason + FROM + azure_subscription AS sub + LEFT JOIN defender_list AS l ON l.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.3 Ensure That Microsoft Defender for Databases Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_4.yaml b/compliance/controls/azure/azure_cis_v200_2_1_4.yaml old mode 100755 new mode 100644 index b7b0fc014..66586c2da --- a/compliance/controls/azure/azure_cis_v200_2_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_4.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v200_2_1_4 -Title: "2.1.4 Ensure That Microsoft Defender for Azure SQL Databases Is Set To 'On'" -Description: "Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for SQL database servers.' - else 'Azure Defender off for SQL database servers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'SqlServers'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL database servers.' + ELSE 'Azure Defender off for SQL database servers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServers'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.4 Ensure That Microsoft Defender for Azure SQL Databases Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_5.yaml b/compliance/controls/azure/azure_cis_v200_2_1_5.yaml old mode 100755 new mode 100644 index 52d018ba1..e9f063d07 --- a/compliance/controls/azure/azure_cis_v200_2_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_5.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v200_2_1_5 -Title: "2.1.5 Ensure That Microsoft Defender for SQL Servers on Machines Is Set To 'On'" -Description: "Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for SQL servers on machines.' - else 'Azure Defender off for SQL servers on machines.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'SqlServerVirtualMachines'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL servers on machines.' + ELSE 'Azure Defender off for SQL servers on machines.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServerVirtualMachines'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.5 Ensure That Microsoft Defender for SQL Servers on Machines Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_6.yaml b/compliance/controls/azure/azure_cis_v200_2_1_6.yaml old mode 100755 new mode 100644 index ffd5c09ac..805947580 --- a/compliance/controls/azure/azure_cis_v200_2_1_6.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_6.yaml @@ -1,32 +1,35 @@ +Description: Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v200_2_1_6 -Title: "2.1.6 Ensure That Microsoft Defender for Open-Source Relational Databases Is Set To 'On'" -Description: "Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Open Source Relational Databases.' - else 'Azure Defender off for Open Source Relational Databases.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'OpenSourceRelationalDatabases'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Open Source Relational Databases.' + ELSE 'Azure Defender off for Open Source Relational Databases.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'OpenSourceRelationalDatabases'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.6 Ensure That Microsoft Defender for Open-Source Relational Databases Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_7.yaml b/compliance/controls/azure/azure_cis_v200_2_1_7.yaml old mode 100755 new mode 100644 index eb88b47b2..f176adb8f --- a/compliance/controls/azure/azure_cis_v200_2_1_7.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_7.yaml @@ -1,32 +1,35 @@ +Description: Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v200_2_1_7 -Title: "2.1.7 Ensure That Microsoft Defender for Storage Is Set To 'On'" -Description: "Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Storage.' - else 'Azure Defender off for Storage.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'StorageAccounts'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Storage.' + ELSE 'Azure Defender off for Storage.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'StorageAccounts'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.7 Ensure That Microsoft Defender for Storage Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_8.yaml b/compliance/controls/azure/azure_cis_v200_2_1_8.yaml old mode 100755 new mode 100644 index 9f972775e..9040acd3c --- a/compliance/controls/azure/azure_cis_v200_2_1_8.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_8.yaml @@ -1,15 +1,33 @@ +Description: Turning on Microsoft Defender for Containers enables threat detection for Container Registries including Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v200_2_1_8 -Title: "2.1.8 Ensure That Microsoft Defender for Containers Is Set To 'On'" -Description: "Turning on Microsoft Defender for Containers enables threat detection for Container Registries including Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Container Registry.'\n else 'Azure Defender off for Container Registry.'\n end as reason\n \n \nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'ContainerRegistry';" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Container Registry.' + ELSE 'Azure Defender off for Container Registry.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'ContainerRegistry'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.8 Ensure That Microsoft Defender for Containers Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_1_9.yaml b/compliance/controls/azure/azure_cis_v200_2_1_9.yaml old mode 100755 new mode 100644 index 915b0e7d4..6afdf2581 --- a/compliance/controls/azure/azure_cis_v200_2_1_9.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_1_9.yaml @@ -1,32 +1,33 @@ +Description: Microsoft Defender for Azure Cosmos DB scans all incoming network requests for threats to your Azure Cosmos DB resources. ID: azure_cis_v200_2_1_9 -Title: "2.1.9 Ensure That Microsoft Defender for Azure Cosmos DB Is Set To 'On'" -Description: "Microsoft Defender for Azure Cosmos DB scans all incoming network requests for threats to your Azure Cosmos DB resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Cosmos DB.' - else 'Azure Defender off for Cosmos DB.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'CosmosDbs'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Cosmos DB.' + ELSE 'Azure Defender off for Cosmos DB.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'CosmosDbs'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.9 Ensure That Microsoft Defender for Azure Cosmos DB Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_2_2_1.yaml b/compliance/controls/azure/azure_cis_v200_2_2_1.yaml old mode 100755 new mode 100644 index 0d33b2f90..5f6057219 --- a/compliance/controls/azure/azure_cis_v200_2_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_2_2_1.yaml @@ -1,24 +1,24 @@ +Description: Microsoft Defender for IoT acts as a central security hub for IoT devices within your organization. ID: azure_cis_v200_2_2_1 -Title: "2.2.1 Ensure That Microsoft Defender for IoT Hub Is Set To 'On'" -Description: "Microsoft Defender for IoT acts as a central security hub for IoT devices within your organization." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.2.1 Ensure That Microsoft Defender for IoT Hub Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_1.yaml b/compliance/controls/azure/azure_cis_v200_3_1.yaml old mode 100755 new mode 100644 index 302ff45e0..46fc19bb3 --- a/compliance/controls/azure/azure_cis_v200_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_1.yaml @@ -1,32 +1,32 @@ +Description: Enable data encryption in transit. ID: azure_cis_v200_3_1 -Title: "3.1 Ensure that 'Secure transfer required' is set to 'Enabled'" -Description: "Enable data encryption in transit." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not enable_https_traffic_only then 'alarm' - else 'ok' - end as status, - case - when not enable_https_traffic_only then sa.name || ' encryption in transit not enabled.' - else sa.name || ' encryption in transit enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT enable_https_traffic_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT enable_https_traffic_only THEN sa.name || ' encryption in transit not enabled.' + ELSE sa.name || ' encryption in transit enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.1 Ensure that 'Secure transfer required' is set to 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_10.yaml b/compliance/controls/azure/azure_cis_v200_3_10.yaml old mode 100755 new mode 100644 index ff73dc599..6ad7a7112 --- a/compliance/controls/azure/azure_cis_v200_3_10.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_10.yaml @@ -1,42 +1,43 @@ +Description: Use private endpoints for your Azure Storage accounts to allow clients and services to securely access data located over a network via an encrypted Private Link. To do this, the private endpoint uses an IP address from the VNet for each service. Network traffic between disparate services securely traverses encrypted over the VNet. ID: azure_cis_v200_3_10 -Title: "3.10 Ensure Private Endpoints are used to access Storage Accounts" -Description: "Use private endpoints for your Azure Storage accounts to allow clients and services to securely access data located over a network via an encrypted Private Link. To do this, the private endpoint uses an IP address from the VNet for each service. Network traffic between disparate services securely traverses encrypted over the VNet." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with storage_account_connection as ( - select - distinct a.id - from - azure_storage_account as a, - jsonb_array_elements(private_endpoint_connections) as connection - where - connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' - ) - select - distinct a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when s.id is null then 'alarm' - else 'ok' - end as status, - case - when s.id is null then a.name || ' not uses private link.' - else a.name || ' uses private link.' - end as reason - from - azure_storage_account as a - left join storage_account_connection as s on a.id = s.id, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + WITH storage_account_connection AS ( + SELECT DISTINCT + a.id + FROM + azure_storage_account AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT DISTINCT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN s.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason + FROM + azure_storage_account AS a + LEFT JOIN + storage_account_connection AS s ON a.id = s.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.10 Ensure Private Endpoints are used to access Storage Accounts \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_11.yaml b/compliance/controls/azure/azure_cis_v200_3_11.yaml old mode 100755 new mode 100644 index 3eebbefc4..17172b776 --- a/compliance/controls/azure/azure_cis_v200_3_11.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_11.yaml @@ -1,32 +1,32 @@ +Description: The Azure Storage blobs contain data like ePHI or Financial, which can be secret or personal. Data that is erroneously modified or deleted by an application or other storage account user will cause data loss or unavailability. ID: azure_cis_v200_3_11 -Title: "3.11 Ensure Soft Delete is Enabled for Azure Containers and Blob Storage" -Description: "The Azure Storage blobs contain data like ePHI or Financial, which can be secret or personal. Data that is erroneously modified or deleted by an application or other storage account user will cause data loss or unavailability." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not blob_soft_delete_enabled then 'alarm' - else 'ok' - end as status, - case - when not blob_soft_delete_enabled then sa.name || ' blobs soft delete disabled.' - else sa.name || ' blobs soft delete enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT blob_soft_delete_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT blob_soft_delete_enabled THEN sa.name || ' blobs soft delete disabled.' + ELSE sa.name || ' blobs soft delete enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.11 Ensure Soft Delete is Enabled for Azure Containers and Blob Storage \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_12.yaml b/compliance/controls/azure/azure_cis_v200_3_12.yaml old mode 100755 new mode 100644 index b1f9e0910..2b7d4d661 --- a/compliance/controls/azure/azure_cis_v200_3_12.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_12.yaml @@ -1,32 +1,32 @@ +Description: Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys. ID: azure_cis_v200_3_12 -Title: "3.12 Ensure Storage for Critical Data are Encrypted with Customer Managed Keys" -Description: "Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when sa.encryption_key_source = 'Microsoft.Storage' then 'alarm' - else 'ok' - end as status, - case - when sa.encryption_key_source = 'Microsoft.Storage' then sa.name || ' not encrypted with CMK.' - else sa.name || ' encrypted with CMK.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN sa.name || ' not encrypted with CMK.' + ELSE sa.name || ' encrypted with CMK.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.12 Ensure Storage for Critical Data are Encrypted with Customer Managed Keys \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_14.yaml b/compliance/controls/azure/azure_cis_v200_3_14.yaml old mode 100755 new mode 100644 index 997150353..1ddcdaafb --- a/compliance/controls/azure/azure_cis_v200_3_14.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_14.yaml @@ -1,38 +1,38 @@ +Description: 'Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.' ID: azure_cis_v200_3_14 -Title: "3.14 Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' Requests" -Description: "Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when table_logging_write and table_logging_read and table_logging_delete then 'ok' - else 'alarm' - end as status, - case - when table_logging_write and table_logging_read and table_logging_delete - then sa.name || ' table service logging enabled for read, write, delete requests.' - else sa.name || ' table service logging not enabled for: ' || - concat_ws(', ', - case when not table_logging_write then 'write' end, - case when not table_logging_read then 'read' end, - case when not table_logging_delete then 'delete' end - ) || ' requests.' - end as reason - from - azure_storage_account as sa, - azure_subscription as sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN table_logging_write AND table_logging_read AND table_logging_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN table_logging_write AND table_logging_read AND table_logging_delete + THEN sa.name || ' table service logging enabled for read, write, delete requests.' + ELSE sa.name || ' table service logging not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT table_logging_write THEN 'write' END, + CASE WHEN NOT table_logging_read THEN 'read' END, + CASE WHEN NOT table_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.14 Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' Requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_15.yaml b/compliance/controls/azure/azure_cis_v200_3_15.yaml old mode 100755 new mode 100644 index b37abd9f2..b42b9191d --- a/compliance/controls/azure/azure_cis_v200_3_15.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_15.yaml @@ -1,34 +1,34 @@ +Description: In some cases, Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2. ID: azure_cis_v200_3_15 -Title: "3.15 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2'" -Description: "In some cases, Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when minimum_tls_version = 'TLSEnforcementDisabled' then 'alarm' - when minimum_tls_version = 'TLS1_2' then 'ok' - else 'alarm' - end as status, - case - when minimum_tls_version = 'TLSEnforcementDisabled' then sa.name || ' TLS enforcement is disabled.' - when minimum_tls_version = 'TLS1_2' then sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' - else sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN minimum_tls_version = 'TLSEnforcementDisabled' THEN 'alarm' + WHEN minimum_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_tls_version = 'TLSEnforcementDisabled' THEN sa.name || ' TLS enforcement is disabled.' + WHEN minimum_tls_version = 'TLS1_2' THEN sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + ELSE sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.15 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_2.yaml b/compliance/controls/azure/azure_cis_v200_3_2.yaml old mode 100755 new mode 100644 index 825f6c2a6..4d611551a --- a/compliance/controls/azure/azure_cis_v200_3_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_2.yaml @@ -1,32 +1,32 @@ +Description: Enabling encryption at the hardware level on top of the default software encryption for Storage Accounts accessing Azure storage solutions. ID: azure_cis_v200_3_2 -Title: "3.2 Ensure that 'Enable Infrastructure Encryption' for Each Storage Account in Azure Storage is Set to 'enabled'" -Description: "Enabling encryption at the hardware level on top of the default software encryption for Storage Accounts accessing Azure storage solutions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when require_infrastructure_encryption then 'ok' - else 'alarm' - end as status, - case - when require_infrastructure_encryption then name || ' infrastructure encryption enabled.' - else name || ' infrastructure encryption disabled.' - end as reason - from - azure_storage_account as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN require_infrastructure_encryption THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN require_infrastructure_encryption THEN name || ' infrastructure encryption enabled.' + ELSE name || ' infrastructure encryption disabled.' + END AS reason + FROM + azure_storage_account AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.2 Ensure that 'Enable Infrastructure Encryption' for Each Storage Account in Azure Storage is Set to 'enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_3.yaml b/compliance/controls/azure/azure_cis_v200_3_3.yaml old mode 100755 new mode 100644 index c3d9fa220..45205c711 --- a/compliance/controls/azure/azure_cis_v200_3_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_3.yaml @@ -1,24 +1,24 @@ +Description: Access Keys authenticate application access requests to data contained in Storage Accounts. A periodic rotation of these keys is recommended to ensure that potentially compromised keys cannot result in a long-term exploitable credential. The 'Rotation Reminder' is an automatic reminder feature for a manual procedure. ID: azure_cis_v200_3_3 -Title: "3.3 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account" -Description: "Access Keys authenticate application access requests to data contained in Storage Accounts. A periodic rotation of these keys is recommended to ensure that potentially compromised keys cannot result in a long-term exploitable credential. The 'Rotation Reminder' is an automatic reminder feature for a manual procedure." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.3 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_4.yaml b/compliance/controls/azure/azure_cis_v200_3_4.yaml old mode 100755 new mode 100644 index b87f53edd..d1714cefc --- a/compliance/controls/azure/azure_cis_v200_3_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_4.yaml @@ -1,24 +1,24 @@ +Description: For increased security, regenerate storage account access keys periodically. ID: azure_cis_v200_3_4 -Title: "3.4 Ensure that Storage Account Access Keys are Periodically Regenerated" -Description: "For increased security, regenerate storage account access keys periodically." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.4 Ensure that Storage Account Access Keys are Periodically Regenerated \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_5.yaml b/compliance/controls/azure/azure_cis_v200_3_5.yaml old mode 100755 new mode 100644 index 4d9a36396..f1fd47647 --- a/compliance/controls/azure/azure_cis_v200_3_5.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_5.yaml @@ -1,38 +1,38 @@ +Description: The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. ID: azure_cis_v200_3_5 -Title: "3.5 Ensure Storage Logging is Enabled for Queue Service for 'Read', 'Write', and 'Delete' requests" -Description: "The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when queue_logging_read and queue_logging_write and queue_logging_delete then 'ok' - else 'alarm' - end as status, - case - when queue_logging_read and queue_logging_write and queue_logging_delete - then sa.name || ' queue service logging enabled for read, write, delete requests.' - else sa.name || ' queue service logging not enabled for: ' || - concat_ws(', ', - case when not queue_logging_write then 'write' end, - case when not queue_logging_read then 'read' end, - case when not queue_logging_delete then 'delete' end - ) || ' requests.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete + THEN sa.name || ' queue service logging enabled for read, write, delete requests.' + ELSE sa.name || ' queue service logging not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT queue_logging_write THEN 'write' END, + CASE WHEN NOT queue_logging_read THEN 'read' END, + CASE WHEN NOT queue_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.5 Ensure Storage Logging is Enabled for Queue Service for 'Read', 'Write', and 'Delete' requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_6.yaml b/compliance/controls/azure/azure_cis_v200_3_6.yaml old mode 100755 new mode 100644 index 0067bedeb..00f1c0b00 --- a/compliance/controls/azure/azure_cis_v200_3_6.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_6.yaml @@ -1,24 +1,24 @@ +Description: Expire shared access signature tokens within an hour. ID: azure_cis_v200_3_6 -Title: "3.6 Ensure that Shared Access Signature Tokens Expire Within an Hour" -Description: "Expire shared access signature tokens within an hour." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.6 Ensure that Shared Access Signature Tokens Expire Within an Hour \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_8.yaml b/compliance/controls/azure/azure_cis_v200_3_8.yaml old mode 100755 new mode 100644 index 8bceddcbb..55d781b37 --- a/compliance/controls/azure/azure_cis_v200_3_8.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_8.yaml @@ -1,32 +1,32 @@ +Description: Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed. ID: azure_cis_v200_3_8 -Title: "3.8 Ensure Default Network Access Rule for Storage Accounts is Set to Deny" -Description: "Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when sa.network_rule_default_action = 'Allow' then 'alarm' - else 'ok' - end as status, - case - when sa.network_rule_default_action = 'Allow' then name || ' allows traffic from all networks.' - else name || ' allows traffic from specific networks.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN name || ' allows traffic from all networks.' + ELSE name || ' allows traffic from specific networks.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.8 Ensure Default Network Access Rule for Storage Accounts is Set to Deny \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_3_9.yaml b/compliance/controls/azure/azure_cis_v200_3_9.yaml old mode 100755 new mode 100644 index 390d718b8..5a19b5642 --- a/compliance/controls/azure/azure_cis_v200_3_9.yaml +++ b/compliance/controls/azure/azure_cis_v200_3_9.yaml @@ -1,32 +1,32 @@ +Description: Some Azure services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account. ID: azure_cis_v200_3_9 -Title: "3.9 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access" -Description: "Some Azure services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when network_rule_bypass not like '%AzureServices%' then 'alarm' - else 'ok' - end as status, - case - when network_rule_bypass not like '%AzureServices%' then sa.name || ' trusted Microsoft services not enabled.' - else sa.name || ' trusted Microsoft services enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN sa.name || ' trusted Microsoft services not enabled.' + ELSE sa.name || ' trusted Microsoft services enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.9 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_1_2.yaml b/compliance/controls/azure/azure_cis_v200_4_1_2.yaml old mode 100755 new mode 100644 index 9784dbc70..4056d787c --- a/compliance/controls/azure/azure_cis_v200_4_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_1_2.yaml @@ -1,36 +1,36 @@ +Description: Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP). ID: azure_cis_v200_4_1_2 -Title: "4.1.2 Ensure no Azure SQL Databases allow ingress from 0.0.0.0/0 (ANY IP)" -Description: "Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' - or firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' - then 'alarm' - else 'ok' - end as status, - case - when firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' - or firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' - then s.title || ' allows ingress 0.0.0.0/0 or any ip over internet.' - else s.title || ' not allows ingress 0.0.0.0/0 or any ip over internet.' - end as reason - from - azure_sql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN s.title || ' allows ingress 0.0.0.0/0 or any IP over internet.' + ELSE s.title || ' does not allow ingress 0.0.0.0/0 or any IP over internet.' + END AS reason + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.2 Ensure no Azure SQL Databases allow ingress from 0.0.0.0/0 (ANY IP) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_1_4.yaml b/compliance/controls/azure/azure_cis_v200_4_1_4.yaml old mode 100755 new mode 100644 index 19ed96d1a..7e4a68e37 --- a/compliance/controls/azure/azure_cis_v200_4_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_1_4.yaml @@ -1,32 +1,32 @@ +Description: Use Azure Active Directory Authentication for authentication with SQL Database to manage credentials in a single place. ID: azure_cis_v200_4_1_4 -Title: "4.1.4 Ensure that Azure Active Directory Admin is Configured for SQL Servers" -Description: "Use Azure Active Directory Authentication for authentication with SQL Database to manage credentials in a single place." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when server_azure_ad_administrator is null then 'alarm' - else 'ok' - end as status, - case - when server_azure_ad_administrator is null then name || ' Azure AD authentication not configured.' - else name || ' Azure AD authentication configured.' - end as reason - from - azure_sql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN server_azure_ad_administrator IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN server_azure_ad_administrator IS NULL THEN name || ' Azure AD authentication not configured.' + ELSE name || ' Azure AD authentication configured.' + END AS reason + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.4 Ensure that Azure Active Directory Admin is Configured for SQL Servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_3_1.yaml b/compliance/controls/azure/azure_cis_v200_4_3_1.yaml old mode 100755 new mode 100644 index 95617e4e6..b18a89b32 --- a/compliance/controls/azure/azure_cis_v200_4_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_3_1.yaml @@ -1,32 +1,32 @@ +Description: Enable SSL connection on PostgreSQL Servers. ID: azure_cis_v200_4_3_1 -Title: "4.3.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for PostgreSQL Database Server" -Description: "Enable SSL connection on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when ssl_enforcement = 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when ssl_enforcement = 'Disabled' then name || ' SSL connection disabled.' - else name || ' SSL connection enabled.' - end as reason - from - azure_postgresql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN name || ' SSL connection disabled.' + ELSE name || ' SSL connection enabled.' + END AS reason + FROM + azure_postgresql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_3_5.yaml b/compliance/controls/azure/azure_cis_v200_4_3_5.yaml old mode 100755 new mode 100644 index 8c11484ee..5488e1f57 --- a/compliance/controls/azure/azure_cis_v200_4_3_5.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_3_5.yaml @@ -1,34 +1,34 @@ +Description: Enable connection_throttling on PostgreSQL Servers. ID: azure_cis_v200_4_3_5 -Title: "4.3.5 Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable connection_throttling on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm' - else 'ok' - end as status, - case - when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter connection_throttling off.' - else s.name || ' server parameter connection_throttling on.' - end as reason - from - azure_postgresql_server s, - jsonb_array_elements(server_configurations) config, - azure_subscription sub - where - config ->> 'Name' = 'connection_throttling' - and sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter connection_throttling off.' + ELSE s.name || ' server parameter connection_throttling on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'connection_throttling' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.5 Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_3_7.yaml b/compliance/controls/azure/azure_cis_v200_4_3_7.yaml old mode 100755 new mode 100644 index 9f0813480..d43f7cf8f --- a/compliance/controls/azure/azure_cis_v200_4_3_7.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_3_7.yaml @@ -1,43 +1,44 @@ +Description: Disable access from Azure services to PostgreSQL Database Server. ID: azure_cis_v200_4_3_7 -Title: "4.3.7 Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled" -Description: "Disable access from Azure services to PostgreSQL Database Server." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with postgres_db_with_allow_access_to_azure_services as ( - select + ListOfTables: + - azure_postgresql_server + - azure_subscription + Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + WITH postgres_db_with_allow_access_to_azure_services AS ( + SELECT id - from + FROM azure_postgresql_server, - jsonb_array_elements(firewall_rules) as r - where + JSONB_ARRAY_ELEMENTS(firewall_rules) AS r + WHERE r -> 'FirewallRuleProperties' ->> 'endIpAddress' = '0.0.0.0' - and r -> 'FirewallRuleProperties' ->> 'startIpAddress' = '0.0.0.0' + AND r -> 'FirewallRuleProperties' ->> 'startIpAddress' = '0.0.0.0' ) - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when a.id is not null then 'alarm' - else 'ok' - end as status, - case - when a.id is not null then s.title || ' does not restrict access to azure services.' - else s.title || ' restricts access to azure services.' - end as reason - from - azure_postgresql_server as s - left join postgres_db_with_allow_access_to_azure_services as a on a.id = s.id, - azure_subscription as sub - where + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN a.id IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.id IS NOT NULL THEN s.title || ' does not restrict access to azure services.' + ELSE s.title || ' restricts access to azure services.' + END AS reason + FROM + azure_postgresql_server AS s + LEFT JOIN postgres_db_with_allow_access_to_azure_services AS a + ON a.id = s.id, + azure_subscription AS sub + WHERE sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server - ListOfTables: - - azure_postgresql_server - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.7 Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_3_8.yaml b/compliance/controls/azure/azure_cis_v200_4_3_8.yaml old mode 100755 new mode 100644 index 7a464e0e8..edb16b2ef --- a/compliance/controls/azure/azure_cis_v200_4_3_8.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_3_8.yaml @@ -1,32 +1,32 @@ +Description: Azure Database for PostgreSQL servers should be created with 'infrastructure double encryption' enabled. ID: azure_cis_v200_4_3_8 -Title: "4.3.8 Ensure 'Infrastructure double encryption' for PostgreSQL Database Server is 'Enabled'" -Description: "Azure Database for PostgreSQL servers should be created with 'infrastructure double encryption' enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when infrastructure_encryption = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when infrastructure_encryption = 'Enabled' then name || ' infrastructure encryption enabled.' - else name || ' infrastructure encryption disabled.' - end as reason - from - azure_postgresql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN name || ' infrastructure encryption enabled.' + ELSE name || ' infrastructure encryption disabled.' + END AS reason + FROM + azure_postgresql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.8 Ensure 'Infrastructure double encryption' for PostgreSQL Database Server is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_4_1.yaml b/compliance/controls/azure/azure_cis_v200_4_4_1.yaml old mode 100755 new mode 100644 index 4d024520a..216188118 --- a/compliance/controls/azure/azure_cis_v200_4_4_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_4_1.yaml @@ -1,15 +1,32 @@ +Description: Enable SSL connection on MySQL Servers. ID: azure_cis_v200_4_4_1 -Title: "4.4.1 Ensure 'Enforce SSL connection' is set to 'Enabled' for Standard MySQL Database Server" -Description: "Enable SSL connection on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when ssl_enforcement = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when ssl_enforcement = 'Disabled' then s.name || ' SSL connection disabled.'\n else s.name || ' SSL connection enabled.'\n end as reason\n \nfrom\n azure_mysql_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;" - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN s.name || ' SSL connection disabled.' + ELSE s.name || ' SSL connection enabled.' + END AS reason + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.1 Ensure 'Enforce SSL connection' is set to 'Enabled' for Standard MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_4_2.yaml b/compliance/controls/azure/azure_cis_v200_4_4_2.yaml old mode 100755 new mode 100644 index 1f0f5bbd2..aa90bfc5e --- a/compliance/controls/azure/azure_cis_v200_4_4_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_4_2.yaml @@ -1,34 +1,34 @@ +Description: Ensure TLS version on MySQL flexible servers is set to the default value. ID: azure_cis_v200_4_4_2 -Title: "4.4.2 Ensure 'TLS Version' is set to 'TLSV1.2' for MySQL flexible Database Server" -Description: "Ensure TLS version on MySQL flexible servers is set to the default value." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when minimal_tls_version = 'TLSEnforcementDisabled' then 'alarm' - when minimal_tls_version = 'TLS1_2' then 'ok' - else 'alarm' - end as status, - case - when minimal_tls_version = 'TLSEnforcementDisabled' then s.name || ' TLS enforcement is disabled.' - when minimal_tls_version = 'TLS1_2' then s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' - else s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' - end as reason - from - azure_mysql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN minimal_tls_version = 'TLSEnforcementDisabled' THEN 'alarm' + WHEN minimal_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimal_tls_version = 'TLSEnforcementDisabled' THEN s.name || ' TLS enforcement is disabled.' + WHEN minimal_tls_version = 'TLS1_2' THEN s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' + ELSE s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' + END AS reason + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.2 Ensure 'TLS Version' is set to 'TLSV1.2' for MySQL flexible Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_5_1.yaml b/compliance/controls/azure/azure_cis_v200_4_5_1.yaml old mode 100755 new mode 100644 index 75ce001d1..2e4412d6a --- a/compliance/controls/azure/azure_cis_v200_4_5_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_5_1.yaml @@ -1,34 +1,34 @@ +Description: Limiting your Cosmos DB to only communicate on whitelisted networks lowers its attack footprint. ID: azure_cis_v200_4_5_1 -Title: "4.5.1 Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks" -Description: "Limiting your Cosmos DB to only communicate on whitelisted networks lowers its attack footprint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when public_network_access = 'Disabled' then 'ok' - when public_network_access = 'Enabled' and is_virtual_network_filter_enabled = 'true' then 'ok' - else 'alarm' - end as status, - case - when public_network_access = 'Disabled' then a.name || ' public network access disabled.' - when public_network_access = 'Enabled' and is_virtual_network_filter_enabled = 'true' then a.name || ' virtual network filter enabled.' - else a.name || ' virtual network filter disabled.' - end as reason - from - azure_cosmosdb_account as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Disabled' THEN 'ok' + WHEN public_network_access = 'Enabled' AND is_virtual_network_filter_enabled = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN public_network_access = 'Disabled' THEN a.name || ' public network access disabled.' + WHEN public_network_access = 'Enabled' AND is_virtual_network_filter_enabled = 'true' THEN a.name || ' virtual network filter enabled.' + ELSE a.name || ' virtual network filter disabled.' + END AS reason + FROM + azure_cosmosdb_account AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.5.1 Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_5_2.yaml b/compliance/controls/azure/azure_cis_v200_4_5_2.yaml old mode 100755 new mode 100644 index af1d7134e..8e99237f9 --- a/compliance/controls/azure/azure_cis_v200_4_5_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_5_2.yaml @@ -1,42 +1,42 @@ +Description: Private endpoints limit network traffic to approved sources. ID: azure_cis_v200_4_5_2 -Title: "4.5.2 Ensure That Private Endpoints Are Used Where Possible" -Description: "Private endpoints limit network traffic to approved sources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with cosmosdb_private_connection as ( - select - distinct a.id - from - azure_cosmosdb_account as a, - jsonb_array_elements(private_endpoint_connections) as connection - where - connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' - ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when c.id is null then 'alarm' - else 'ok' - end as status, - case - when c.id is null then a.name || ' not uses private link.' - else a.name || ' uses private link.' - end as reason - from - azure_cosmosdb_account as a - left join cosmosdb_private_connection as c on c.id = a.id, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + WITH cosmosdb_private_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_cosmosdb_account AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason + FROM + azure_cosmosdb_account AS a + LEFT JOIN cosmosdb_private_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.5.2 Ensure That Private Endpoints Are Used Where Possible \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_4_5_3.yaml b/compliance/controls/azure/azure_cis_v200_4_5_3.yaml old mode 100755 new mode 100644 index 5c0ea76b5..0b8a4d2e0 --- a/compliance/controls/azure/azure_cis_v200_4_5_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_4_5_3.yaml @@ -1,24 +1,24 @@ +Description: Cosmos DB can use tokens or AAD for client authentication which in turn will use Azure RBAC for authorization. Using AAD is significantly more secure because AAD handles the credentials and allows for MFA and centralized management, and the Azure RBAC better integrated with the rest of Azure. ID: azure_cis_v200_4_5_3 -Title: "4.5.3 Use Azure Active Directory (AAD) Client Authentication and Azure RBAC where possible" -Description: "Cosmos DB can use tokens or AAD for client authentication which in turn will use Azure RBAC for authorization. Using AAD is significantly more secure because AAD handles the credentials and allows for MFA and centralized management, and the Azure RBAC better integrated with the rest of Azure." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 4.5.3 Use Azure Active Directory (AAD) Client Authentication and Azure RBAC where possible \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_1_1.yaml b/compliance/controls/azure/azure_cis_v200_5_1_1.yaml old mode 100755 new mode 100644 index 48427568e..08d7d2ece --- a/compliance/controls/azure/azure_cis_v200_5_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_1_1.yaml @@ -1,24 +1,24 @@ +Description: Enable Diagnostic settings for exporting activity logs. Diagnostic settings are available for each individual resource within a subscription. Settings should be configured for all appropriate resources for your environment. ID: azure_cis_v200_5_1_1 -Title: "5.1.1 Ensure that a 'Diagnostic Setting' exists" -Description: "Enable Diagnostic settings for exporting activity logs. Diagnostic settings are available for each individual resource within a subscription. Settings should be configured for all appropriate resources for your environment." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.1 Ensure that a 'Diagnostic Setting' exists \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_1_2.yaml b/compliance/controls/azure/azure_cis_v200_5_1_2.yaml old mode 100755 new mode 100644 index c6486abea..27bf9f7ce --- a/compliance/controls/azure/azure_cis_v200_5_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_1_2.yaml @@ -1,28 +1,32 @@ +Description: 'A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: ''Ensure that a ''Diagnostic Setting'' exists.'' The diagnostic setting should be configured to log the appropriate activities from the control/management plane.' ID: azure_cis_v200_5_1_2 -Title: "5.1.2 Ensure Diagnostic Setting captures appropriate categories" -Description: "A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: 'Ensure that a 'Diagnostic Setting' exists.' The diagnostic setting should be configured to log the appropriate activities from the control/management plane." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with enabled_settings as ( - select + ListOfTables: + - azure_diagnostic_setting + - azure_subscription + Parameters: [] + PrimaryTable: azure_diagnostic_setting + QueryToExecute: | + WITH enabled_settings AS ( + SELECT name, id, _ctx, resource_group, subscription_id, - count(*) filter (where l ->> 'enabled' = 'true' - and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy') - ) as valid_category_count, - string_agg(l ->> 'category', ', ') filter (where l ->> 'enabled' = 'true' - and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy') - ) as valid_categories, + COUNT(*) FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy')) AS valid_category_count, + STRING_AGG(l ->> 'category', ', ') FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy')) AS valid_categories, og_account_id, og_resource_id - from + FROM azure_diagnostic_setting, - jsonb_array_elements(logs) as l - group by + jsonb_array_elements(logs) AS l + GROUP BY name, id, _ctx, @@ -31,32 +35,26 @@ Query: og_account_id, og_resource_id ) - select - sett.id as resource, - sett.og_account_id as og_account_id, - sett.og_resource_id as og_resource_id, - case - when valid_category_count = 4 then 'ok' - else 'alarm' - end as status, - case - when valid_category_count = 4 - then name || ' logs enabled for required categories administrative, security, alert and policy.' - when valid_category_count > 0 - then sett.name || ' logs enabled for ' || valid_categories || ' categories.' - else sett.name || ' logs not enabled for categories administrative, security, alert and policy.' - end as reason - from + SELECT + sett.id AS resource, + sett.og_account_id AS og_account_id, + sett.og_resource_id AS og_resource_id, + CASE + WHEN valid_category_count = 4 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN valid_category_count = 4 + THEN name || ' logs enabled for required categories administrative, security, alert and policy.' + WHEN valid_category_count > 0 + THEN sett.name || ' logs enabled for ' || valid_categories || ' categories.' + ELSE sett.name || ' logs not enabled for categories administrative, security, alert and policy.' + END AS reason + FROM enabled_settings sett, azure_subscription sub - where + WHERE sub.subscription_id = sett.subscription_id; - PrimaryTable: azure_diagnostic_setting - ListOfTables: - - azure_diagnostic_setting - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.2 Ensure Diagnostic Setting captures appropriate categories \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_1_3.yaml b/compliance/controls/azure/azure_cis_v200_5_1_3.yaml old mode 100755 new mode 100644 index 6cd619453..e7ef76316 --- a/compliance/controls/azure/azure_cis_v200_5_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_1_3.yaml @@ -1,34 +1,34 @@ +Description: The storage account container containing the activity log export should not be publicly accessible. ID: azure_cis_v200_5_1_3 -Title: "5.1.3 Ensure the Storage Container Storing the Activity Logs is not Publicly Accessible" -Description: "The storage account container containing the activity log export should not be publicly accessible." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc.id as resource, - sc.og_account_id as og_account_id, - sc.og_resource_id as og_resource_id, - case - when public_access != 'None' then 'alarm' - else 'ok' - end as status, - case - when public_access != 'None' - then account_name || ' container insights-activity-logs storing activity logs publicly accessible.' - else account_name || ' container insights-activity-logs storing activity logs not publicly accessible.' - end as reason - from - azure_storage_container sc, - azure_subscription sub - where - name = 'insights-activity-logs' - and sub.subscription_id = sc.subscription_id; - PrimaryTable: azure_storage_container ListOfTables: - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_container + QueryToExecute: | + SELECT + sc.id AS resource, + sc.og_account_id AS og_account_id, + sc.og_resource_id AS og_resource_id, + CASE + WHEN public_access != 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_access != 'None' + THEN account_name || ' container insights-activity-logs storing activity logs publicly accessible.' + ELSE account_name || ' container insights-activity-logs storing activity logs not publicly accessible.' + END AS reason + FROM + azure_storage_container sc, + azure_subscription sub + WHERE + name = 'insights-activity-logs' + AND sub.subscription_id = sc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.3 Ensure the Storage Container Storing the Activity Logs is not Publicly Accessible \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_1_5.yaml b/compliance/controls/azure/azure_cis_v200_5_1_5.yaml old mode 100755 new mode 100644 index b7a350191..12b94c182 --- a/compliance/controls/azure/azure_cis_v200_5_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_1_5.yaml @@ -1,49 +1,49 @@ +Description: Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available. ID: azure_cis_v200_5_1_5 -Title: "5.1.5 Ensure that logging for Azure Key Vault is 'Enabled'" -Description: "Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with logging_details as ( - select - name as key_vault_name - from + ListOfTables: + - azure_key_vault + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + WITH logging_details AS ( + SELECT + name AS key_vault_name + FROM azure_key_vault, jsonb_array_elements(diagnostic_settings) setting, jsonb_array_elements(setting -> 'properties' -> 'logs') log - where - diagnostic_settings is not null - and setting -> 'properties' ->> 'storageAccountId' <> '' - and (log ->> 'enabled') :: boolean - and log ->> 'category' = 'AuditEvent' - and (log -> 'retentionPolicy') :: JSONB ? 'days' + WHERE + diagnostic_settings IS NOT NULL + AND setting -> 'properties' ->> 'storageAccountId' <> '' + AND (log ->> 'enabled')::BOOLEAN + AND log ->> 'category' = 'AuditEvent' + AND (log -> 'retentionPolicy')::JSONB ? 'days' ) - select - v.id as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when v.diagnostic_settings is null then 'alarm' - when l.key_vault_name not like concat('%', v.name, '%') then 'alarm' - else 'ok' - end as status, - case - when v.diagnostic_settings is null then v.name || ' logging not enabled.' - when l.key_vault_name not like concat('%', v.name, '%') then v.name || ' logging not enabled.' - else v.name || ' logging enabled.' - end as reason - from + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason + FROM azure_key_vault v, logging_details l, azure_subscription sub - where + WHERE sub.subscription_id = v.subscription_id; - PrimaryTable: azure_key_vault - ListOfTables: - - azure_key_vault - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.5 Ensure that logging for Azure Key Vault is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_1_6.yaml b/compliance/controls/azure/azure_cis_v200_5_1_6.yaml old mode 100755 new mode 100644 index b1a416920..9a0e806a4 --- a/compliance/controls/azure/azure_cis_v200_5_1_6.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_1_6.yaml @@ -1,24 +1,24 @@ +Description: Ensure that network flow logs are captured and fed into a central log analytics workspace. ID: azure_cis_v200_5_1_6 -Title: "5.1.6 Ensure that Network Security Group Flow logs are captured and sent to Log Analytics" -Description: "Ensure that network flow logs are captured and fed into a central log analytics workspace." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.6 Ensure that Network Security Group Flow logs are captured and sent to Log Analytics \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_1_7.yaml b/compliance/controls/azure/azure_cis_v200_5_1_7.yaml old mode 100755 new mode 100644 index 2fc8e9c38..b962e46f6 --- a/compliance/controls/azure/azure_cis_v200_5_1_7.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_1_7.yaml @@ -1,24 +1,24 @@ +Description: Enable AppServiceHTTPLogs diagnostic log category for Azure App Service instances to ensure all http requests are captured and centrally logged. ID: azure_cis_v200_5_1_7 -Title: "5.1.7 Ensure that logging for Azure AppService 'HTTP logs' is enabled" -Description: "Enable AppServiceHTTPLogs diagnostic log category for Azure App Service instances to ensure all http requests are captured and centrally logged." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.7 Ensure that logging for Azure AppService 'HTTP logs' is enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_2_1.yaml b/compliance/controls/azure/azure_cis_v200_5_2_1.yaml old mode 100755 new mode 100644 index 02bd3cd9f..5620bfd0c --- a/compliance/controls/azure/azure_cis_v200_5_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_2_1.yaml @@ -1,57 +1,57 @@ +Description: Create an activity log alert for the Create Policy Assignment event. ID: azure_cis_v200_5_2_1 -Title: "5.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment" -Description: "Create an activity log alert for the Create Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id, - alert.og_account_id as og_account_id, - alert.og_resource_id as og_resource_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + alert.og_account_id AS og_account_id, + alert.og_resource_id AS og_resource_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' - limit 1 + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' + LIMIT 1 ) - select - a.subscription_id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create policy assignment event.' - else 'Activity log alert does not exists for create policy assignment event.' - end as reason - from + SELECT + a.subscription_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create policy assignment event.' + ELSE 'Activity log alert does not exist for create policy assignment event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY a.subscription_id, sub.subscription_id, sub._ctx, sub.display_name, a.og_account_id, a.og_resource_id; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_2_10.yaml b/compliance/controls/azure/azure_cis_v200_5_2_10.yaml old mode 100755 new mode 100644 index 81ee5f9d2..f4d52b75a --- a/compliance/controls/azure/azure_cis_v200_5_2_10.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_2_10.yaml @@ -1,64 +1,60 @@ +Description: Create an activity log alert for the Delete Public IP Address rule. ID: azure_cis_v200_5_2_10 -Title: "5.2.10 Ensure that Activity Log Alert exists for Delete Public IP Address rule" -Description: "Create an activity log alert for the Delete Public IP Address rule." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/delete"}]' - ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - ) + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/delete"}]') + OR + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Delete Public IP Address rule.' - else 'Activity Log Alert does not exists for Delete Public IP Address rule.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Delete Public IP Address rule.' + ELSE 'Activity Log Alert does not exist for Delete Public IP Address rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name, sub.og_account_id, sub.og_resource_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.10 Ensure that Activity Log Alert exists for Delete Public IP Address rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_2_2.yaml b/compliance/controls/azure/azure_cis_v200_5_2_2.yaml old mode 100755 new mode 100644 index cee43381f..b1de546d3 --- a/compliance/controls/azure/azure_cis_v200_5_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_2_2.yaml @@ -1,54 +1,54 @@ +Description: Create an activity log alert for the Delete Policy Assignment event. ID: azure_cis_v200_5_2_2 -Title: "5.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment" -Description: "Create an activity log alert for the Delete Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/delete"}]' - limit 1 + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/delete"}]' + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete policy assignment event.' - else 'Activity log alert does not exists for delete policy assignment event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete policy assignment event.' + ELSE 'Activity log alert does not exist for delete policy assignment event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name, sub.og_account_id, sub.og_resource_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_2_3.yaml b/compliance/controls/azure/azure_cis_v200_5_2_3.yaml old mode 100755 new mode 100644 index 1f2df4c6d..a4c817fe4 --- a/compliance/controls/azure/azure_cis_v200_5_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_2_3.yaml @@ -1,64 +1,66 @@ +Description: Create an Activity Log Alert for the Create or Update Network Security Group event. ID: azure_cis_v200_5_2_3 -Title: "5.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group" -Description: "Create an Activity Log Alert for the Create or Update Network Security Group event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Network Security Group event.' - else 'Activity log alert does not exists for create or update Network Security Group event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 + THEN 'Activity log alert exists for create or update Network Security Group event.' + ELSE 'Activity log alert does not exist for create or update Network Security Group event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN + alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name, sub.og_account_id, sub.og_resource_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_2_4.yaml b/compliance/controls/azure/azure_cis_v200_5_2_4.yaml old mode 100755 new mode 100644 index aa3855374..dcf2dd22a --- a/compliance/controls/azure/azure_cis_v200_5_2_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_2_4.yaml @@ -1,66 +1,65 @@ +Description: Create an activity log alert for the Delete Network Security Group event. ID: azure_cis_v200_5_2_4 -Title: "5.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group" -Description: "Create an activity log alert for the Delete Network Security Group event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id, jsonb_array_length(alert.condition -> 'allOf') - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Network Security Group event.' - else 'Activity log alert does not exists for delete Network Security Group event.' - end as reason - - from - azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by - sub._ctx, - sub.subscription_id, - sub.display_name, - sub.og_account_id, - sub.og_resource_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Network Security Group event.' + ELSE 'Activity log alert does not exist for delete Network Security Group event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name, + sub.og_account_id, + sub.og_resource_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_2_5.yaml b/compliance/controls/azure/azure_cis_v200_5_2_5.yaml old mode 100755 new mode 100644 index aec27a8c2..95f515e0a --- a/compliance/controls/azure/azure_cis_v200_5_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_2_5.yaml @@ -1,64 +1,64 @@ +Description: Create an activity log alert for the Create or Update Security Solution event. ID: azure_cis_v200_5_2_5 -Title: "5.2.5 Ensure that Activity Log Alert exists for Create or Update Security Solution" -Description: "Create an activity log alert for the Create or Update Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/write"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/write"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Security Solution event.' - else 'Activity log alert does not exists for create or update Security Solution event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Security Solution event.' + ELSE 'Activity log alert does not exist for create or update Security Solution event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name, sub.og_account_id, sub.og_resource_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.5 Ensure that Activity Log Alert exists for Create or Update Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_2_6.yaml b/compliance/controls/azure/azure_cis_v200_5_2_6.yaml old mode 100755 new mode 100644 index 8855e281f..f53fe62a3 --- a/compliance/controls/azure/azure_cis_v200_5_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_2_6.yaml @@ -1,15 +1,64 @@ +Description: Create an activity log alert for the Delete Security Solution event. ID: azure_cis_v200_5_2_6 -Title: "5.2.6 Ensure that Activity Log Alert exists for Delete Security Solution" -Description: "Create an activity log alert for the Delete Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and (\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Security\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Security/securitySolutions/delete\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Security\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.security/securitysolutions\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Security Solution event.'\n else 'Activity log alert does not exists for delete Security Solution event.'\n end as reason\n \n \nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub._ctx,\n sub.subscription_id,\n sub.display_name,\n sub.og_account_id,\n sub.og_resource_id;" - PrimaryTable: azure_subscription ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/delete"}]' + ) + OR + ( + alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Security Solution event.' + ELSE 'Activity log alert does not exist for delete Security Solution event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.display_name, + sub.og_account_id, + sub.og_resource_id Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.6 Ensure that Activity Log Alert exists for Delete Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_2_7.yaml b/compliance/controls/azure/azure_cis_v200_5_2_7.yaml old mode 100755 new mode 100644 index 8f92a3b32..18292c3c8 --- a/compliance/controls/azure/azure_cis_v200_5_2_7.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_2_7.yaml @@ -1,65 +1,62 @@ +Description: Create an activity log alert for the Create or Update SQL Server Firewall Rule event. ID: azure_cis_v200_5_2_7 -Title: "5.2.7 Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule" -Description: "Create an activity log alert for the Create or Update SQL Server Firewall Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( - select - alert.id as alert_id, - alert.name as alert_name, + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/write"}]' - ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - ) + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/write"}]') + OR + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Create or Update SQL Server Firewall Rule.' - else 'Activity Log Alert does not exists for Create or Update SQL Server Firewall Rule.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Create or Update SQL Server Firewall Rule.' + ELSE 'Activity Log Alert does not exists for Create or Update SQL Server Firewall Rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name, sub.og_account_id, sub.og_resource_id; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.7 Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_2_8.yaml b/compliance/controls/azure/azure_cis_v200_5_2_8.yaml old mode 100755 new mode 100644 index 89660195f..9eca51cc3 --- a/compliance/controls/azure/azure_cis_v200_5_2_8.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_2_8.yaml @@ -1,63 +1,60 @@ +Description: Create an activity log alert for the 'Delete SQL Server Firewall Rule.' ID: azure_cis_v200_5_2_8 -Title: "5.2.8 Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule" -Description: "Create an activity log alert for the 'Delete SQL Server Firewall Rule.'" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/delete"}]' ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - ) + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/delete"}]') + OR + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Delete SQL Server Firewall Rule.' - else 'Activity Log Alert does not exists for Delete SQL Server Firewall Rule.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Delete SQL Server Firewall Rule.' + ELSE 'Activity Log Alert does not exist for Delete SQL Server Firewall Rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name, sub.og_account_id, sub.og_resource_id; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.8 Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_2_9.yaml b/compliance/controls/azure/azure_cis_v200_5_2_9.yaml old mode 100755 new mode 100644 index e94a9af64..b2663f32b --- a/compliance/controls/azure/azure_cis_v200_5_2_9.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_2_9.yaml @@ -1,65 +1,62 @@ +Description: Create an activity log alert for the Create or Update Public IP Addresses rule. ID: azure_cis_v200_5_2_9 -Title: "5.2.9 Ensure that Activity Log Alert exists for Create or Update Public IP Address rule" -Description: "Create an activity log alert for the Create or Update Public IP Addresses rule." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as - ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/write"}]' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/write"}]' ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + OR + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Create or Update Public IP Address rule.' - else 'Activity Log Alert does not exists for Create or Update Public IP Address rule.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Create or Update Public IP Address rule.' + ELSE 'Activity Log Alert does not exists for Create or Update Public IP Address rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.display_name, sub.og_account_id, sub.og_resource_id; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.9 Ensure that Activity Log Alert exists for Create or Update Public IP Address rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_3_1.yaml b/compliance/controls/azure/azure_cis_v200_5_3_1.yaml old mode 100755 new mode 100644 index f382be187..34ef9d813 --- a/compliance/controls/azure/azure_cis_v200_5_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_3_1.yaml @@ -1,15 +1,39 @@ +Description: Application Insights within Azure act as an Application Performance Monitoring solution providing valuable data into how well an application performs and additional information when performing incident response. The types of log data collected include application metrics, telemetry data, and application trace logging data providing organizations with detailed information about application activity and application transactions. ID: azure_cis_v200_5_3_1 -Title: "5.3.1 Ensure Application Insights are Configured" -Description: "Application Insights within Azure act as an Application Performance Monitoring solution providing valuable data into how well an application performs and additional information when performing incident response. The types of log data collected include application metrics, telemetry data, and application trace logging data providing organizations with detailed information about application activity and application transactions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with application_insights as (\n select\n subscription_id,\n count(*) as no_application_insight\n from\n azure_application_insight\n group by\n subscription_id\n)\nselect\n sub.id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when i.subscription_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when i.subscription_id is null then sub.display_name || ' does not have application insights configured.'\n else sub.display_name || ' has ' || no_application_insight || ' application insights configured.'\n end as reason\n \n \nfrom\n azure_subscription as sub\n left join application_insights as i on i.subscription_id = sub.subscription_id;" - PrimaryTable: azure_application_insight ListOfTables: - azure_application_insight - azure_subscription Parameters: [] + PrimaryTable: azure_application_insight + QueryToExecute: | + WITH application_insights AS ( + SELECT + subscription_id, + COUNT(*) AS no_application_insight + FROM + azure_application_insight + GROUP BY + subscription_id + ) + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN i.subscription_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.subscription_id IS NULL THEN sub.display_name || ' does not have application insights configured.' + ELSE sub.display_name || ' has ' || no_application_insight || ' application insights configured.' + END AS reason + FROM + azure_subscription AS sub + LEFT JOIN application_insights AS i ON i.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.3.1 Ensure Application Insights are Configured \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_5_4.yaml b/compliance/controls/azure/azure_cis_v200_5_4.yaml old mode 100755 new mode 100644 index e2db44c18..853552542 --- a/compliance/controls/azure/azure_cis_v200_5_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_5_4.yaml @@ -1,24 +1,24 @@ +Description: Resource Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself; for example, reading or updating a secret from a Key Vault. ID: azure_cis_v200_5_4 -Title: "5.4 Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it" -Description: "Resource Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself; for example, reading or updating a secret from a Key Vault." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.4 Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_6_1.yaml b/compliance/controls/azure/azure_cis_v200_6_1.yaml old mode 100755 new mode 100644 index fe9da8ddc..0e4de5c56 --- a/compliance/controls/azure/azure_cis_v200_6_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_6_1.yaml @@ -1,54 +1,54 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required. ID: azure_cis_v200_6_1 -Title: "6.1 Ensure that RDP access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from - azure_network_security_group nsg, - jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where - sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('3389', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 3389 - and split_part(dport, '-', 2) :: integer >= 3389 - ) - ) - ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts RDP access from internet.' - else sg.title || ' allows RDP access from internet.' - end as reason - from - azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name AS sg_name + FROM + azure_network_security_group AS nsg, + jsonb_array_elements(security_rules) AS sg, + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) AS dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) AS sip + WHERE + sg -> 'properties' ->> 'access' = 'Allow' + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('3389', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1) :: INTEGER <= 3389 + AND split_part(dport, '-', 2) :: INTEGER >= 3389 + ) + ) + ) + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts RDP access from internet.' + ELSE sg.title || ' allows RDP access from internet.' + END AS reason + FROM + azure_network_security_group AS sg + LEFT JOIN network_sg AS nsg ON nsg.sg_name = sg.name + JOIN azure_subscription AS sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.1 Ensure that RDP access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_6_2.yaml b/compliance/controls/azure/azure_cis_v200_6_2.yaml old mode 100755 new mode 100644 index fe0f83774..61a53648e --- a/compliance/controls/azure/azure_cis_v200_6_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_6_2.yaml @@ -1,54 +1,54 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required. ID: azure_cis_v200_6_2 -Title: "6.2 Ensure that SSH access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('22', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 22 - and split_part(dport, '-', 2) :: integer >= 22 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('22', '*') + OR ( + dport LIKE '%-%' + AND SPLIT_PART(dport, '-', 1)::integer <= 22 + AND SPLIT_PART(dport, '-', 2)::integer >= 22 ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts SSH access from internet.' - else sg.title || ' allows SSH access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts SSH access from internet.' + ELSE sg.title || ' allows SSH access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.2 Ensure that SSH access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_6_3.yaml b/compliance/controls/azure/azure_cis_v200_6_3.yaml old mode 100755 new mode 100644 index 66af1288e..88a2e62bf --- a/compliance/controls/azure/azure_cis_v200_6_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_6_3.yaml @@ -1,59 +1,59 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required. ID: azure_cis_v200_6_3 -Title: "6.3 Ensure that UDP access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and sg -> 'properties' ->> 'protocol' = 'UDP' - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' = 'UDP' + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( dport = '*' - or ( - dport like '%-%' - and ( - 53 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 123 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 161 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 389 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 1900 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer + OR ( + dport LIKE '%-%' + AND ( + 53 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 123 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 161 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 389 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 1900 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER ) ) ) ) - select - sg.id as resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts UDP services from internet.' - else sg.title || ' allows UDP services from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts UDP services from internet.' + ELSE sg.title || ' allows UDP services from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.3 Ensure that UDP access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_6_4.yaml b/compliance/controls/azure/azure_cis_v200_6_4.yaml old mode 100755 new mode 100644 index bbe65512e..5ed591e39 --- a/compliance/controls/azure/azure_cis_v200_6_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_6_4.yaml @@ -1,22 +1,28 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured. ID: azure_cis_v200_6_4 -Title: "6.4 Ensure that HTTP(S) access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select distinct - name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT DISTINCT + name AS sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) AS dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and sg -> 'properties' ->> 'protocol' ilike 'TCP' - and sip in + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' ILIKE 'TCP' + AND sip IN ( '*', '0.0.0.0', @@ -26,43 +32,33 @@ Query: '/0', '/0' ) - and + AND ( - dport in - ( - '80', - '*' - ) - or + dport IN ('80', '*') + OR ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 80 - and split_part(dport, '-', 2) :: integer >= 80 + dport LIKE '%-%' + AND split_part(dport, '-', 1)::integer <= 80 + AND split_part(dport, '-', 2)::integer >= 80 ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts HTTPS access from internet.' - else sg.title || ' allows HTTPS access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts HTTPS access from internet.' + ELSE sg.title || ' allows HTTPS access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.4 Ensure that HTTP(S) access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_6_7.yaml b/compliance/controls/azure/azure_cis_v200_6_7.yaml old mode 100755 new mode 100644 index f00662c29..dea6bd602 --- a/compliance/controls/azure/azure_cis_v200_6_7.yaml +++ b/compliance/controls/azure/azure_cis_v200_6_7.yaml @@ -1,24 +1,24 @@ +Description: Public IP Addresses provide tenant accounts with Internet connectivity for resources contained within the tenant. During the creation of certain resources in Azure, a Public IP Address may be created. All Public IP Addresses within the tenant should be periodically reviewed for accuracy and necessity. ID: azure_cis_v200_6_7 -Title: "6.7 Ensure that Public IP addresses are Evaluated on a Periodic Basis" -Description: "Public IP Addresses provide tenant accounts with Internet connectivity for resources contained within the tenant. During the creation of certain resources in Azure, a Public IP Address may be created. All Public IP Addresses within the tenant should be periodically reviewed for accuracy and necessity." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 6.7 Ensure that Public IP addresses are Evaluated on a Periodic Basis \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_7_1.yaml b/compliance/controls/azure/azure_cis_v200_7_1.yaml old mode 100755 new mode 100644 index bcd6082c4..6a0aa1b1b --- a/compliance/controls/azure/azure_cis_v200_7_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_7_1.yaml @@ -1,45 +1,46 @@ +Description: The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service. ID: azure_cis_v200_7_1 -Title: "7.1 Ensure an Azure Bastion Host Exists" -Description: "The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bastion_hosts as ( - select + ListOfTables: + - azure_bastion_host + - azure_subscription + Parameters: [] + PrimaryTable: azure_bastion_host + QueryToExecute: | + WITH bastion_hosts AS ( + SELECT subscription_id, _ctx, region, resource_group, - count(*) as no_bastion_host - from + COUNT(*) AS no_bastion_host + FROM azure_bastion_host - group by + GROUP BY subscription_id, _ctx, resource_group, region ) - select - sub.id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when i.subscription_id is null then 'alarm' - else 'ok' - end as status, - case - when i.subscription_id is null then sub.display_name || ' does not have bastion host.' - else sub.display_name || ' has ' || no_bastion_host || ' bastion host(s).' - end as reason - from - azure_subscription as sub - left join bastion_hosts as i on i.subscription_id = sub.subscription_id; - PrimaryTable: azure_bastion_host - ListOfTables: - - azure_bastion_host - - azure_subscription - Parameters: [] + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN i.subscription_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.subscription_id IS NULL THEN sub.display_name || ' does not have bastion host.' + ELSE sub.display_name || ' has ' || no_bastion_host || ' bastion host(s).' + END AS reason + FROM + azure_subscription AS sub + LEFT JOIN bastion_hosts AS i + ON i.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.1 Ensure an Azure Bastion Host Exists \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_7_2.yaml b/compliance/controls/azure/azure_cis_v200_7_2.yaml old mode 100755 new mode 100644 index 543cab721..f85b9fb4d --- a/compliance/controls/azure/azure_cis_v200_7_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_7_2.yaml @@ -1,32 +1,32 @@ +Description: Migrate blob-based VHDs to Managed Disks on Virtual Machines to exploit the default features of this configuration. ID: azure_cis_v200_7_2 -Title: "7.2 Ensure Virtual Machines are utilizing Managed Disks" -Description: "Migrate blob-based VHDs to Managed Disks on Virtual Machines to exploit the default features of this configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - vm.id as resource, - vm.og_account_id as og_account_id, - vm.og_resource_id as og_resource_id, - case - when managed_disk_id is null then 'alarm' - else 'ok' - end as status, - case - when managed_disk_id is null then vm.name || ' VM not utilizing managed disks.' - else vm.name || ' VM utilizing managed disks.' - end as reason - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where - sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN managed_disk_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN managed_disk_id IS NULL THEN vm.name || ' VM not utilizing managed disks.' + ELSE vm.name || ' VM utilizing managed disks.' + END AS reason + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.2 Ensure Virtual Machines are utilizing Managed Disks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_7_3.yaml b/compliance/controls/azure/azure_cis_v200_7_3.yaml old mode 100755 new mode 100644 index 83b57aed7..3ec92700c --- a/compliance/controls/azure/azure_cis_v200_7_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_7_3.yaml @@ -1,33 +1,33 @@ +Description: Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE or Server Side Encryption(SSE). ID: azure_cis_v200_7_3 -Title: "7.3 Ensure that 'OS and Data' disks are encrypted with Customer Managed Key (CMK)" -Description: "Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE or Server Side Encryption(SSE)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.' - else disk.name || ' not encrypted with CMK.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state = 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state = 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.3 Ensure that 'OS and Data' disks are encrypted with Customer Managed Key (CMK) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_7_4.yaml b/compliance/controls/azure/azure_cis_v200_7_4.yaml old mode 100755 new mode 100644 index 732e7f329..c3121060b --- a/compliance/controls/azure/azure_cis_v200_7_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_7_4.yaml @@ -1,33 +1,33 @@ +Description: Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK). ID: azure_cis_v200_7_4 -Title: "7.4 Ensure that 'Unattached disks' are encrypted with 'Customer Managed Key' (CMK)" -Description: "Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.' - else disk.name || ' not encrypted with CMK.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state != 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state != 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.4 Ensure that 'Unattached disks' are encrypted with 'Customer Managed Key' (CMK) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_7_5.yaml b/compliance/controls/azure/azure_cis_v200_7_5.yaml old mode 100755 new mode 100644 index ee41b413a..4aea23eea --- a/compliance/controls/azure/azure_cis_v200_7_5.yaml +++ b/compliance/controls/azure/azure_cis_v200_7_5.yaml @@ -1,24 +1,24 @@ +Description: For added security, only install organization-approved extensions on VMs. ID: azure_cis_v200_7_5 -Title: "7.5 Ensure that Only Approved Extensions Are Installed" -Description: "For added security, only install organization-approved extensions on VMs." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.5 Ensure that Only Approved Extensions Are Installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_7_6.yaml b/compliance/controls/azure/azure_cis_v200_7_6.yaml old mode 100755 new mode 100644 index af885589b..21ad70ff4 --- a/compliance/controls/azure/azure_cis_v200_7_6.yaml +++ b/compliance/controls/azure/azure_cis_v200_7_6.yaml @@ -1,24 +1,24 @@ +Description: Install endpoint protection for all virtual machines. ID: azure_cis_v200_7_6 -Title: "7.6 Ensure that Endpoint Protection for all Virtual Machines is installed" -Description: "Install endpoint protection for all virtual machines." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.6 Ensure that Endpoint Protection for all Virtual Machines is installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_7_7.yaml b/compliance/controls/azure/azure_cis_v200_7_7.yaml old mode 100755 new mode 100644 index 827d355e5..3de39f58d --- a/compliance/controls/azure/azure_cis_v200_7_7.yaml +++ b/compliance/controls/azure/azure_cis_v200_7_7.yaml @@ -1,24 +1,24 @@ +Description: VHD (Virtual Hard Disks) are stored in blob storage and are the old-style disks that were attached to Virtual Machines. The blob VHD was then leased to the VM. By default, storage accounts are not encrypted, and Microsoft Defender will then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK. This should be turned on for storage accounts containing VHDs. ID: azure_cis_v200_7_7 -Title: "7.7 Ensure that VHDs are Encrypted" -Description: "VHD (Virtual Hard Disks) are stored in blob storage and are the old-style disks that were attached to Virtual Machines. The blob VHD was then leased to the VM. By default, storage accounts are not encrypted, and Microsoft Defender will then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK. This should be turned on for storage accounts containing VHDs." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.7 Ensure that VHDs are Encrypted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_8_1.yaml b/compliance/controls/azure/azure_cis_v200_8_1.yaml old mode 100755 new mode 100644 index d059303e9..92a0ad7e1 --- a/compliance/controls/azure/azure_cis_v200_8_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_8_1.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set. ID: azure_cis_v200_8_1 -Title: "8.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults" -Description: "Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_key_vault + - azure_key_vault_key + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_key QueryToExecute: | - with rbac_vault as ( - select + WITH rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where enable_rbac_authorization + WHERE + enable_rbac_authorization ) - select - kvk.id as resource, - kvk.og_account_id as og_account_id, - kvk.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvk.name || - case - when v.name is null then ' not RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' not RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_key kvk - left join rbac_vault as v on v.name = kvk.vault_name, + LEFT JOIN rbac_vault AS v ON v.name = kvk.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvk.subscription_id; - PrimaryTable: azure_key_vault_key - ListOfTables: - - azure_key_vault - - azure_key_vault_key - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_8_2.yaml b/compliance/controls/azure/azure_cis_v200_8_2.yaml old mode 100755 new mode 100644 index c26544076..d37b1f9ae --- a/compliance/controls/azure/azure_cis_v200_8_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_8_2.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set. ID: azure_cis_v200_8_2 -Title: "8.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults" -Description: "Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with non_rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_key + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + WITH non_rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where not enable_rbac_authorization + WHERE + NOT enable_rbac_authorization ) - select - kvk.id as resource, - kvk.og_account_id as og_account_id, - kvk.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvk.name || - case - when v.name is null then ' RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_key kvk - left join non_rbac_vault as v on v.name = kvk.vault_name, + LEFT JOIN non_rbac_vault AS v ON v.name = kvk.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvk.subscription_id; - PrimaryTable: azure_key_vault_key - ListOfTables: - - azure_key_vault - - azure_key_vault_key - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_8_3.yaml b/compliance/controls/azure/azure_cis_v200_8_3.yaml old mode 100755 new mode 100644 index b6c593879..5c6c8423f --- a/compliance/controls/azure/azure_cis_v200_8_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_8_3.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set. ID: azure_cis_v200_8_3 -Title: "8.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults" -Description: "Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_secret + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + WITH rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where enable_rbac_authorization + WHERE + enable_rbac_authorization ) - select - kvs.id as resource, - kvs.og_account_id as og_account_id, - kvs.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvs.name || - case - when v.name is null then ' not RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' not RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_secret kvs - left join rbac_vault as v on v.name = kvs.vault_name, + LEFT JOIN rbac_vault AS v ON v.name = kvs.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvs.subscription_id; - PrimaryTable: azure_key_vault_secret - ListOfTables: - - azure_key_vault - - azure_key_vault_secret - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_8_4.yaml b/compliance/controls/azure/azure_cis_v200_8_4.yaml old mode 100755 new mode 100644 index e19bd0280..b44fe0438 --- a/compliance/controls/azure/azure_cis_v200_8_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_8_4.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set. ID: azure_cis_v200_8_4 -Title: "8.4 Ensure that the Expiration Date is set for all Secrets in Non- RBAC Key Vaults" -Description: "Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with non_rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_secret + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + WITH non_rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where not enable_rbac_authorization + WHERE + NOT enable_rbac_authorization ) - select - kvs.id as resource, - kvs.og_account_id as og_account_id, - kvs.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvs.name || - case - when v.name is null then ' RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_secret kvs - left join non_rbac_vault as v on v.name = kvs.vault_name, + LEFT JOIN non_rbac_vault AS v ON v.name = kvs.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvs.subscription_id; - PrimaryTable: azure_key_vault_secret - ListOfTables: - - azure_key_vault - - azure_key_vault_secret - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.4 Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_8_5.yaml b/compliance/controls/azure/azure_cis_v200_8_5.yaml old mode 100755 new mode 100644 index 5eef3e2ae..c6e8cd883 --- a/compliance/controls/azure/azure_cis_v200_8_5.yaml +++ b/compliance/controls/azure/azure_cis_v200_8_5.yaml @@ -1,34 +1,34 @@ +Description: The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the "Do Not Purge" and "Soft Delete" functions. ID: azure_cis_v200_8_5 -Title: "8.5 Ensure the Key Vault is Recoverable" -Description: "The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the \\\"Do Not Purge\\\" and \\\"Soft Delete\\\" functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when soft_delete_enabled and purge_protection_enabled then 'ok' - else 'alarm' - end as status, - case - when not soft_delete_enabled and not purge_protection_enabled then name || ' "soft delete" and "do not purge" not enabled.' - when not soft_delete_enabled then name || ' "soft delete" not enabled.' - when not purge_protection_enabled then name || ' "do not purge" not enabled.' - else name || ' "soft delete" and "do not purge" enabled.' - end as reason - from - azure_key_vault kv, - azure_subscription sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN soft_delete_enabled AND purge_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT soft_delete_enabled AND NOT purge_protection_enabled THEN name || ' "soft delete" and "do not purge" not enabled.' + WHEN NOT soft_delete_enabled THEN name || ' "soft delete" not enabled.' + WHEN NOT purge_protection_enabled THEN name || ' "do not purge" not enabled.' + ELSE name || ' "soft delete" and "do not purge" enabled.' + END AS reason + FROM + azure_key_vault kv, + azure_subscription sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.5 Ensure the Key Vault is Recoverable \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_8_6.yaml b/compliance/controls/azure/azure_cis_v200_8_6.yaml old mode 100755 new mode 100644 index 874b92c13..cccc80a87 --- a/compliance/controls/azure/azure_cis_v200_8_6.yaml +++ b/compliance/controls/azure/azure_cis_v200_8_6.yaml @@ -1,32 +1,32 @@ +Description: Role assignments disappear when a Key Vault has been deleted (soft-delete) and recovered. Afterwards, it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services. ID: azure_cis_v200_8_6 -Title: "8.6 Enable Role Based Access Control for Azure Key Vault" -Description: "Role assignments disappear when a Key Vault has been deleted (soft- delete) and recovered. Afterwards it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when enable_rbac_authorization then 'ok' - else 'alarm' - end as status, - case - when enable_rbac_authorization then name || ' has RBAC enabled.' - else name || ' have RBAC disabled.' - end as reason - from - azure_key_vault as kv, - azure_subscription as sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN enable_rbac_authorization THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_rbac_authorization THEN name || ' has RBAC enabled.' + ELSE name || ' have RBAC disabled.' + END AS reason + FROM + azure_key_vault AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.6 Enable Role Based Access Control for Azure Key Vault \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_8_8.yaml b/compliance/controls/azure/azure_cis_v200_8_8.yaml old mode 100755 new mode 100644 index de7dfb849..233c651dc --- a/compliance/controls/azure/azure_cis_v200_8_8.yaml +++ b/compliance/controls/azure/azure_cis_v200_8_8.yaml @@ -1,24 +1,24 @@ +Description: Automatic Key Rotation is available in Public Preview. The currently supported applications are Key Vault, Managed Disks, and Storage accounts accessing keys within Key Vault. The number of supported applications will incrementally increase. ID: azure_cis_v200_8_8 -Title: "8.8 Ensure Automatic Key Rotation is Enabled Within Azure Key Vault for the Supported Services" -Description: "Automatic Key Rotation is available in Public Preview. The currently supported applications are Key Vault, Managed Disks, and Storage accounts accessing keys within Key Vault. The number of supported applications will incrementally increased." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 8.8 Ensure Automatic Key Rotation is Enabled Within Azure Key Vault for the Supported Services \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_9_1.yaml b/compliance/controls/azure/azure_cis_v200_9_1.yaml old mode 100755 new mode 100644 index e61a32885..ac9ce47f3 --- a/compliance/controls/azure/azure_cis_v200_9_1.yaml +++ b/compliance/controls/azure/azure_cis_v200_9_1.yaml @@ -1,32 +1,32 @@ +Description: Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented. ID: azure_cis_v200_9_1 -Title: "9.1 Ensure App Service Authentication is set up for apps in Azure App Service" -Description: "Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then name || ' authentication not set.' - else name || ' authentication set.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::BOOLEAN THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::BOOLEAN THEN name || ' authentication not set.' + ELSE name || ' authentication set.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.1 Ensure App Service Authentication is set up for apps in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_9_11.yaml b/compliance/controls/azure/azure_cis_v200_9_11.yaml old mode 100755 new mode 100644 index 4fec0f478..ceed0d586 --- a/compliance/controls/azure/azure_cis_v200_9_11.yaml +++ b/compliance/controls/azure/azure_cis_v200_9_11.yaml @@ -1,24 +1,24 @@ +Description: Azure Key Vault will store multiple types of sensitive information such as encryption keys, certificate thumbprints, and Managed Identity Credentials. Access to these 'Secrets' can be controlled through granular permissions. ID: azure_cis_v200_9_11 -Title: "9.11 Ensure Azure Key Vaults are Used to Store Secrets" -Description: "Azure Key Vault will store multiple types of sensitive information such as encryption keys, certificate thumbprints, and Managed Identity Credentials. Access to these 'Secrets' can be controlled through granular permissions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.11 Ensure Azure Key Vaults are Used to Store Secrets \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_9_2.yaml b/compliance/controls/azure/azure_cis_v200_9_2.yaml old mode 100755 new mode 100644 index 76ebbf6d1..b9ede289d --- a/compliance/controls/azure/azure_cis_v200_9_2.yaml +++ b/compliance/controls/azure/azure_cis_v200_9_2.yaml @@ -1,32 +1,32 @@ +Description: Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic. ID: azure_cis_v200_9_2 -Title: "9.2 Ensure Web App Redirects All HTTP traffic to HTTPS in Azure App Service" -Description: "Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not https_only then 'alarm' - else 'ok' - end as status, - case - when not https_only then name || ' does not redirect all HTTP traffic to HTTPS.' - else name || ' redirects all HTTP traffic to HTTPS.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT https_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT https_only THEN name || ' does not redirect all HTTP traffic to HTTPS.' + ELSE name || ' redirects all HTTP traffic to HTTPS.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.2 Ensure Web App Redirects All HTTP traffic to HTTPS in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_9_3.yaml b/compliance/controls/azure/azure_cis_v200_9_3.yaml old mode 100755 new mode 100644 index 5ce6f174c..d53c87821 --- a/compliance/controls/azure/azure_cis_v200_9_3.yaml +++ b/compliance/controls/azure/azure_cis_v200_9_3.yaml @@ -1,32 +1,32 @@ +Description: The TLS (Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards such as PCI DSS. ID: azure_cis_v200_9_3 -Title: "9.3 Ensure Web App is using the latest version of TLS encryption" -Description: "The TLS (Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards such as PCI DSS." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then 'alarm' - else 'ok' - end as status, - case - when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then name || ' not using the latest version of TLS encryption.' - else name || ' using the latest version of TLS encryption.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN name || ' not using the latest version of TLS encryption.' + ELSE name || ' using the latest version of TLS encryption.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.3 Ensure Web App is using the latest version of TLS encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_9_4.yaml b/compliance/controls/azure/azure_cis_v200_9_4.yaml old mode 100755 new mode 100644 index 63bb11d87..8f232087d --- a/compliance/controls/azure/azure_cis_v200_9_4.yaml +++ b/compliance/controls/azure/azure_cis_v200_9_4.yaml @@ -1,32 +1,32 @@ +Description: Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app. ID: azure_cis_v200_9_4 -Title: "9.4 Ensure the web app has 'Client Certificates (Incoming client certificates)' set to 'On'" -Description: "Client certificates allow for the app to request a certificate for incoming requests. Only clients that have a valid certificate will be able to reach the app." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not client_cert_enabled then 'alarm' - else 'ok' - end as status, - case - when not client_cert_enabled then name || ' incoming client certificates set to off.' - else name || ' incoming client certificates set to on.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT client_cert_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT client_cert_enabled THEN name || ' incoming client certificates set to off.' + ELSE name || ' incoming client certificates set to on.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.4 Ensure the web app has 'Client Certificates (Incoming client certificates)' set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_9_5.yaml b/compliance/controls/azure/azure_cis_v200_9_5.yaml old mode 100755 new mode 100644 index 13a59a71f..c073c5853 --- a/compliance/controls/azure/azure_cis_v200_9_5.yaml +++ b/compliance/controls/azure/azure_cis_v200_9_5.yaml @@ -1,32 +1,32 @@ +Description: Managed service identity in App Service provides more security by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in App Service, the app will connect to other Azure services securely without the need for usernames and passwords. ID: azure_cis_v200_9_5 -Title: "9.5 Ensure that Register with Azure Active Directory is enabled on App Service" -Description: "Managed service identity in App Service provides more security by eliminating secrets from the app, such as credentials in the connection strings. When registering with Azure Active Directory in App Service, the app will connect to other Azure services securely without the need for usernames and passwords." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when identity = '{}' then 'alarm' - else 'ok' - end as status, - case - when identity = '{}' then name || ' register with azure active directory disabled.' - else name || ' register with azure active directory enabled.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN identity = '{}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity = '{}' THEN name || ' register with azure active directory disabled.' + ELSE name || ' register with azure active directory enabled.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.5 Ensure that Register with Azure Active Directory is enabled on App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_9_6.yaml b/compliance/controls/azure/azure_cis_v200_9_6.yaml old mode 100755 new mode 100644 index 9943e6c6c..12ef41ceb --- a/compliance/controls/azure/azure_cis_v200_9_6.yaml +++ b/compliance/controls/azure/azure_cis_v200_9_6.yaml @@ -1,24 +1,24 @@ +Description: Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version. ID: azure_cis_v200_9_6 -Title: "9.6 Ensure That 'PHP version' is the Latest, If Used to Run the Web App" -Description: "Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.6 Ensure That 'PHP version' is the Latest, If Used to Run the Web App \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_9_7.yaml b/compliance/controls/azure/azure_cis_v200_9_7.yaml old mode 100755 new mode 100644 index f3d93b761..a59c669b9 --- a/compliance/controls/azure/azure_cis_v200_9_7.yaml +++ b/compliance/controls/azure/azure_cis_v200_9_7.yaml @@ -1,24 +1,24 @@ +Description: Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest full Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version. ID: azure_cis_v200_9_7 -Title: "9.7 Ensure that 'Python version' is the Latest Stable Version, if Used to Run the Web App" -Description: "Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest full Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.7 Ensure that 'Python version' is the Latest Stable Version, if Used to Run the Web App \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_9_8.yaml b/compliance/controls/azure/azure_cis_v200_9_8.yaml old mode 100755 new mode 100644 index 327f5c8a5..82c751a90 --- a/compliance/controls/azure/azure_cis_v200_9_8.yaml +++ b/compliance/controls/azure/azure_cis_v200_9_8.yaml @@ -1,24 +1,24 @@ +Description: Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version. ID: azure_cis_v200_9_8 -Title: "9.8 Ensure that 'Java version' is the latest, if used to run the Web App" -Description: "Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.8 Ensure that 'Java version' is the latest, if used to run the Web App \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v200_9_9.yaml b/compliance/controls/azure/azure_cis_v200_9_9.yaml old mode 100755 new mode 100644 index c0c6e2908..df0f3741a --- a/compliance/controls/azure/azure_cis_v200_9_9.yaml +++ b/compliance/controls/azure/azure_cis_v200_9_9.yaml @@ -1,32 +1,32 @@ +Description: Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version. ID: azure_cis_v200_9_9 -Title: "9.9 Ensure that 'HTTP Version' is the Latest, if Used to Run the Web App" -Description: "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then name || ' HTTP version not latest.' - else name || ' HTTP version is latest.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::boolean THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::boolean THEN name || ' HTTP version not latest.' + ELSE name || ' HTTP version is latest.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.9 Ensure that 'HTTP Version' is the Latest, if Used to Run the Web App \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_10_1.yaml b/compliance/controls/azure/azure_cis_v210_10_1.yaml old mode 100755 new mode 100644 index 29aba2930..a7b3f353d --- a/compliance/controls/azure/azure_cis_v210_10_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_10_1.yaml @@ -1,24 +1,24 @@ +Description: Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users. ID: azure_cis_v210_10_1 -Title: "10.1 Ensure that Resource Locks are set for Mission-Critical Azure Resources" -Description: "Resource Manager Locks provide a way for administrators to lock down Azure resources to prevent deletion of, or modifications to, a resource. These locks sit outside of the Role Based Access Controls (RBAC) hierarchy and, when applied, will place restrictions on the resource for all users." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 10.1 Ensure that Resource Locks are set for Mission-Critical Azure Resources \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_10.yaml b/compliance/controls/azure/azure_cis_v210_1_10.yaml old mode 100755 new mode 100644 index dd4448477..9e0adddcc --- a/compliance/controls/azure/azure_cis_v210_1_10.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_10.yaml @@ -1,19 +1,19 @@ +Description: Require administrators to provide consent for applications before use. ID: azure_cis_v210_1_10 -Title: "1.10 Ensure 'User consent for applications' is set to 'Do not allow user consent'" -Description: "Require administrators to provide consent for applications before use." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.10 Ensure 'User consent for applications' is set to 'Do not allow user consent' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_11.yaml b/compliance/controls/azure/azure_cis_v210_1_11.yaml old mode 100755 new mode 100644 index ffec24983..683aa2043 --- a/compliance/controls/azure/azure_cis_v210_1_11.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_11.yaml @@ -1,19 +1,19 @@ +Description: Allow users to provide consent for selected permissions when a request is coming from a verified publisher. ID: azure_cis_v210_1_11 -Title: "1.11 Ensure 'User consent for applications' Is Set To 'Allow for Verified Publishers'" -Description: "Allow users to provide consent for selected permissions when a request is coming from a verified publisher." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.11 Ensure 'User consent for applications' Is Set To 'Allow for Verified Publishers' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_12.yaml b/compliance/controls/azure/azure_cis_v210_1_12.yaml old mode 100755 new mode 100644 index d964e1e41..ce6320052 --- a/compliance/controls/azure/azure_cis_v210_1_12.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_12.yaml @@ -1,19 +1,19 @@ +Description: Require administrators to provide consent for the apps before use. ID: azure_cis_v210_1_12 -Title: "1.12 Ensure that 'Users can add gallery apps to My Apps' is set to 'No'" -Description: "Require administrators to provide consent for the apps before use." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.12 Ensure that 'Users can add gallery apps to My Apps' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_13.yaml b/compliance/controls/azure/azure_cis_v210_1_13.yaml old mode 100755 new mode 100644 index 6d1860293..d42b174e3 --- a/compliance/controls/azure/azure_cis_v210_1_13.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_13.yaml @@ -1,39 +1,39 @@ +Description: Require administrators or appropriately delegated users to register third-party applications. ID: azure_cis_v210_1_13 -Title: "1.13 Ensure That 'Users Can Register Applications' Is Set to 'No'" -Description: "Require administrators or appropriately delegated users to register third-party applications." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_authorization_policy + Parameters: [] + PrimaryTable: azuread_authorization_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT DISTINCT + tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' then 'ok' - else 'alarm' - end as status, - case - when a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' then a.display_name || ' does not allow user to register applications.' - else a.display_name || ' allows user to register applications.' - end as reason, + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' THEN a.display_name || ' does not allow user to register applications.' + ELSE a.display_name || ' allows user to register applications.' + END AS reason, t.tenant_id - from - distinct_tenant as t, - azuread_authorization_policy as a; - PrimaryTable: azuread_authorization_policy - ListOfTables: - - azure_tenant - - azuread_authorization_policy - Parameters: [] + FROM + distinct_tenant AS t, + azuread_authorization_policy AS a; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.13 Ensure That 'Users Can Register Applications' Is Set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_14.yaml b/compliance/controls/azure/azure_cis_v210_1_14.yaml old mode 100755 new mode 100644 index 9bb56fc36..d788c6c85 --- a/compliance/controls/azure/azure_cis_v210_1_14.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_14.yaml @@ -1,19 +1,19 @@ +Description: Limit guest user permissions. ID: azure_cis_v210_1_14 -Title: "1.14 Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects'" -Description: "Limit guest user permissions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.14 Ensure That 'Guest users access restrictions' is set to 'Guest user access is restricted to properties and memberships of their own directory objects' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_15.yaml b/compliance/controls/azure/azure_cis_v210_1_15.yaml old mode 100755 new mode 100644 index 979fbfb86..1b2c335a7 --- a/compliance/controls/azure/azure_cis_v210_1_15.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_15.yaml @@ -1,19 +1,19 @@ +Description: Restrict invitations to users with specific administrative roles only. ID: azure_cis_v210_1_15 -Title: "1.15 Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users'" -Description: "Restrict invitations to users with specific administrative roles only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.15 Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_16.yaml b/compliance/controls/azure/azure_cis_v210_1_16.yaml old mode 100755 new mode 100644 index 3c695cea9..8ab9da0d5 --- a/compliance/controls/azure/azure_cis_v210_1_16.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_16.yaml @@ -1,19 +1,19 @@ +Description: Restrict access to the Azure AD administration portal to administrators only. ID: azure_cis_v210_1_16 -Title: "1.16 Ensure That 'Restrict access to Microsoft Entra admin center' is Set to 'Yes'" -Description: "Restrict access to the Azure AD administration portal to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.16 Ensure That 'Restrict access to Microsoft Entra admin center' is Set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_17.yaml b/compliance/controls/azure/azure_cis_v210_1_17.yaml old mode 100755 new mode 100644 index 955cf3d07..66b449db2 --- a/compliance/controls/azure/azure_cis_v210_1_17.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_17.yaml @@ -1,19 +1,19 @@ +Description: Restricts group creation to administrators with permissions only. ID: azure_cis_v210_1_17 -Title: "1.17 Ensure that 'Restrict user ability to access groups features in the Access Pane' is Set to 'Yes'" -Description: "Restricts group creation to administrators with permissions only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.17 Ensure that 'Restrict user ability to access groups features in the Access Pane' is Set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_18.yaml b/compliance/controls/azure/azure_cis_v210_1_18.yaml old mode 100755 new mode 100644 index 7df59004c..757502f69 --- a/compliance/controls/azure/azure_cis_v210_1_18.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_18.yaml @@ -1,15 +1,39 @@ +Description: Restrict security group creation to administrators only. ID: azure_cis_v210_1_18 -Title: "1.18 Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No'" -Description: "Restrict security group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with distinct_tenant as (\n select\n distinct tenant_id,\n subscription_id,\n _ctx\n from\n azure_tenant\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' then a.display_name || ' does not allow user to create security groups.'\n else a.display_name || ' allows user to create security groups.'\n end as reason,\n t.tenant_id\n \nfrom\n distinct_tenant as t,\n azuread_authorization_policy as a;" - PrimaryTable: azuread_authorization_policy ListOfTables: - azure_tenant - azuread_authorization_policy Parameters: [] + PrimaryTable: azuread_authorization_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, + subscription_id, + _ctx + FROM + azure_tenant + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' THEN a.display_name || ' does not allow user to create security groups.' + ELSE a.display_name || ' allows user to create security groups.' + END AS reason, + t.tenant_id + FROM + distinct_tenant AS t, + azuread_authorization_policy AS a; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.18 Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_19.yaml b/compliance/controls/azure/azure_cis_v210_1_19.yaml old mode 100755 new mode 100644 index 11e31806a..f54384131 --- a/compliance/controls/azure/azure_cis_v210_1_19.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_19.yaml @@ -1,19 +1,19 @@ +Description: Restrict security group management to administrators only. ID: azure_cis_v210_1_19 -Title: "1.19 Ensure that 'Owners can manage group membership requests in the Access Panel' is set to 'No'" -Description: "Restrict security group management to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.19 Ensure that 'Owners can manage group membership requests in the Access Panel' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_1_1.yaml b/compliance/controls/azure/azure_cis_v210_1_1_1.yaml old mode 100755 new mode 100644 index 7e20d216f..ee0fbb106 --- a/compliance/controls/azure/azure_cis_v210_1_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_1_1.yaml @@ -1,19 +1,19 @@ +Description: Security defaults in Microsoft Entra ID make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks. Security defaults is available to everyone. The goal is to ensure that all organizations have a basic level of security enabled at no extra cost. You may turn on security defaults in the Azure portal. ID: azure_cis_v210_1_1_1 -Title: "1.1.1 Ensure Security Defaults is enabled on Microsoft Entra ID" -Description: "Security defaults in Microsoft Entra ID make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks. Security defaults is available to everyone. The goal is to ensure that all organizations have a basic level of security enabled at no extra cost. You may turn on security defaults in the Azure portal." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.1 Ensure Security Defaults is enabled on Microsoft Entra ID \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_1_2.yaml b/compliance/controls/azure/azure_cis_v210_1_1_2.yaml old mode 100755 new mode 100644 index 863e696d6..d5ce0805a --- a/compliance/controls/azure/azure_cis_v210_1_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_1_2.yaml @@ -1,19 +1,19 @@ +Description: Enable multi-factor authentication for all roles, groups, and users that have write access or permissions to Azure resources. ID: azure_cis_v210_1_1_2 -Title: "1.1.2 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Privileged Users" -Description: "Enable multi-factor authentication for all roles, groups, and users that have write access or permissions to Azure resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.2 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Privileged Users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_1_3.yaml b/compliance/controls/azure/azure_cis_v210_1_1_3.yaml old mode 100755 new mode 100644 index 8d64f7060..50b33ce8d --- a/compliance/controls/azure/azure_cis_v210_1_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_1_3.yaml @@ -1,19 +1,19 @@ +Description: Enable multi-factor authentication for all non-privileged users. ID: azure_cis_v210_1_1_3 -Title: "1.1.3 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Non-Privileged Users" -Description: "Enable multi-factor authentication for all non-privileged users." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.3 Ensure that 'Multi-Factor Auth Status' is 'Enabled' for all Non-Privileged Users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_1_4.yaml b/compliance/controls/azure/azure_cis_v210_1_1_4.yaml old mode 100755 new mode 100644 index 37d1ef19e..7fff73799 --- a/compliance/controls/azure/azure_cis_v210_1_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_1_4.yaml @@ -1,19 +1,19 @@ +Description: Do not allow users to remember multi-factor authentication on devices. ID: azure_cis_v210_1_1_4 -Title: "1.1.4 Ensure that 'Allow users to remember multi-factor authentication on devices they trust' is Disabled" -Description: "Do not allow users to remember multi-factor authentication on devices." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.1.4 Ensure that 'Allow users to remember multi-factor authentication on devices they trust' is Disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_20.yaml b/compliance/controls/azure/azure_cis_v210_1_20.yaml old mode 100755 new mode 100644 index cc9b36da0..b20f94caf --- a/compliance/controls/azure/azure_cis_v210_1_20.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_20.yaml @@ -1,19 +1,19 @@ +Description: Restrict Microsoft 365 group creation to administrators only. ID: azure_cis_v210_1_20 -Title: "1.20 Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No'" -Description: "Restrict Microsoft 365 group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.20 Ensure that 'Users can create Microsoft 365 groups in Azure portals, API or PowerShell' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_21.yaml b/compliance/controls/azure/azure_cis_v210_1_21.yaml old mode 100755 new mode 100644 index 910fa5ff8..55a0ee2a3 --- a/compliance/controls/azure/azure_cis_v210_1_21.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_21.yaml @@ -1,19 +1,19 @@ +Description: Joining or registering devices to the active directory should require Multi-factor authentication. ID: azure_cis_v210_1_21 -Title: "1.21 Ensure that 'Require Multi-Factor Authentication to register or join devices with Microsoft Entra ID' is set to 'Yes'" -Description: "Joining or registering devices to the active directory should require Multi-factor authentication." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.21 Ensure that 'Require Multi-Factor Authentication to register or join devices with Microsoft Entra ID' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_22.yaml b/compliance/controls/azure/azure_cis_v210_1_22.yaml old mode 100755 new mode 100644 index 35626780b..4e8792356 --- a/compliance/controls/azure/azure_cis_v210_1_22.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_22.yaml @@ -1,11 +1,17 @@ +Description: The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access. ID: azure_cis_v210_1_22 -Title: "1.22 Ensure That No Custom Subscription Administrator Roles Exist" -Description: "The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with owner_custom_roles as ( - select + ListOfTables: + - azure_role_definition + - azure_subscription + Parameters: [] + PrimaryTable: azure_role_definition + QueryToExecute: | + WITH owner_custom_roles AS ( + SELECT role_name, role_type, title, @@ -14,44 +20,38 @@ Query: subscription_id, og_account_id, og_resource_id - from + FROM azure_role_definition, - jsonb_array_elements(permissions) as s, - jsonb_array_elements_text(s -> 'actions') as action - where + jsonb_array_elements(permissions) AS s, + jsonb_array_elements_text(s -> 'actions') AS action + WHERE role_type = 'CustomRole' - and action in ('*', '*:*') + AND action IN ('*', '*:*') ) - select - cr.subscription_id as resource, - cr.og_account_id as og_account_id, - cr.og_resource_id as og_resource_id, - case - when count(*) > 0 then 'alarm' - else 'ok' - end as status, - case - when count(*) = 1 then 'There is one custom owner role.' - when count(*) > 1 then 'There are ' || count(*) || ' custom owner roles.' - else 'There are no custom owner roles.' - end as reason - from + SELECT + cr.subscription_id AS resource, + cr.og_account_id AS og_account_id, + cr.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(*) > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(*) = 1 THEN 'There is one custom owner role.' + WHEN COUNT(*) > 1 THEN 'There are ' || COUNT(*) || ' custom owner roles.' + ELSE 'There are no custom owner roles.' + END AS reason + FROM owner_custom_roles cr, azure_subscription sub - where + WHERE sub.subscription_id = cr.subscription_id - group by + GROUP BY cr.subscription_id, cr._ctx, sub.display_name, cr.og_account_id, cr.og_resource_id; - PrimaryTable: azure_role_definition - ListOfTables: - - azure_role_definition - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.22 Ensure That No Custom Subscription Administrator Roles Exist \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_23.yaml b/compliance/controls/azure/azure_cis_v210_1_23.yaml old mode 100755 new mode 100644 index 1fa376d74..2d0165382 --- a/compliance/controls/azure/azure_cis_v210_1_23.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_23.yaml @@ -1,19 +1,19 @@ +Description: Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration. ID: azure_cis_v210_1_23 -Title: "1.23 Ensure a Custom Role is Assigned Permissions for Administering Resource Locks" -Description: "Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.23 Ensure a Custom Role is Assigned Permissions for Administering Resource Locks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_24.yaml b/compliance/controls/azure/azure_cis_v210_1_24.yaml old mode 100755 new mode 100644 index 7a2701b46..0aec961d6 --- a/compliance/controls/azure/azure_cis_v210_1_24.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_24.yaml @@ -1,19 +1,19 @@ +Description: Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Azure Active Directories. ID: azure_cis_v210_1_24 -Title: "1.24 Ensure That `Subscription leaving Microsoft Entra ID directory` and `Subscription entering Microsoft Entra ID directory` Is Set To 'Permit No One'" -Description: "Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Azure Active Directories." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.24 Ensure That `Subscription leaving Microsoft Entra ID directory` and `Subscription entering Microsoft Entra ID directory` Is Set To 'Permit No One' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_25.yaml b/compliance/controls/azure/azure_cis_v210_1_25.yaml old mode 100755 new mode 100644 index 9a2a9b06d..8706c2a34 --- a/compliance/controls/azure/azure_cis_v210_1_25.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_25.yaml @@ -1,41 +1,41 @@ +Description: This recommendation aims to maintain a balance between security and operational efficiency by ensuring that a minimum of 2 and a maximum of 4 users are assigned the Global Administrator role in Microsoft Entra ID. Having at least two Global Administrators ensures redundancy, while limiting the number to four reduces the risk of excessive privileged access. ID: azure_cis_v210_1_25 -Title: "1.25 Ensure fewer than 5 users have global administrator assignment" -Description: "This recommendation aims to maintain a balance between security and operational efficiency by ensuring that a minimum of 2 and a maximum of 4 users are assigned the Global Administrator role in Microsoft Entra ID. Having at least two Global Administrators ensures redundancy, while limiting the number to four reduces the risk of excessive privileged access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_directory_role + Parameters: [] + PrimaryTable: azuread_directory_role + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, title, subscription_id, og_account_id, og_resource_id, _ctx - from + FROM azure_tenant ) - select - t.tenant_id as resource, - t.og_account_id as og_account_id, - t.og_resource_id as og_resource_id, - case - when jsonb_array_length(member_ids) <= 5 then 'ok' - else 'alarm' - end as status, - t.title || ' has ' || (jsonb_array_length(member_ids)) || ' users with global administrator assignment.' as reason, + SELECT + t.tenant_id AS resource, + t.og_account_id AS og_account_id, + t.og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(member_ids) <= 5 THEN 'ok' + ELSE 'alarm' + END AS status, + t.title || ' has ' || (jsonb_array_length(member_ids)) || ' users with global administrator assignment.' AS reason, t.tenant_id - from - distinct_tenant as t, + FROM + distinct_tenant AS t, azuread_directory_role - where + WHERE display_name = 'Global Administrator' - PrimaryTable: azuread_directory_role - ListOfTables: - - azure_tenant - - azuread_directory_role - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.25 Ensure fewer than 5 users have global administrator assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_2_1.yaml b/compliance/controls/azure/azure_cis_v210_1_2_1.yaml old mode 100755 new mode 100644 index 816743f67..230e6d909 --- a/compliance/controls/azure/azure_cis_v210_1_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_2_1.yaml @@ -1,19 +1,19 @@ +Description: Microsoft Entra ID Conditional Access allows an organization to configure Named locations and configure whether those locations are trusted or untrusted. These settings provide organizations the means to specify Geographical locations for use in conditional access policies, or define actual IP addresses and IP ranges and whether or not those IP addresses and/or ranges are trusted by the organization. ID: azure_cis_v210_1_2_1 -Title: "1.2.1 Ensure Trusted Locations Are Defined" -Description: "Microsoft Entra ID Conditional Access allows an organization to configure Named locations and configure whether those locations are trusted or untrusted. These settings provide organizations the means to specify Geographical locations for use in conditional access policies, or define actual IP addresses and IP ranges and whether or not those IP addresses and/or ranges are trusted by the organization." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.1 Ensure Trusted Locations Are Defined \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_2_2.yaml b/compliance/controls/azure/azure_cis_v210_1_2_2.yaml old mode 100755 new mode 100644 index 6116ef1e6..96f7d7354 --- a/compliance/controls/azure/azure_cis_v210_1_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_2_2.yaml @@ -1,19 +1,19 @@ +Description: Conditional Access Policies can be used to block access from geographic locations that are deemed out-of-scope for your organization or application. The scope and variables for this policy should be carefully examined and defined. ID: azure_cis_v210_1_2_2 -Title: "1.2.2 Ensure that an exclusionary Geographic Access Policy is considered" -Description: "Conditional Access Policies can be used to block access from geographic locations that are deemed out-of-scope for your organization or application. The scope and variables for this policy should be carefully examined and defined." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.2 Ensure that an exclusionary Geographic Access Policy is considered \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_2_3.yaml b/compliance/controls/azure/azure_cis_v210_1_2_3.yaml old mode 100755 new mode 100644 index 1f3b5991f..7d278fb52 --- a/compliance/controls/azure/azure_cis_v210_1_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_2_3.yaml @@ -1,19 +1,19 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login. ID: azure_cis_v210_1_2_3 -Title: "1.2.3 Ensure that A Multi-factor Authentication Policy Exists for Administrative Groups" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.3 Ensure that A Multi-factor Authentication Policy Exists for Administrative Groups \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_2_4.yaml b/compliance/controls/azure/azure_cis_v210_1_2_4.yaml old mode 100755 new mode 100644 index 7825d273d..84480fc7e --- a/compliance/controls/azure/azure_cis_v210_1_2_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_2_4.yaml @@ -1,19 +1,19 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins. ID: azure_cis_v210_1_2_4 -Title: "1.2.4 Ensure that A Multi-factor Authentication Policy Exists for All Users" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.4 Ensure that A Multi-factor Authentication Policy Exists for All Users \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_2_5.yaml b/compliance/controls/azure/azure_cis_v210_1_2_5.yaml old mode 100755 new mode 100644 index 52aa68bdc..4e8768aa8 --- a/compliance/controls/azure/azure_cis_v210_1_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_2_5.yaml @@ -1,19 +1,19 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login. ID: azure_cis_v210_1_2_5 -Title: "1.2.5 Ensure Multi-factor Authentication is Required for Risky Sign-ins" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.2.5 Ensure Multi-factor Authentication is Required for Risky Sign-ins \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_2_6.yaml b/compliance/controls/azure/azure_cis_v210_1_2_6.yaml old mode 100755 new mode 100644 index b9c202930..500672b3a --- a/compliance/controls/azure/azure_cis_v210_1_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_2_6.yaml @@ -1,39 +1,39 @@ +Description: This recommendation ensures that users accessing the Windows Azure Service Management API (i.e. Azure Powershell, Azure CLI, Azure Resource Manager API, etc.) are required to use multifactor authentication (MFA) credentials when accessing resources through the Windows Azure Service Management API. ID: azure_cis_v210_1_2_6 -Title: "1.2.6 Ensure Multifactor Authentication is Required for Windows Azure Service Management API" -Description: "This recommendation ensures that users accessing the Windows Azure Service Management API (i.e. Azure Powershell, Azure CLI, Azure Resource Manager API, etc.) are required to use multifactor authentication (MFA) credentials when accessing resources through the Windows Azure Service Management API." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_conditional_access_policy + Parameters: [] + PrimaryTable: azuread_conditional_access_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - p.id as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when p.built_in_controls @> '["mfa"]' then 'ok' - else 'alarm' - end as status, - case - when p.built_in_controls @> '["mfa"]' then p.display_name || ' MFA enabled.' - else p.display_name || ' MFA disabled.' - end as reason, + SELECT + p.id AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.built_in_controls @> '["mfa"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.built_in_controls @> '["mfa"]' THEN p.display_name || ' MFA enabled.' + ELSE p.display_name || ' MFA disabled.' + END AS reason, t.tenant_id - from - distinct_tenant as t, - azuread_conditional_access_policy as p; - PrimaryTable: azuread_conditional_access_policy - ListOfTables: - - azure_tenant - - azuread_conditional_access_policy - Parameters: [] + FROM + distinct_tenant AS t, + azuread_conditional_access_policy AS p; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.2.6 Ensure Multifactor Authentication is Required for Windows Azure Service Management API \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_2_7.yaml b/compliance/controls/azure/azure_cis_v210_1_2_7.yaml old mode 100755 new mode 100644 index 692a11c1e..7e3230b29 --- a/compliance/controls/azure/azure_cis_v210_1_2_7.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_2_7.yaml @@ -1,17 +1,45 @@ +Description: This recommendation ensures that users accessing Microsoft Admin Portals (i.e. Microsoft 365 Admin, Microsoft 365 Defender, Exchange Admin Center, Azure Portal, etc.) are required to use multifactor authentication (MFA) credentials when logging into an Admin Portal. ID: azure_cis_v210_1_2_7 -Title: "1.2.7 Ensure Multifactor Authentication is Required to access Microsoft Admin Portals" -Description: "This recommendation ensures that users accessing Microsoft Admin Portals (i.e. Microsoft 365 Admin, Microsoft 365 Defender, Exchange Admin Center, Azure Portal, etc.) are required to use multifactor authentication (MFA) credentials when logging into an Admin Portal." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with distinct_tenant as (\n select\n u.id,\n tenant_id\n from\n azuread_user as u\n left join azure_role_assignment as a on a.principal_id = u.id\n left join azure_role_definition as d on d.id = a.role_definition_id\n where role_type = 'BuiltInRole' and (role_name like '%Administrator%' or role_name = 'Owner')\n)\nselect\n p.id as resource,\np.og_account_id as og_account_id,\np.og_resource_id as og_resource_id,\n case\n when p.built_in_controls @> '[\"mfa\"]' then 'ok'\n else 'alarm'\n end as status,\n case\n when p.built_in_controls @> '[\"mfa\"]' then p.display_name || ' MFA enabled.'\n else p.display_name || ' MFA disabled.'\n end as reason,\n t.tenant_id\n \nfrom\n distinct_tenant as t,\n azuread_conditional_access_policy as p;" - PrimaryTable: azuread_conditional_access_policy ListOfTables: - azuread_user - azure_role_assignment - azure_role_definition - azuread_conditional_access_policy Parameters: [] + PrimaryTable: azuread_conditional_access_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + u.id, + tenant_id + FROM + azuread_user AS u + LEFT JOIN azure_role_assignment AS a ON a.principal_id = u.id + LEFT JOIN azure_role_definition AS d ON d.id = a.role_definition_id + WHERE + role_type = 'BuiltInRole' + AND (role_name LIKE '%Administrator%' OR role_name = 'Owner') + ) + SELECT + p.id AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.built_in_controls @> '["mfa"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.built_in_controls @> '["mfa"]' THEN p.display_name || ' MFA enabled.' + ELSE p.display_name || ' MFA disabled.' + END AS reason, + t.tenant_id + FROM + distinct_tenant AS t, + azuread_conditional_access_policy AS p; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.2.7 Ensure Multifactor Authentication is Required to access Microsoft Admin Portals \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_4.yaml b/compliance/controls/azure/azure_cis_v210_1_4.yaml old mode 100755 new mode 100644 index 508a300e8..d30f2fdde --- a/compliance/controls/azure/azure_cis_v210_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_4.yaml @@ -1,42 +1,42 @@ +Description: Microsoft Entra ID is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user. Guest users in every subscription should be review on a regular basis to ensure that inactive and unneeded accounts are removed. ID: azure_cis_v210_1_4 -Title: "1.4 Ensure Guest Users Are Reviewed on a Regular Basis" -Description: "Microsoft Entra ID is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user. Guest users in every subscription should be review on a regular basis to ensure that inactive and unneeded accounts are removed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_user + Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - u.display_name as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when not account_enabled then 'alarm' - when u.created_date_time::timestamp <= (current_date - interval '30' day) then 'alarm' - else 'ok' - end as status, - case - when not account_enabled then 'Guest user ''' || u.display_name || ''' inactive.' - else 'Guest user ''' || u.display_name || ''' was created ' || extract(day from current_timestamp - u.created_date_time::timestamp) || ' days ago.' - end as reason, + SELECT + u.display_name AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN NOT account_enabled THEN 'alarm' + WHEN u.created_date_time::timestamp <= (CURRENT_DATE - INTERVAL '30' DAY) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT account_enabled THEN 'Guest user ''' || u.display_name || ''' inactive.' + ELSE 'Guest user ''' || u.display_name || ''' was created ' || EXTRACT(DAY FROM CURRENT_TIMESTAMP - u.created_date_time::timestamp) || ' days ago.' + END AS reason, t.tenant_id - from - azuread_user as u - left join distinct_tenant as t on t.tenant_id = u.tenant_id - where + FROM + azuread_user AS u + LEFT JOIN distinct_tenant AS t ON t.tenant_id = u.tenant_id + WHERE u.user_type = 'Guest'; - PrimaryTable: azuread_user - ListOfTables: - - azure_tenant - - azuread_user - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.4 Ensure Guest Users Are Reviewed on a Regular Basis \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_5.yaml b/compliance/controls/azure/azure_cis_v210_1_5.yaml old mode 100755 new mode 100644 index a67ee3b8f..dcf170e85 --- a/compliance/controls/azure/azure_cis_v210_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_5.yaml @@ -1,19 +1,19 @@ +Description: Ensures that two alternate forms of identification are provided before allowing a password reset. ID: azure_cis_v210_1_5 -Title: "1.5 Ensure That 'Number of methods required to reset' is set to '2'" -Description: "Ensures that two alternate forms of identification are provided before allowing a password reset." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.5 Ensure That 'Number of methods required to reset' is set to '2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_6.yaml b/compliance/controls/azure/azure_cis_v210_1_6.yaml old mode 100755 new mode 100644 index 0c9442b6b..85e1689cb --- a/compliance/controls/azure/azure_cis_v210_1_6.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_6.yaml @@ -1,19 +1,19 @@ +Description: Microsoft Azure provides a Global Banned Password policy that applies to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Azure AD Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers. Please see the list in default values on the specifics of this policy. To further password security, it is recommended to further define a custom banned password policy. ID: azure_cis_v210_1_6 -Title: "1.6 Ensure that a Custom Bad Password List is set to 'Enforce' for your Organization" -Description: "Microsoft Azure provides a Global Banned Password policy that applies to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Azure AD Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers. Please see the list in default values on the specifics of this policy. To further password security, it is recommended to further define a custom banned password policy." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.6 Ensure that a Custom Bad Password List is set to 'Enforce' for your Organization \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_7.yaml b/compliance/controls/azure/azure_cis_v210_1_7.yaml old mode 100755 new mode 100644 index 47945b35a..141348b05 --- a/compliance/controls/azure/azure_cis_v210_1_7.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_7.yaml @@ -1,19 +1,19 @@ +Description: Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0. ID: azure_cis_v210_1_7 -Title: "1.7 Ensure that 'Number of days before users are asked to re-confirm their authentication information' is not set to '0'" -Description: "Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.7 Ensure that 'Number of days before users are asked to re-confirm their authentication information' is not set to '0' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_8.yaml b/compliance/controls/azure/azure_cis_v210_1_8.yaml old mode 100755 new mode 100644 index 66c7bac66..01ad1c282 --- a/compliance/controls/azure/azure_cis_v210_1_8.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_8.yaml @@ -1,19 +1,19 @@ +Description: Ensure that users are notified on their primary and secondary emails on password resets. ID: azure_cis_v210_1_8 -Title: "1.8 Ensure that 'Notify users on password resets?' is set to 'Yes'" -Description: "Ensure that users are notified on their primary and secondary emails on password resets." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.8 Ensure that 'Notify users on password resets?' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_1_9.yaml b/compliance/controls/azure/azure_cis_v210_1_9.yaml old mode 100755 new mode 100644 index 87609b50b..687d5646e --- a/compliance/controls/azure/azure_cis_v210_1_9.yaml +++ b/compliance/controls/azure/azure_cis_v210_1_9.yaml @@ -1,19 +1,19 @@ +Description: Ensure that all Global Administrators are notified if any other administrator resets their password. ID: azure_cis_v210_1_9 -Title: "1.9 Ensure That 'Notify all admins when other admins reset their password?' is set to 'Yes'" -Description: "Ensure that all Global Administrators are notified if any other administrator resets their password." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 1.9 Ensure That 'Notify all admins when other admins reset their password?' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_1.yaml b/compliance/controls/azure/azure_cis_v210_2_1_1.yaml old mode 100755 new mode 100644 index 859abe020..7caeb5e3b --- a/compliance/controls/azure/azure_cis_v210_2_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_1.yaml @@ -1,32 +1,35 @@ +Description: Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v210_2_1_1 -Title: "2.1.1 Ensure That Microsoft Defender for Servers Is Set to 'On'" -Description: "Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Servers.' - else 'Azure Defender off for Servers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'VirtualMachines'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Servers.' + ELSE 'Azure Defender off for Servers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'VirtualMachines'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.1 Ensure That Microsoft Defender for Servers Is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_10.yaml b/compliance/controls/azure/azure_cis_v210_2_1_10.yaml old mode 100755 new mode 100644 index f8e032e21..5d7852d5b --- a/compliance/controls/azure/azure_cis_v210_2_1_10.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_10.yaml @@ -1,32 +1,33 @@ +Description: Microsoft Defender for DNS scans all network traffic exiting from within a subscription. ID: azure_cis_v210_2_1_10 -Title: "2.1.10 [LEGACY] Ensure That Microsoft Defender for DNS Is Set To 'On'" -Description: "Microsoft Defender for DNS scans all network traffic exiting from within a subscription." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for DNS.' - else 'Azure Defender off for DNS.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'Dns'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for DNS.' + ELSE 'Azure Defender off for DNS.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'Dns'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.10 [LEGACY] Ensure That Microsoft Defender for DNS Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_11.yaml b/compliance/controls/azure/azure_cis_v210_2_1_11.yaml old mode 100755 new mode 100644 index 784f7ad13..6836546d8 --- a/compliance/controls/azure/azure_cis_v210_2_1_11.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_11.yaml @@ -1,15 +1,33 @@ +Description: Microsoft Defender for Resource Manager scans incoming administrative requests to change your infrastructure from both CLI and the Azure portal. ID: azure_cis_v210_2_1_11 -Title: "2.1.11 Ensure That Microsoft Defender for Resource Manager Is Set To 'On'" -Description: "Microsoft Defender for Resource Manager scans incoming administrative requests to change your infrastructure from both CLI and the Azure portal." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Resource Manager.'\n else 'Azure Defender off for Resource Manager.'\n end as reason\n \n \nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'Arm';" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Resource Manager.' + ELSE 'Azure Defender off for Resource Manager.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'Arm'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.11 Ensure That Microsoft Defender for Resource Manager Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_12.yaml b/compliance/controls/azure/azure_cis_v210_2_1_12.yaml old mode 100755 new mode 100644 index db8e7756e..55e54a043 --- a/compliance/controls/azure/azure_cis_v210_2_1_12.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_12.yaml @@ -1,24 +1,24 @@ +Description: Ensure that the latest OS patches for all virtual machines are applied. ID: azure_cis_v210_2_1_12 -Title: "2.1.12 Ensure that Microsoft Defender Recommendation for 'Apply system updates' status is 'Completed'" -Description: "Ensure that the latest OS patches for all virtual machines are applied." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.1.12 Ensure that Microsoft Defender Recommendation for 'Apply system updates' status is 'Completed' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_13.yaml b/compliance/controls/azure/azure_cis_v210_2_1_13.yaml old mode 100755 new mode 100644 index f69ede7d1..977cd9f2a --- a/compliance/controls/azure/azure_cis_v210_2_1_13.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_13.yaml @@ -1,24 +1,24 @@ +Description: The Microsoft Cloud Security Benchmark (or 'MCSB') is an Azure Policy Initiative containing many security policies to evaluate resource configuration against best practice recommendations. If a policy in the MCSB is set with effect type Disabled, it is not evaluated and may prevent administrators from being informed of valuable security recommendations. ID: azure_cis_v210_2_1_13 -Title: "2.1.13 Ensure that Microsoft Cloud Security Benchmark policies are not set to 'Disabled'" -Description: "The Microsoft Cloud Security Benchmark (or 'MCSB') is an Azure Policy Initiative containing many security policies to evaluate resource configuration against best practice recommendations. If a policy in the MCSB is set with effect type Disabled, it is not evaluated and may prevent administrators from being informed of valuable security recommendations." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.1.13 Ensure that Microsoft Cloud Security Benchmark policies are not set to 'Disabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_14.yaml b/compliance/controls/azure/azure_cis_v210_2_1_14.yaml old mode 100755 new mode 100644 index 3df8610ee..ebb8e06ca --- a/compliance/controls/azure/azure_cis_v210_2_1_14.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_14.yaml @@ -1,30 +1,33 @@ +Description: Enable automatic provisioning of the monitoring agent to collect security data. ID: azure_cis_v210_2_1_14 -Title: "2.1.14 Ensure that Auto provisioning of 'Log Analytics agent for Azure VMs' is Set to 'On'" -Description: "Enable automatic provisioning of the monitoring agent to collect security data." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_prov.id as resource, - sc_prov.og_account_id as og_account_id, - sc_prov.og_resource_id as og_resource_id, - case - when auto_provision = 'On' then 'ok' - else 'alarm' - end as status, - case - when auto_provision = 'On' then 'Automatic provisioning of monitoring agent is on.' - else 'Automatic provisioning of monitoring agent is off.' - end as reason - from - azure_security_center_auto_provisioning sc_prov - right join azure_subscription sub on sc_prov.subscription_id = sub.subscription_id; - PrimaryTable: azure_security_center_auto_provisioning ListOfTables: - azure_security_center_auto_provisioning - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_auto_provisioning + QueryToExecute: | + SELECT + sc_prov.id AS resource, + sc_prov.og_account_id AS og_account_id, + sc_prov.og_resource_id AS og_resource_id, + CASE + WHEN auto_provision = 'On' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_provision = 'On' THEN 'Automatic provisioning of monitoring agent is on.' + ELSE 'Automatic provisioning of monitoring agent is off.' + END AS reason + FROM + azure_security_center_auto_provisioning sc_prov + RIGHT JOIN + azure_subscription sub + ON + sc_prov.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.14 Ensure that Auto provisioning of 'Log Analytics agent for Azure VMs' is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_15.yaml b/compliance/controls/azure/azure_cis_v210_2_1_15.yaml old mode 100755 new mode 100644 index 25e373f56..09e2bbd36 --- a/compliance/controls/azure/azure_cis_v210_2_1_15.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_15.yaml @@ -1,24 +1,24 @@ +Description: Enable automatic provisioning of vulnerability assessment for machines on both Azure and hybrid (Arc enabled) machines. ID: azure_cis_v210_2_1_15 -Title: "2.1.15 Ensure that Auto provisioning of 'Vulnerability assessment for machines' is Set to 'On'" -Description: "Enable automatic provisioning of vulnerability assessment for machines on both Azure and hybrid (Arc enabled) machines." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.1.15 Ensure that Auto provisioning of 'Vulnerability assessment for machines' is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_16.yaml b/compliance/controls/azure/azure_cis_v210_2_1_16.yaml old mode 100755 new mode 100644 index 37dd75c4a..48eb5dcc3 --- a/compliance/controls/azure/azure_cis_v210_2_1_16.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_16.yaml @@ -1,32 +1,33 @@ +Description: Enable automatic provisioning of the Microsoft Defender for Containers components. ID: azure_cis_v210_2_1_16 -Title: "2.1.16 Ensure that Auto provisioning of 'Microsoft Defender for Containers components' is Set to 'On'" -Description: "Enable automatic provisioning of the Microsoft Defender for Containers components." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Containers.' - else 'Azure Defender off for Containers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'Containers'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Containers.' + ELSE 'Azure Defender off for Containers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'Containers'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.16 Ensure that Auto provisioning of 'Microsoft Defender for Containers components' is Set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_17.yaml b/compliance/controls/azure/azure_cis_v210_2_1_17.yaml old mode 100755 new mode 100644 index fe6ef6c6d..7deebb63b --- a/compliance/controls/azure/azure_cis_v210_2_1_17.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_17.yaml @@ -1,40 +1,40 @@ +Description: Enable security alert emails to subscription owners. ID: azure_cis_v210_2_1_17 -Title: "2.1.17 Ensure That 'All users with the following roles' is set to 'Owner'" -Description: "Enable security alert emails to subscription owners." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with contact_info as ( - select - count(*) filter (where alerts_to_admins = 'On') as admin_alert_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alerts_to_admins = 'On') AS admin_alert_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when admin_alert_count > 0 then 'ok' - else 'alarm' - end as status, - case - when admin_alert_count > 0 then '"All users with the following roles" set to Owner' - else '"All users with the following roles" not set to Owner.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN admin_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN admin_alert_count > 0 THEN '"All users with the following roles" set to Owner' + ELSE '"All users with the following roles" not set to Owner.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - PrimaryTable: azure_subscription - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.17 Ensure That 'All users with the following roles' is set to 'Owner' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_18.yaml b/compliance/controls/azure/azure_cis_v210_2_1_18.yaml old mode 100755 new mode 100644 index 7d1449421..f9c2bb6c1 --- a/compliance/controls/azure/azure_cis_v210_2_1_18.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_18.yaml @@ -1,44 +1,44 @@ +Description: Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address. ID: azure_cis_v210_2_1_18 -Title: "2.1.18 Ensure 'Additional email addresses' is Configured with a Security Contact Email" -Description: "Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with contact_info as ( - select - jsonb_agg(email) filter (where name = 'default' and email != '') as default_email, - count(*) filter (where name != 'default') as non_default_count, - count(*) filter (where name = 'default') as default_count, + ListOfTables: + - azure_security_center_contact + - azure_subscription + Parameters: [] + PrimaryTable: azure_security_center_contact + QueryToExecute: | + WITH contact_info AS ( + SELECT + JSONB_AGG(email) FILTER (WHERE name = 'default' AND email != '') AS default_email, + COUNT(*) FILTER (WHERE name != 'default') AS non_default_count, + COUNT(*) FILTER (WHERE name = 'default') AS default_count, subscription_id - from + FROM azure_security_center_contact - group by + GROUP BY subscription_id - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when non_default_count > 0 then 'ok' - when default_count = 1 and jsonb_array_length(default_email) != 0 then 'ok' - else 'alarm' - end as status, - case - when non_default_count > 0 then 'Additional email addresses configured.' - when default_count = 1 and default_email is not null then 'Additional email addresses configured.' - else 'Additional email addresses not configured.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN non_default_count > 0 THEN 'ok' + WHEN default_count = 1 AND JSONB_ARRAY_LENGTH(default_email) != 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN non_default_count > 0 THEN 'Additional email addresses configured.' + WHEN default_count = 1 AND default_email IS NOT NULL THEN 'Additional email addresses configured.' + ELSE 'Additional email addresses not configured.' + END AS reason + FROM azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - PrimaryTable: azure_security_center_contact - ListOfTables: - - azure_security_center_contact - - azure_subscription - Parameters: [] + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.18 Ensure 'Additional email addresses' is Configured with a Security Contact Email \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_19.yaml b/compliance/controls/azure/azure_cis_v210_2_1_19.yaml old mode 100755 new mode 100644 index c8ce79e2f..71ef89303 --- a/compliance/controls/azure/azure_cis_v210_2_1_19.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_19.yaml @@ -1,40 +1,40 @@ +Description: Enables emailing security alerts to the subscription owner or other designated security contact. ID: azure_cis_v210_2_1_19 -Title: "2.1.19 Ensure That 'Notify about alerts with the following severity' is Set to 'High'" -Description: "Enables emailing security alerts to the subscription owner or other designated security contact." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with contact_info as ( - select - count(*) filter (where alert_notifications = 'On') as notification_alert_count, - subscription_id - from - azure_security_center_contact - group by - subscription_id - limit 1 - ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when notification_alert_count > 0 then 'ok' - else 'alarm' - end as status, - case - when notification_alert_count > 0 then '"Notify about alerts with the following severity" set to High.' - else '"Notify about alerts with the following severity" not set to High.' - end as reason - from - azure_subscription sub - left join contact_info ci on sub.subscription_id = ci.subscription_id; - PrimaryTable: azure_subscription ListOfTables: - azure_security_center_contact - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alert_notifications = 'On') AS notification_alert_count, + subscription_id + FROM + azure_security_center_contact + GROUP BY + subscription_id + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN notification_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN notification_alert_count > 0 THEN '"Notify about alerts with the following severity" set to High.' + ELSE '"Notify about alerts with the following severity" not set to High.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.19 Ensure That 'Notify about alerts with the following severity' is Set to 'High' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_2.yaml b/compliance/controls/azure/azure_cis_v210_2_1_2.yaml old mode 100755 new mode 100644 index 58ce1521a..5fd18928d --- a/compliance/controls/azure/azure_cis_v210_2_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_2.yaml @@ -1,32 +1,34 @@ +Description: Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v210_2_1_2 -Title: "2.1.2 Ensure That Microsoft Defender for App Services Is Set To 'On'" -Description: "Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for App Services.' - else 'Azure Defender off for App Services.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'AppServices'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for App Services.' + ELSE 'Azure Defender off for App Services.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'AppServices'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.2 Ensure That Microsoft Defender for App Services Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_20.yaml b/compliance/controls/azure/azure_cis_v210_2_1_20.yaml old mode 100755 new mode 100644 index 236427495..adf311b1b --- a/compliance/controls/azure/azure_cis_v210_2_1_20.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_20.yaml @@ -1,32 +1,35 @@ +Description: This integration setting enables Microsoft Defender for Cloud Apps (formerly 'Microsoft Cloud App Security' or 'MCAS' - see additional info) to communicate with Microsoft Defender for Cloud. ID: azure_cis_v210_2_1_20 -Title: "2.1.20 Ensure that Microsoft Defender for Cloud Apps integration with Microsoft Defender for Cloud is Selected" -Description: "This integration setting enables Microsoft Defender for Cloud Apps (formerly 'Microsoft Cloud App Security' or 'MCAS' - see additional info) to communicate with Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc_sett.id as resource, - sc_sett.og_account_id as og_account_id, - sc_sett.og_resource_id as og_resource_id, - case - when enabled then 'ok' - else 'alarm' - end as status, - case - when enabled then 'Windows Defender ATP (WDATP) integrated with Security Center.' - else 'Windows Defender ATP (WDATP) not integrated with Security Center.' - end as reason - from - azure_security_center_setting sc_sett - right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id - where - name = 'MCAS'; - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Windows Defender ATP (WDATP) integrated with Security Center.' + ELSE 'Windows Defender ATP (WDATP) not integrated with Security Center.' + END AS reason + FROM + azure_security_center_setting sc_sett + RIGHT JOIN + azure_subscription sub + ON + sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'MCAS'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.20 Ensure that Microsoft Defender for Cloud Apps integration with Microsoft Defender for Cloud is Selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_21.yaml b/compliance/controls/azure/azure_cis_v210_2_1_21.yaml old mode 100755 new mode 100644 index 0a0fa2ff1..0cec47812 --- a/compliance/controls/azure/azure_cis_v210_2_1_21.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_21.yaml @@ -1,15 +1,35 @@ +Description: This integration setting enables Microsoft Defender for Endpoint (formerly 'Advanced Threat Protection' or 'ATP' or 'WDATP' - see additional info) to communicate with Microsoft Defender for Cloud. ID: azure_cis_v210_2_1_21 -Title: "2.1.21 Ensure that Microsoft Defender for Endpoint integration with Microsoft Defender for Cloud is selected" -Description: "This integration setting enables Microsoft Defender for Endpoint (formerly 'Advanced Threat Protection' or 'ATP' or 'WDATP' - see additional info) to communicate with Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sc_sett.id as resource,\n sc_sett.og_account_id as og_account_id,\n sc_sett.og_resource_id as og_resource_id,\n case\n when enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when enabled then 'Microsoft Cloud App Security (MCAS) integrated with Security Center.'\n else 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.'\n end as reason\n \n \nfrom\n azure_security_center_setting sc_sett\n right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id\nwhere\n name = 'WDATP';" - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Microsoft Cloud App Security (MCAS) integrated with Security Center.' + ELSE 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.' + END AS reason + FROM + azure_security_center_setting sc_sett + RIGHT JOIN + azure_subscription sub + ON + sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'WDATP'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.21 Ensure that Microsoft Defender for Endpoint integration with Microsoft Defender for Cloud is selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_22.yaml b/compliance/controls/azure/azure_cis_v210_2_1_22.yaml old mode 100755 new mode 100644 index 4fdc9e0ea..45859ad77 --- a/compliance/controls/azure/azure_cis_v210_2_1_22.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_22.yaml @@ -1,24 +1,24 @@ +Description: An organization's attack surface is the collection of assets with a public network identifier or URI that an external threat actor can see or access from outside your cloud. It is the set of points on the boundary of a system, a system element, system component, or an environment where an attacker can try to enter, cause an effect on, or extract data from, that system, system element, system component, or environment. The larger the attack surface, the harder it is to protect. ID: azure_cis_v210_2_1_22 -Title: "2.1.22 Ensure that Microsoft Defender External Attack Surface Monitoring (EASM) is enabled" -Description: "An organization's attack surface is the collection of assets with a public network identifier or URI that an external threat actor can see or access from outside your cloud. It is the set of points on the boundary of a system, a system element, system component, or an environment where an attacker can try to enter, cause an effect on, or extract data from, that system, system element, system component, or environment. The larger the attack surface, the harder it is to protect." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.1.22 Ensure that Microsoft Defender External Attack Surface Monitoring (EASM) is enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_3.yaml b/compliance/controls/azure/azure_cis_v210_2_1_3.yaml old mode 100755 new mode 100644 index 08285296b..704abef89 --- a/compliance/controls/azure/azure_cis_v210_2_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_3.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v210_2_1_3 -Title: "2.1.3 Ensure That Microsoft Defender for (Managed Instance) Azure SQL Databases Is Set To 'On'" -Description: "Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for SQL database servers.' - else 'Azure Defender off for SQL database servers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'SqlServers'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL database servers.' + ELSE 'Azure Defender off for SQL database servers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub + ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServers'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.3 Ensure That Microsoft Defender for (Managed Instance) Azure SQL Databases Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_4.yaml b/compliance/controls/azure/azure_cis_v210_2_1_4.yaml old mode 100755 new mode 100644 index f6959c2fc..ece1a72fa --- a/compliance/controls/azure/azure_cis_v210_2_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_4.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v210_2_1_4 -Title: "2.1.4 Ensure That Microsoft Defender for SQL Servers on Machines Is Set To 'On'" -Description: "Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for SQL servers on machines.' - else 'Azure Defender off for SQL servers on machines.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'SqlServerVirtualMachines'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL servers on machines.' + ELSE 'Azure Defender off for SQL servers on machines.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServerVirtualMachines'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.4 Ensure That Microsoft Defender for SQL Servers on Machines Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_5.yaml b/compliance/controls/azure/azure_cis_v210_2_1_5.yaml old mode 100755 new mode 100644 index 8f782f92d..eb39146e0 --- a/compliance/controls/azure/azure_cis_v210_2_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_5.yaml @@ -1,32 +1,33 @@ +Description: Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v210_2_1_5 -Title: "2.1.5 Ensure That Microsoft Defender for Open-Source Relational Databases Is Set To 'On'" -Description: "Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Open Source Relational Databases.' - else 'Azure Defender off for Open Source Relational Databases.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'OpenSourceRelationalDatabases'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Open Source Relational Databases.' + ELSE 'Azure Defender off for Open Source Relational Databases.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'OpenSourceRelationalDatabases'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.5 Ensure That Microsoft Defender for Open-Source Relational Databases Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_6.yaml b/compliance/controls/azure/azure_cis_v210_2_1_6.yaml old mode 100755 new mode 100644 index 8467f8155..c057eb329 --- a/compliance/controls/azure/azure_cis_v210_2_1_6.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_6.yaml @@ -1,32 +1,33 @@ +Description: Microsoft Defender for Azure Cosmos DB scans all incoming network requests for threats to your Azure Cosmos DB resources. ID: azure_cis_v210_2_1_6 -Title: "2.1.6 Ensure That Microsoft Defender for Azure Cosmos DB Is Set To 'On'" -Description: "Microsoft Defender for Azure Cosmos DB scans all incoming network requests for threats to your Azure Cosmos DB resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Cosmos DB.' - else 'Azure Defender off for Cosmos DB.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'CosmosDbs'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Cosmos DB.' + ELSE 'Azure Defender off for Cosmos DB.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'CosmosDbs'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.6 Ensure That Microsoft Defender for Azure Cosmos DB Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_7.yaml b/compliance/controls/azure/azure_cis_v210_2_1_7.yaml old mode 100755 new mode 100644 index bca84ec00..cd9198c82 --- a/compliance/controls/azure/azure_cis_v210_2_1_7.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_7.yaml @@ -1,32 +1,32 @@ +Description: Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v210_2_1_7 -Title: "2.1.7 Ensure That Microsoft Defender for Storage Is Set To 'On'" -Description: "Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Storage.' - else 'Azure Defender off for Storage.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'StorageAccounts'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Storage.' + ELSE 'Azure Defender off for Storage.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'StorageAccounts'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.7 Ensure That Microsoft Defender for Storage Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_1_8.yaml b/compliance/controls/azure/azure_cis_v210_2_1_8.yaml old mode 100755 new mode 100644 index cc6517476..4ed58b207 --- a/compliance/controls/azure/azure_cis_v210_2_1_8.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_1_8.yaml @@ -1,15 +1,35 @@ +Description: Turning on Microsoft Defender for Containers enables threat detection for Container Registries including Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v210_2_1_8 -Title: "2.1.8 Ensure That Microsoft Defender for Containers Is Set To 'On'" -Description: "Turning on Microsoft Defender for Containers enables threat detection for Container Registries including Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Container Registry.'\n else 'Azure Defender off for Container Registry.'\n end as reason\n \n \nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'ContainerRegistry';" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Container Registry.' + ELSE 'Azure Defender off for Container Registry.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'ContainerRegistry'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.8 Ensure That Microsoft Defender for Containers Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_2_2_1.yaml b/compliance/controls/azure/azure_cis_v210_2_2_1.yaml old mode 100755 new mode 100644 index 2bd23f5ea..df37772d3 --- a/compliance/controls/azure/azure_cis_v210_2_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_2_2_1.yaml @@ -1,24 +1,24 @@ +Description: Microsoft Defender for IoT acts as a central security hub for IoT devices within your organization. ID: azure_cis_v210_2_2_1 -Title: "2.2.1 Ensure That Microsoft Defender for IoT Hub Is Set To 'On'" -Description: "Microsoft Defender for IoT acts as a central security hub for IoT devices within your organization." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 2.2.1 Ensure That Microsoft Defender for IoT Hub Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_1.yaml b/compliance/controls/azure/azure_cis_v210_3_1.yaml old mode 100755 new mode 100644 index 248ca1681..17acce392 --- a/compliance/controls/azure/azure_cis_v210_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_1.yaml @@ -1,32 +1,32 @@ +Description: Enable data encryption in transit. ID: azure_cis_v210_3_1 -Title: "3.1 Ensure that 'Secure transfer required' is set to 'Enabled'" -Description: "Enable data encryption in transit." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not enable_https_traffic_only then 'alarm' - else 'ok' - end as status, - case - when not enable_https_traffic_only then sa.name || ' encryption in transit not enabled.' - else sa.name || ' encryption in transit enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT enable_https_traffic_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT enable_https_traffic_only THEN sa.name || ' encryption in transit not enabled.' + ELSE sa.name || ' encryption in transit enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.1 Ensure that 'Secure transfer required' is set to 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_10.yaml b/compliance/controls/azure/azure_cis_v210_3_10.yaml old mode 100755 new mode 100644 index 65446f8c4..873ab7bdc --- a/compliance/controls/azure/azure_cis_v210_3_10.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_10.yaml @@ -1,42 +1,42 @@ +Description: Use private endpoints for your Azure Storage accounts to allow clients and services to securely access data located over a network via an encrypted Private Link. To do this, the private endpoint uses an IP address from the VNet for each service. Network traffic between disparate services securely traverses encrypted over the VNet. ID: azure_cis_v210_3_10 -Title: "3.10 Ensure Private Endpoints are used to access Storage Accounts" -Description: "Use private endpoints for your Azure Storage accounts to allow clients and services to securely access data located over a network via an encrypted Private Link. To do this, the private endpoint uses an IP address from the VNet for each service. Network traffic between disparate services securely traverses encrypted over the VNet." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with storage_account_connection as ( - select - distinct a.id - from - azure_storage_account as a, - jsonb_array_elements(private_endpoint_connections) as connection - where - connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' - ) - select - distinct a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when s.id is null then 'alarm' - else 'ok' - end as status, - case - when s.id is null then a.name || ' not uses private link.' - else a.name || ' uses private link.' - end as reason - from - azure_storage_account as a - left join storage_account_connection as s on a.id = s.id, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + WITH storage_account_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_storage_account AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + DISTINCT a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN s.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason + FROM + azure_storage_account AS a + LEFT JOIN storage_account_connection AS s ON a.id = s.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.10 Ensure Private Endpoints are used to access Storage Accounts \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_11.yaml b/compliance/controls/azure/azure_cis_v210_3_11.yaml old mode 100755 new mode 100644 index 7f7b0c19b..1dd72a392 --- a/compliance/controls/azure/azure_cis_v210_3_11.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_11.yaml @@ -1,32 +1,32 @@ +Description: The Azure Storage blobs contain data like ePHI or Financial, which can be secret or personal. Data that is erroneously modified or deleted by an application or other storage account user will cause data loss or unavailability. ID: azure_cis_v210_3_11 -Title: "3.11 Ensure Soft Delete is Enabled for Azure Containers and Blob Storage" -Description: "The Azure Storage blobs contain data like ePHI or Financial, which can be secret or personal. Data that is erroneously modified or deleted by an application or other storage account user will cause data loss or unavailability." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not blob_soft_delete_enabled then 'alarm' - else 'ok' - end as status, - case - when not blob_soft_delete_enabled then sa.name || ' blobs soft delete disabled.' - else sa.name || ' blobs soft delete enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT blob_soft_delete_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT blob_soft_delete_enabled THEN sa.name || ' blobs soft delete disabled.' + ELSE sa.name || ' blobs soft delete enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.11 Ensure Soft Delete is Enabled for Azure Containers and Blob Storage \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_12.yaml b/compliance/controls/azure/azure_cis_v210_3_12.yaml old mode 100755 new mode 100644 index d6d27f2bc..4a1f2797e --- a/compliance/controls/azure/azure_cis_v210_3_12.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_12.yaml @@ -1,32 +1,32 @@ +Description: Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys. ID: azure_cis_v210_3_12 -Title: "3.12 Ensure Storage for Critical Data are Encrypted with Customer Managed Keys" -Description: "Enable sensitive data encryption at rest using Customer Managed Keys rather than Microsoft Managed keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when sa.encryption_key_source = 'Microsoft.Storage' then 'alarm' - else 'ok' - end as status, - case - when sa.encryption_key_source = 'Microsoft.Storage' then sa.name || ' not encrypted with CMK.' - else sa.name || ' encrypted with CMK.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN sa.name || ' not encrypted with CMK.' + ELSE sa.name || ' encrypted with CMK.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.12 Ensure Storage for Critical Data are Encrypted with Customer Managed Keys \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_13.yaml b/compliance/controls/azure/azure_cis_v210_3_13.yaml old mode 100755 new mode 100644 index 5d374d3f4..dd3f04cbb --- a/compliance/controls/azure/azure_cis_v210_3_13.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_13.yaml @@ -1,41 +1,41 @@ +Description: 'The Storage Blob service provides scalable, cost-efficient object storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.' ID: azure_cis_v210_3_13 -Title: "3.13 Ensure Storage logging is Enabled for Blob Service for 'Read', 'Write', and 'Delete' requests" -Description: "The Storage Blob service provides scalable, cost-efficient object storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when not (sa.blob_service_logging ->> 'Read') :: boolean - or not (sa.blob_service_logging ->> 'Write') :: boolean - or not (sa.blob_service_logging ->> 'Delete') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (sa.blob_service_logging ->> 'Read') :: boolean - or not (sa.blob_service_logging ->> 'Write') :: boolean - or not (sa.blob_service_logging ->> 'Delete') :: boolean then name || ' blob service logging not enabled for ' || - concat_ws(', ', - case when not (sa.blob_service_logging ->> 'Write') :: boolean then 'write' end, - case when not (sa.blob_service_logging ->> 'Read') :: boolean then 'read' end, - case when not (sa.blob_service_logging ->> 'Delete') :: boolean then 'delete' end - ) || ' requests.' - else name || ' blob service logging enabled for read, write, delete requests.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN name || ' blob service logging not enabled for ' || + CONCAT_WS(', ', + CASE WHEN NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN THEN 'write' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN THEN 'read' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN 'delete' END + ) || ' requests.' + ELSE name || ' blob service logging enabled for read, write, delete requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.13 Ensure Storage logging is Enabled for Blob Service for 'Read', 'Write', and 'Delete' requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_14.yaml b/compliance/controls/azure/azure_cis_v210_3_14.yaml old mode 100755 new mode 100644 index 58ee0f43f..a0f648e0c --- a/compliance/controls/azure/azure_cis_v210_3_14.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_14.yaml @@ -1,38 +1,38 @@ +Description: 'Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.' ID: azure_cis_v210_3_14 -Title: "3.14 Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' Requests" -Description: "Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when table_logging_write and table_logging_read and table_logging_delete then 'ok' - else 'alarm' - end as status, - case - when table_logging_write and table_logging_read and table_logging_delete - then sa.name || ' table service logging enabled for read, write, delete requests.' - else sa.name || ' table service logging not enabled for: ' || - concat_ws(', ', - case when not table_logging_write then 'write' end, - case when not table_logging_read then 'read' end, - case when not table_logging_delete then 'delete' end - ) || ' requests.' - end as reason - from - azure_storage_account as sa, - azure_subscription as sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN table_logging_write AND table_logging_read AND table_logging_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN table_logging_write AND table_logging_read AND table_logging_delete + THEN sa.name || ' table service logging enabled for read, write, delete requests.' + ELSE sa.name || ' table service logging not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT table_logging_write THEN 'write' END, + CASE WHEN NOT table_logging_read THEN 'read' END, + CASE WHEN NOT table_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.14 Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' Requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_15.yaml b/compliance/controls/azure/azure_cis_v210_3_15.yaml old mode 100755 new mode 100644 index 39cac5550..448e1b639 --- a/compliance/controls/azure/azure_cis_v210_3_15.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_15.yaml @@ -1,34 +1,34 @@ +Description: In some cases, Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2. ID: azure_cis_v210_3_15 -Title: "3.15 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2'" -Description: "In some cases, Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when minimum_tls_version = 'TLSEnforcementDisabled' then 'alarm' - when minimum_tls_version = 'TLS1_2' then 'ok' - else 'alarm' - end as status, - case - when minimum_tls_version = 'TLSEnforcementDisabled' then sa.name || ' TLS enforcement is disabled.' - when minimum_tls_version = 'TLS1_2' then sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' - else sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN minimum_tls_version = 'TLSEnforcementDisabled' THEN 'alarm' + WHEN minimum_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_tls_version = 'TLSEnforcementDisabled' THEN sa.name || ' TLS enforcement is disabled.' + WHEN minimum_tls_version = 'TLS1_2' THEN sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + ELSE sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.15 Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_16.yaml b/compliance/controls/azure/azure_cis_v210_3_16.yaml old mode 100755 new mode 100644 index 0961cd536..fc1be0582 --- a/compliance/controls/azure/azure_cis_v210_3_16.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_16.yaml @@ -1,24 +1,27 @@ +Description: Cross Tenant Replication in Azure allows data to be replicated across multiple Azure tenants. + While this feature can be beneficial for data sharing and availability, it also poses a significant security risk if not properly managed. + Unauthorized data access, data leakage, and compliance violations are potential risks. + Disabling Cross Tenant Replication ensures that data is not inadvertently replicated across different tenant boundaries without explicit authorization. ID: azure_cis_v210_3_16 -Title: "3.16 Ensure 'Cross Tenant Replication' is not enabled" -Description: "Cross Tenant Replication in Azure allows data to be replicated across multiple Azure tenants. While this feature can be beneficial for data sharing and availability, it also poses a significant security risk if not properly managed. Unauthorized data access, data leakage, and compliance violations are potential risks. Disabling Cross Tenant Replication ensures that data is not inadvertently replicated across different tenant boundaries without explicit authorization." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.16 Ensure 'Cross Tenant Replication' is not enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_2.yaml b/compliance/controls/azure/azure_cis_v210_3_2.yaml old mode 100755 new mode 100644 index 7992cf3b7..0d20a4c8b --- a/compliance/controls/azure/azure_cis_v210_3_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_2.yaml @@ -1,32 +1,32 @@ +Description: Enabling encryption at the hardware level on top of the default software encryption for Storage Accounts accessing Azure storage solutions. ID: azure_cis_v210_3_2 -Title: "3.2 Ensure that 'Enable Infrastructure Encryption' for Each Storage Account in Azure Storage is Set to 'enabled'" -Description: "Enabling encryption at the hardware level on top of the default software encryption for Storage Accounts accessing Azure storage solutions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when require_infrastructure_encryption then 'ok' - else 'alarm' - end as status, - case - when require_infrastructure_encryption then name || ' infrastructure encryption enabled.' - else name || ' infrastructure encryption disabled.' - end as reason - from - azure_storage_account as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN require_infrastructure_encryption THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN require_infrastructure_encryption THEN name || ' infrastructure encryption enabled.' + ELSE name || ' infrastructure encryption disabled.' + END AS reason + FROM + azure_storage_account AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.2 Ensure that 'Enable Infrastructure Encryption' for Each Storage Account in Azure Storage is Set to 'enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_3.yaml b/compliance/controls/azure/azure_cis_v210_3_3.yaml old mode 100755 new mode 100644 index 402e7987d..34a95f6cb --- a/compliance/controls/azure/azure_cis_v210_3_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_3.yaml @@ -1,24 +1,24 @@ +Description: Access Keys authenticate application access requests to data contained in Storage Accounts. A periodic rotation of these keys is recommended to ensure that potentially compromised keys cannot result in a long-term exploitable credential. The 'Rotation Reminder' is an automatic reminder feature for a manual procedure. ID: azure_cis_v210_3_3 -Title: "3.3 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account" -Description: "Access Keys authenticate application access requests to data contained in Storage Accounts. A periodic rotation of these keys is recommended to ensure that potentially compromised keys cannot result in a long-term exploitable credential. The 'Rotation Reminder' is an automatic reminder feature for a manual procedure." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.3 Ensure that 'Enable key rotation reminders' is enabled for each Storage Account \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_4.yaml b/compliance/controls/azure/azure_cis_v210_3_4.yaml old mode 100755 new mode 100644 index 012dd9954..12821ec21 --- a/compliance/controls/azure/azure_cis_v210_3_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_4.yaml @@ -1,24 +1,24 @@ +Description: For increased security, regenerate storage account access keys periodically. ID: azure_cis_v210_3_4 -Title: "3.4 Ensure that Storage Account Access Keys are Periodically Regenerated" -Description: "For increased security, regenerate storage account access keys periodically." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.4 Ensure that Storage Account Access Keys are Periodically Regenerated \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_5.yaml b/compliance/controls/azure/azure_cis_v210_3_5.yaml old mode 100755 new mode 100644 index 058742307..d1e109e1a --- a/compliance/controls/azure/azure_cis_v210_3_5.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_5.yaml @@ -1,38 +1,38 @@ +Description: The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. ID: azure_cis_v210_3_5 -Title: "3.5 Ensure Storage Logging is Enabled for Queue Service for 'Read', 'Write', and 'Delete' requests" -Description: "The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when queue_logging_read and queue_logging_write and queue_logging_delete then 'ok' - else 'alarm' - end as status, - case - when queue_logging_read and queue_logging_write and queue_logging_delete - then sa.name || ' queue service logging enabled for read, write, delete requests.' - else sa.name || ' queue service logging not enabled for: ' || - concat_ws(', ', - case when not queue_logging_write then 'write' end, - case when not queue_logging_read then 'read' end, - case when not queue_logging_delete then 'delete' end - ) || ' requests.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete + THEN sa.name || ' queue service logging enabled for read, write, delete requests.' + ELSE sa.name || ' queue service logging not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT queue_logging_write THEN 'write' END, + CASE WHEN NOT queue_logging_read THEN 'read' END, + CASE WHEN NOT queue_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.5 Ensure Storage Logging is Enabled for Queue Service for 'Read', 'Write', and 'Delete' requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_6.yaml b/compliance/controls/azure/azure_cis_v210_3_6.yaml old mode 100755 new mode 100644 index 155a3eb8a..4c367a7e1 --- a/compliance/controls/azure/azure_cis_v210_3_6.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_6.yaml @@ -1,24 +1,24 @@ +Description: Expire shared access signature tokens within an hour. ID: azure_cis_v210_3_6 -Title: "3.6 Ensure that Shared Access Signature Tokens Expire Within an Hour" -Description: "Expire shared access signature tokens within an hour." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 3.6 Ensure that Shared Access Signature Tokens Expire Within an Hour \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_7.yaml b/compliance/controls/azure/azure_cis_v210_3_7.yaml old mode 100755 new mode 100644 index d9b79fdb1..7d2d11981 --- a/compliance/controls/azure/azure_cis_v210_3_7.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_7.yaml @@ -1,32 +1,32 @@ +Description: Disallowing public network access for a storage account overrides the public access settings for individual containers in that storage account for Azure Resource Manager Deployment Model storage accounts. Azure Storage accounts that use the classic deployment model will be retired on August 31, 2024. ID: azure_cis_v210_3_7 -Title: "3.7 Ensure that 'Public Network Access' is `Disabled' for storage accounts" -Description: "Disallowing public network access for a storage account overrides the public access settings for individual containers in that storage account for Azure Resource Manager Deployment Model storage accounts. Azure Storage accounts that use the classic deployment model will be retired on August 31, 2024." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when lower(sa.public_network_access) = 'disabled' then 'ok' - else 'alarm' - end as status, - case - when lower(sa.public_network_access) = 'disabled' then sa.name || ' not publicy accessible.' - else sa.name || ' publicy accessible.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(sa.public_network_access) = 'disabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN LOWER(sa.public_network_access) = 'disabled' THEN sa.name || ' not publicly accessible.' + ELSE sa.name || ' publicly accessible.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.7 Ensure that 'Public Network Access' is `Disabled' for storage accounts \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_8.yaml b/compliance/controls/azure/azure_cis_v210_3_8.yaml old mode 100755 new mode 100644 index 1fde908e6..ff91ab801 --- a/compliance/controls/azure/azure_cis_v210_3_8.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_8.yaml @@ -1,32 +1,32 @@ +Description: Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed. ID: azure_cis_v210_3_8 -Title: "3.8 Ensure Default Network Access Rule for Storage Accounts is Set to Deny" -Description: "Restricting default network access helps to provide a new layer of security, since storage accounts accept connections from clients on any network. To limit access to selected networks, the default action must be changed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when sa.network_rule_default_action = 'Allow' then 'alarm' - else 'ok' - end as status, - case - when sa.network_rule_default_action = 'Allow' then name || ' allows traffic from all networks.' - else name || ' allows traffic from specific networks.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN name || ' allows traffic from all networks.' + ELSE name || ' allows traffic from specific networks.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.8 Ensure Default Network Access Rule for Storage Accounts is Set to Deny \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_3_9.yaml b/compliance/controls/azure/azure_cis_v210_3_9.yaml old mode 100755 new mode 100644 index 79b238a0b..9f170cf71 --- a/compliance/controls/azure/azure_cis_v210_3_9.yaml +++ b/compliance/controls/azure/azure_cis_v210_3_9.yaml @@ -1,32 +1,32 @@ +Description: Some Azure services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account. ID: azure_cis_v210_3_9 -Title: "3.9 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access" -Description: "Some Azure services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when network_rule_bypass not like '%AzureServices%' then 'alarm' - else 'ok' - end as status, - case - when network_rule_bypass not like '%AzureServices%' then sa.name || ' trusted Microsoft services not enabled.' - else sa.name || ' trusted Microsoft services enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN sa.name || ' trusted Microsoft services not enabled.' + ELSE sa.name || ' trusted Microsoft services enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.9 Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_1_2.yaml b/compliance/controls/azure/azure_cis_v210_4_1_2.yaml old mode 100755 new mode 100644 index 949c8a38a..79f5c0572 --- a/compliance/controls/azure/azure_cis_v210_4_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_1_2.yaml @@ -1,36 +1,36 @@ +Description: Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP). ID: azure_cis_v210_4_1_2 -Title: "4.1.2 Ensure no Azure SQL Databases allow ingress from 0.0.0.0/0 (ANY IP)" -Description: "Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' - or firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' - then 'alarm' - else 'ok' - end as status, - case - when firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' - or firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' - then s.title || ' allows ingress 0.0.0.0/0 or any ip over internet.' - else s.title || ' not allows ingress 0.0.0.0/0 or any ip over internet.' - end as reason - from - azure_sql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN s.title || ' allows ingress 0.0.0.0/0 or any IP over the internet.' + ELSE s.title || ' does not allow ingress 0.0.0.0/0 or any IP over the internet.' + END AS reason + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.2 Ensure no Azure SQL Databases allow ingress from 0.0.0.0/0 (ANY IP) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_1_4.yaml b/compliance/controls/azure/azure_cis_v210_4_1_4.yaml old mode 100755 new mode 100644 index 3eef810c2..6b60dd6e3 --- a/compliance/controls/azure/azure_cis_v210_4_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_1_4.yaml @@ -1,32 +1,32 @@ +Description: Use Azure Active Directory Authentication for authentication with SQL Database to manage credentials in a single place. ID: azure_cis_v210_4_1_4 -Title: "4.1.4 Ensure that Microsoft Entra authentication is Configured for SQL Servers" -Description: "Use Azure Active Directory Authentication for authentication with SQL Database to manage credentials in a single place." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when server_azure_ad_administrator is null then 'alarm' - else 'ok' - end as status, - case - when server_azure_ad_administrator is null then name || ' Azure AD authentication not configured.' - else name || ' Azure AD authentication configured.' - end as reason - from - azure_sql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN server_azure_ad_administrator IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN server_azure_ad_administrator IS NULL THEN name || ' Azure AD authentication not configured.' + ELSE name || ' Azure AD authentication configured.' + END AS reason + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.4 Ensure that Microsoft Entra authentication is Configured for SQL Servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_1_5.yaml b/compliance/controls/azure/azure_cis_v210_4_1_5.yaml old mode 100755 new mode 100644 index 8e8771045..46c2e6346 --- a/compliance/controls/azure/azure_cis_v210_4_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_1_5.yaml @@ -1,33 +1,33 @@ +Description: Enable Transparent Data Encryption on every SQL server. ID: azure_cis_v210_4_1_5 -Title: "4.1.5 Ensure that 'Data encryption' is set to 'On' on a SQL Database" -Description: "Enable Transparent Data Encryption on every SQL server." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.database_id resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then s.title || ' transparent data encryption enabled.' - else s.title || ' transparent data encryption disabled.' - end as reason - from - azure_sql_database as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id - and s.name <> 'master'; - PrimaryTable: azure_sql_database ListOfTables: - azure_sql_database - azure_subscription Parameters: [] + PrimaryTable: azure_sql_database + QueryToExecute: | + SELECT + s.database_id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' OR transparent_data_encryption ->> 'state' = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' OR transparent_data_encryption ->> 'state' = 'Enabled' THEN s.title || ' transparent data encryption enabled.' + ELSE s.title || ' transparent data encryption disabled.' + END AS reason + FROM + azure_sql_database AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id + AND s.name <> 'master'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.5 Ensure that 'Data encryption' is set to 'On' on a SQL Database \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_3_1.yaml b/compliance/controls/azure/azure_cis_v210_4_3_1.yaml old mode 100755 new mode 100644 index 340428bb9..f182e491c --- a/compliance/controls/azure/azure_cis_v210_4_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_3_1.yaml @@ -1,32 +1,32 @@ +Description: Enable SSL connection on PostgreSQL Servers. ID: azure_cis_v210_4_3_1 -Title: "4.3.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for PostgreSQL Database Server" -Description: "Enable SSL connection on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when ssl_enforcement = 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when ssl_enforcement = 'Disabled' then name || ' SSL connection disabled.' - else name || ' SSL connection enabled.' - end as reason - from - azure_postgresql_server s, - azure_subscription sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN name || ' SSL connection disabled.' + ELSE name || ' SSL connection enabled.' + END AS reason + FROM + azure_postgresql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.1 Ensure 'Enforce SSL connection' is set to 'ENABLED' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_3_7.yaml b/compliance/controls/azure/azure_cis_v210_4_3_7.yaml old mode 100755 new mode 100644 index 2370309f9..912e7508a --- a/compliance/controls/azure/azure_cis_v210_4_3_7.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_3_7.yaml @@ -1,43 +1,44 @@ +Description: Disable access from Azure services to PostgreSQL Database Server. ID: azure_cis_v210_4_3_7 -Title: "4.3.7 Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled" -Description: "Disable access from Azure services to PostgreSQL Database Server." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_postgresql_server + - azure_subscription + Parameters: [] + PrimaryTable: azure_postgresql_server QueryToExecute: | - with postgres_db_with_allow_access_to_azure_services as ( - select + WITH postgres_db_with_allow_access_to_azure_services AS ( + SELECT id - from + FROM azure_postgresql_server, - jsonb_array_elements(firewall_rules) as r - where + jsonb_array_elements(firewall_rules) AS r + WHERE r -> 'FirewallRuleProperties' ->> 'endIpAddress' = '0.0.0.0' - and r -> 'FirewallRuleProperties' ->> 'startIpAddress' = '0.0.0.0' + AND r -> 'FirewallRuleProperties' ->> 'startIpAddress' = '0.0.0.0' ) - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when a.id is not null then 'alarm' - else 'ok' - end as status, - case - when a.id is not null then s.title || ' does not restrict access to azure services.' - else s.title || ' restricts access to azure services.' - end as reason - from - azure_postgresql_server as s - left join postgres_db_with_allow_access_to_azure_services as a on a.id = s.id, - azure_subscription as sub - where + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN a.id IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.id IS NOT NULL THEN s.title || ' does not restrict access to Azure services.' + ELSE s.title || ' restricts access to Azure services.' + END AS reason + FROM + azure_postgresql_server AS s + LEFT JOIN + postgres_db_with_allow_access_to_azure_services AS a ON a.id = s.id, + azure_subscription AS sub + WHERE sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server - ListOfTables: - - azure_postgresql_server - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.7 Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_3_8.yaml b/compliance/controls/azure/azure_cis_v210_4_3_8.yaml old mode 100755 new mode 100644 index 71306b621..6be414a57 --- a/compliance/controls/azure/azure_cis_v210_4_3_8.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_3_8.yaml @@ -1,32 +1,32 @@ +Description: Azure Database for PostgreSQL servers should be created with 'infrastructure double encryption' enabled. ID: azure_cis_v210_4_3_8 -Title: "4.3.8 Ensure 'Infrastructure double encryption' for PostgreSQL Database Server is 'Enabled'" -Description: "Azure Database for PostgreSQL servers should be created with 'infrastructure double encryption' enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when infrastructure_encryption = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when infrastructure_encryption = 'Enabled' then name || ' infrastructure encryption enabled.' - else name || ' infrastructure encryption disabled.' - end as reason - from - azure_postgresql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN name || ' infrastructure encryption enabled.' + ELSE name || ' infrastructure encryption disabled.' + END AS reason + FROM + azure_postgresql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.8 Ensure 'Infrastructure double encryption' for PostgreSQL Database Server is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_4_1.yaml b/compliance/controls/azure/azure_cis_v210_4_4_1.yaml old mode 100755 new mode 100644 index 925b5ae98..7f9cb9f14 --- a/compliance/controls/azure/azure_cis_v210_4_4_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_4_1.yaml @@ -1,32 +1,32 @@ +Description: Enable SSL connection on MySQL Servers. ID: azure_cis_v210_4_4_1 -Title: "4.4.1 Ensure 'Enforce SSL connection' is set to 'Enabled' for Standard MySQL Database Server" -Description: "Enable SSL connection on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when ssl_enforcement = 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when ssl_enforcement = 'Disabled' then s.name || ' SSL connection disabled.' - else s.name || ' SSL connection enabled.' - end as reason - from - azure_mysql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN s.name || ' SSL connection disabled.' + ELSE s.name || ' SSL connection enabled.' + END AS reason + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.1 Ensure 'Enforce SSL connection' is set to 'Enabled' for Standard MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_4_2.yaml b/compliance/controls/azure/azure_cis_v210_4_4_2.yaml old mode 100755 new mode 100644 index ffcc9488a..3bc36c1bf --- a/compliance/controls/azure/azure_cis_v210_4_4_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_4_2.yaml @@ -1,34 +1,34 @@ +Description: Ensure TLS version on MySQL flexible servers is set to use TLS version 1.2 or higher. ID: azure_cis_v210_4_4_2 -Title: "4.4.2 Ensure 'TLS Version' is set to 'TLSV1.2' for MySQL flexible Database Server" -Description: "Ensure TLS version on MySQL flexible servers is set to use TLS version 1.2 or higher." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when minimal_tls_version = 'TLSEnforcementDisabled' then 'alarm' - when minimal_tls_version = 'TLS1_2' then 'ok' - else 'alarm' - end as status, - case - when minimal_tls_version = 'TLSEnforcementDisabled' then s.name || ' TLS enforcement is disabled.' - when minimal_tls_version = 'TLS1_2' then s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' - else s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' - end as reason - from - azure_mysql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN minimal_tls_version = 'TLSEnforcementDisabled' THEN 'alarm' + WHEN minimal_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimal_tls_version = 'TLSEnforcementDisabled' THEN s.name || ' TLS enforcement is disabled.' + WHEN minimal_tls_version = 'TLS1_2' THEN s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' + ELSE s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' + END AS reason + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.2 Ensure 'TLS Version' is set to 'TLSV1.2' for MySQL flexible Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_5_1.yaml b/compliance/controls/azure/azure_cis_v210_4_5_1.yaml old mode 100755 new mode 100644 index 0b457318e..bf293bc9f --- a/compliance/controls/azure/azure_cis_v210_4_5_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_5_1.yaml @@ -1,34 +1,34 @@ +Description: Limiting your Cosmos DB to only communicate on whitelisted networks lowers its attack footprint. ID: azure_cis_v210_4_5_1 -Title: "4.5.1 Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks" -Description: "Limiting your Cosmos DB to only communicate on whitelisted networks lowers its attack footprint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when public_network_access = 'Disabled' then 'ok' - when public_network_access = 'Enabled' and is_virtual_network_filter_enabled = 'true' then 'ok' - else 'alarm' - end as status, - case - when public_network_access = 'Disabled' then a.name || ' public network access disabled.' - when public_network_access = 'Enabled' and is_virtual_network_filter_enabled = 'true' then a.name || ' virtual network filter enabled.' - else a.name || ' virtual network filter disabled.' - end as reason - from - azure_cosmosdb_account as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Disabled' THEN 'ok' + WHEN public_network_access = 'Enabled' AND is_virtual_network_filter_enabled = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN public_network_access = 'Disabled' THEN a.name || ' public network access disabled.' + WHEN public_network_access = 'Enabled' AND is_virtual_network_filter_enabled = 'true' THEN a.name || ' virtual network filter enabled.' + ELSE a.name || ' virtual network filter disabled.' + END AS reason + FROM + azure_cosmosdb_account AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.5.1 Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_5_2.yaml b/compliance/controls/azure/azure_cis_v210_4_5_2.yaml old mode 100755 new mode 100644 index eef33ac85..656530f04 --- a/compliance/controls/azure/azure_cis_v210_4_5_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_5_2.yaml @@ -1,42 +1,43 @@ +Description: Private endpoints limit network traffic to approved sources. ID: azure_cis_v210_4_5_2 -Title: "4.5.2 Ensure That Private Endpoints Are Used Where Possible" -Description: "Private endpoints limit network traffic to approved sources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with cosmosdb_private_connection as ( - select - distinct a.id - from - azure_cosmosdb_account as a, - jsonb_array_elements(private_endpoint_connections) as connection - where - connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' - ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when c.id is null then 'alarm' - else 'ok' - end as status, - case - when c.id is null then a.name || ' not uses private link.' - else a.name || ' uses private link.' - end as reason - from - azure_cosmosdb_account as a - left join cosmosdb_private_connection as c on c.id = a.id, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + WITH cosmosdb_private_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_cosmosdb_account AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason + FROM + azure_cosmosdb_account AS a + LEFT JOIN + cosmosdb_private_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.5.2 Ensure That Private Endpoints Are Used Where Possible \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_4_5_3.yaml b/compliance/controls/azure/azure_cis_v210_4_5_3.yaml old mode 100755 new mode 100644 index e5a883bb4..457de812b --- a/compliance/controls/azure/azure_cis_v210_4_5_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_4_5_3.yaml @@ -1,24 +1,24 @@ +Description: Cosmos DB can use tokens or AAD for client authentication which in turn will use Azure RBAC for authorization. Using AAD is significantly more secure because AAD handles the credentials and allows for MFA and centralized management, and the Azure RBAC better integrated with the rest of Azure. ID: azure_cis_v210_4_5_3 -Title: "4.5.3 Use Entra ID Client Authentication and Azure RBAC where possible" -Description: "Cosmos DB can use tokens or AAD for client authentication which in turn will use Azure RBAC for authorization. Using AAD is significantly more secure because AAD handles the credentials and allows for MFA and centralized management, and the Azure RBAC better integrated with the rest of Azure." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 4.5.3 Use Entra ID Client Authentication and Azure RBAC where possible \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_1_1.yaml b/compliance/controls/azure/azure_cis_v210_5_1_1.yaml old mode 100755 new mode 100644 index 4074cc945..913f14924 --- a/compliance/controls/azure/azure_cis_v210_5_1_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_1_1.yaml @@ -1,24 +1,24 @@ +Description: Enable Diagnostic settings for exporting activity logs. Diagnostic settings are available for each individual resource within a subscription. Settings should be configured for all appropriate resources for your environment. ID: azure_cis_v210_5_1_1 -Title: "5.1.1 Ensure that a 'Diagnostic Setting' exists for Subscription Activity Logs" -Description: "Enable Diagnostic settings for exporting activity logs. Diagnostic settings are available for each individual resource within a subscription. Settings should be configured for all appropriate resources for your environment." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.1 Ensure that a 'Diagnostic Setting' exists for Subscription Activity Logs \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_1_2.yaml b/compliance/controls/azure/azure_cis_v210_5_1_2.yaml old mode 100755 new mode 100644 index bcc7e817e..8990c5ed2 --- a/compliance/controls/azure/azure_cis_v210_5_1_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_1_2.yaml @@ -1,28 +1,34 @@ +Description: 'A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: ''Ensure that a ''Diagnostic Setting'' exists.'' The diagnostic setting should be configured to log the appropriate activities from the control/management plane.' ID: azure_cis_v210_5_1_2 -Title: "5.1.2 Ensure Diagnostic Setting captures appropriate categories" -Description: "A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: 'Ensure that a 'Diagnostic Setting' exists.' The diagnostic setting should be configured to log the appropriate activities from the control/management plane." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with enabled_settings as ( - select + ListOfTables: + - azure_diagnostic_setting + - azure_subscription + Parameters: [] + PrimaryTable: azure_diagnostic_setting + QueryToExecute: | + WITH enabled_settings AS ( + SELECT name, id, _ctx, resource_group, subscription_id, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - count(*) filter (where l ->> 'enabled' = 'true' - and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy') - ) as valid_category_count, - string_agg(l ->> 'category', ', ') filter (where l ->> 'enabled' = 'true' - and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy') - ) as valid_categories - from + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + COUNT(*) FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy') + ) AS valid_category_count, + STRING_AGG(l ->> 'category', ', ') FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy') + ) AS valid_categories + FROM azure_diagnostic_setting, - jsonb_array_elements(logs) as l - group by + jsonb_array_elements(logs) AS l + GROUP BY name, id, _ctx, @@ -31,32 +37,26 @@ Query: og_account_id, og_resource_id ) - select - sett.id as resource, - sett.og_account_id as og_account_id, - sett.og_resource_id as og_resource_id, - case - when valid_category_count = 4 then 'ok' - else 'alarm' - end as status, - case - when valid_category_count = 4 - then name || ' logs enabled for required categories administrative, security, alert and policy.' - when valid_category_count > 0 - then sett.name || ' logs enabled for ' || valid_categories || ' categories.' - else sett.name || ' logs not enabled for categories administrative, security, alert and policy.' - end as reason - from + SELECT + sett.id AS resource, + sett.og_account_id AS og_account_id, + sett.og_resource_id AS og_resource_id, + CASE + WHEN valid_category_count = 4 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN valid_category_count = 4 + THEN name || ' logs enabled for required categories administrative, security, alert and policy.' + WHEN valid_category_count > 0 + THEN sett.name || ' logs enabled for ' || valid_categories || ' categories.' + ELSE sett.name || ' logs not enabled for categories administrative, security, alert and policy.' + END AS reason + FROM enabled_settings sett, azure_subscription sub - where + WHERE sub.subscription_id = sett.subscription_id; - PrimaryTable: azure_diagnostic_setting - ListOfTables: - - azure_diagnostic_setting - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.2 Ensure Diagnostic Setting captures appropriate categories \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_1_3.yaml b/compliance/controls/azure/azure_cis_v210_5_1_3.yaml old mode 100755 new mode 100644 index 526fedc55..41b0c5a6e --- a/compliance/controls/azure/azure_cis_v210_5_1_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_1_3.yaml @@ -1,37 +1,37 @@ +Description: Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK). ID: azure_cis_v210_5_1_3 -Title: "5.1.3 Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key" -Description: "Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.encryption_key_source = 'Microsoft.Keyvault' then 'ok' - else 'alarm' - end as status, - case - when a.encryption_key_source = 'Microsoft.Keyvault' - then a.name || ' container insights-activity-logs encrypted with BYOK.' - else a.name || ' container insights-activity-logs not encrypted with BYOK.' - end as reason - from - azure_storage_container c, - azure_storage_account a, - azure_subscription sub - where - c.name = 'insights-activity-logs' - and c.account_name = a.name - and sub.subscription_id = a.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_container - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' + THEN a.name || ' container insights-activity-logs encrypted with BYOK.' + ELSE a.name || ' container insights-activity-logs not encrypted with BYOK.' + END AS reason + FROM + azure_storage_container c, + azure_storage_account a, + azure_subscription sub + WHERE + c.name = 'insights-activity-logs' + AND c.account_name = a.name + AND sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.3 Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_1_4.yaml b/compliance/controls/azure/azure_cis_v210_5_1_4.yaml old mode 100755 new mode 100644 index e6a7c42a4..2e96ab2e1 --- a/compliance/controls/azure/azure_cis_v210_5_1_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_1_4.yaml @@ -1,49 +1,49 @@ +Description: Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available. ID: azure_cis_v210_5_1_4 -Title: "5.1.4 Ensure that logging for Azure Key Vault is 'Enabled'" -Description: "Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with logging_details as ( - select - name as key_vault_name - from + ListOfTables: + - azure_key_vault + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + WITH logging_details AS ( + SELECT + name AS key_vault_name + FROM azure_key_vault, jsonb_array_elements(diagnostic_settings) setting, jsonb_array_elements(setting -> 'properties' -> 'logs') log - where - diagnostic_settings is not null - and setting -> 'properties' ->> 'storageAccountId' <> '' - and (log ->> 'enabled') :: boolean - and log ->> 'category' = 'AuditEvent' - and (log -> 'retentionPolicy') :: JSONB ? 'days' + WHERE + diagnostic_settings IS NOT NULL + AND setting -> 'properties' ->> 'storageAccountId' <> '' + AND (log ->> 'enabled')::BOOLEAN + AND log ->> 'category' = 'AuditEvent' + AND (log -> 'retentionPolicy')::JSONB ? 'days' ) - select - v.id as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when v.diagnostic_settings is null then 'alarm' - when l.key_vault_name not like concat('%', v.name, '%') then 'alarm' - else 'ok' - end as status, - case - when v.diagnostic_settings is null then v.name || ' logging not enabled.' - when l.key_vault_name not like concat('%', v.name, '%') then v.name || ' logging not enabled.' - else v.name || ' logging enabled.' - end as reason - from + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason + FROM azure_key_vault v, logging_details l, azure_subscription sub - where + WHERE sub.subscription_id = v.subscription_id; - PrimaryTable: azure_key_vault - ListOfTables: - - azure_key_vault - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.4 Ensure that logging for Azure Key Vault is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_1_5.yaml b/compliance/controls/azure/azure_cis_v210_5_1_5.yaml old mode 100755 new mode 100644 index 2d979a381..4c0181c6b --- a/compliance/controls/azure/azure_cis_v210_5_1_5.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_1_5.yaml @@ -1,24 +1,24 @@ +Description: Ensure that network flow logs are captured and fed into a central log analytics workspace. ID: azure_cis_v210_5_1_5 -Title: "5.1.5 Ensure that Network Security Group Flow logs are captured and sent to Log Analytics" -Description: "Ensure that network flow logs are captured and fed into a central log analytics workspace." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.5 Ensure that Network Security Group Flow logs are captured and sent to Log Analytics \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_1_6.yaml b/compliance/controls/azure/azure_cis_v210_5_1_6.yaml old mode 100755 new mode 100644 index 53fe9d1a3..c497a6bfc --- a/compliance/controls/azure/azure_cis_v210_5_1_6.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_1_6.yaml @@ -1,24 +1,24 @@ +Description: Enable AppServiceHTTPLogs diagnostic log category for Azure App Service instances to ensure all http requests are captured and centrally logged. ID: azure_cis_v210_5_1_6 -Title: "5.1.6 Ensure that logging for Azure AppService 'HTTP logs' is enabled" -Description: "Enable AppServiceHTTPLogs diagnostic log category for Azure App Service instances to ensure all http requests are captured and centrally logged." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.1.6 Ensure that logging for Azure AppService 'HTTP logs' is enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_2_1.yaml b/compliance/controls/azure/azure_cis_v210_5_2_1.yaml old mode 100755 new mode 100644 index 6a84b145a..657d0dd4d --- a/compliance/controls/azure/azure_cis_v210_5_2_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_2_1.yaml @@ -1,55 +1,55 @@ +Description: Create an activity log alert for the Create Policy Assignment event. ID: azure_cis_v210_5_2_1 -Title: "5.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment" -Description: "Create an activity log alert for the Create Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' - limit 1 + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' + LIMIT 1 ) - select - a.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create policy assignment event.' - else 'Activity log alert does not exists for create policy assignment event.' - end as reason - from + SELECT + a.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create policy assignment event.' + ELSE 'Activity log alert does not exist for create policy assignment event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY a.subscription_id, sub.subscription_id, sub.og_account_id, sub.og_resource_id, sub._ctx, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.1 Ensure that Activity Log Alert exists for Create Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_2_10.yaml b/compliance/controls/azure/azure_cis_v210_5_2_10.yaml old mode 100755 new mode 100644 index c50d6ace7..a010bff77 --- a/compliance/controls/azure/azure_cis_v210_5_2_10.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_2_10.yaml @@ -1,15 +1,60 @@ +Description: Create an activity log alert for the Delete Public IP Address rule. ID: azure_cis_v210_5_2_10 -Title: "5.2.10 Ensure that Activity Log Alert exists for Delete Public IP Address rule" -Description: "Create an activity log alert for the Delete Public IP Address rule." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as(\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and\n (\n ( alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/publicIPAddresses/delete\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/publicipaddresses\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Delete Public IP Address rule.'\n else 'Activity Log Alert does not exists for Delete Public IP Address rule.'\n end as reason \nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub._ctx,\n sub.subscription_id,\n sub.og_account_id,\n sub.og_resource_id,\n sub.display_name;" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/delete"}]') + OR + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Delete Public IP Address rule.' + ELSE 'Activity Log Alert does not exist for Delete Public IP Address rule.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.og_account_id, + sub.og_resource_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.10 Ensure that Activity Log Alert exists for Delete Public IP Address rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_2_2.yaml b/compliance/controls/azure/azure_cis_v210_5_2_2.yaml old mode 100755 new mode 100644 index 811149448..77f608897 --- a/compliance/controls/azure/azure_cis_v210_5_2_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_2_2.yaml @@ -1,54 +1,54 @@ +Description: Create an activity log alert for the Delete Policy Assignment event. ID: azure_cis_v210_5_2_2 -Title: "5.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment" -Description: "Create an activity log alert for the Delete Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/delete"}]' - limit 1 + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/delete"}]' + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete policy assignment event.' - else 'Activity log alert does not exists for delete policy assignment event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete policy assignment event.' + ELSE 'Activity log alert does not exist for delete policy assignment event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.og_account_id, sub.og_resource_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.2 Ensure that Activity Log Alert exists for Delete Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_2_3.yaml b/compliance/controls/azure/azure_cis_v210_5_2_3.yaml old mode 100755 new mode 100644 index 583a06f90..85d4b7847 --- a/compliance/controls/azure/azure_cis_v210_5_2_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_2_3.yaml @@ -1,64 +1,64 @@ +Description: Create an Activity Log Alert for the Create or Update Network Security Group event. ID: azure_cis_v210_5_2_3 -Title: "5.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group" -Description: "Create an Activity Log Alert for the Create or Update Network Security Group event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Network Security Group event.' - else 'Activity log alert does not exists for create or update Network Security Group event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Network Security Group event.' + ELSE 'Activity log alert does not exist for create or update Network Security Group event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.og_account_id, sub.og_resource_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.3 Ensure that Activity Log Alert exists for Create or Update Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_2_4.yaml b/compliance/controls/azure/azure_cis_v210_5_2_4.yaml old mode 100755 new mode 100644 index d162bfde8..64f4ec56d --- a/compliance/controls/azure/azure_cis_v210_5_2_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_2_4.yaml @@ -1,65 +1,65 @@ +Description: Create an activity log alert for the Delete Network Security Group event. ID: azure_cis_v210_5_2_4 -Title: "5.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group" -Description: "Create an activity log alert for the Delete Network Security Group event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id, jsonb_array_length(alert.condition -> 'allOf') - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Network Security Group event.' - else 'Activity log alert does not exists for delete Network Security Group event.' - end as reason - from - azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by - sub._ctx, - sub.subscription_id, - sub.og_account_id, - sub.og_resource_id, - sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Network Security Group event.' + ELSE 'Activity log alert does not exist for delete Network Security Group event.' + END AS reason + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.og_account_id, + sub.og_resource_id, + sub.display_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.4 Ensure that Activity Log Alert exists for Delete Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_2_5.yaml b/compliance/controls/azure/azure_cis_v210_5_2_5.yaml old mode 100755 new mode 100644 index 97cc0b200..a68d8c628 --- a/compliance/controls/azure/azure_cis_v210_5_2_5.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_2_5.yaml @@ -1,64 +1,63 @@ +Description: Create an activity log alert for the Create or Update Security Solution event. ID: azure_cis_v210_5_2_5 -Title: "5.2.5 Ensure that Activity Log Alert exists for Create or Update Security Solution" -Description: "Create an activity log alert for the Create or Update Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/write"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/write"}]' ) - or - ( + OR ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Security Solution event.' - else 'Activity log alert does not exists for create or update Security Solution event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Security Solution event.' + ELSE 'Activity log alert does not exist for create or update Security Solution event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.og_account_id, sub.og_resource_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.5 Ensure that Activity Log Alert exists for Create or Update Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_2_6.yaml b/compliance/controls/azure/azure_cis_v210_5_2_6.yaml old mode 100755 new mode 100644 index 802565593..968f315ff --- a/compliance/controls/azure/azure_cis_v210_5_2_6.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_2_6.yaml @@ -1,64 +1,64 @@ +Description: Create an activity log alert for the Delete Security Solution event. ID: azure_cis_v210_5_2_6 -Title: "5.2.6 Ensure that Activity Log Alert exists for Delete Security Solution" -Description: "Create an activity log alert for the Delete Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/delete"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/delete"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Security Solution event.' - else 'Activity log alert does not exists for delete Security Solution event.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN count(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN count(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Security Solution event.' + ELSE 'Activity log alert does not exist for delete Security Solution event.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.og_account_id, sub.og_resource_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.6 Ensure that Activity Log Alert exists for Delete Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_2_7.yaml b/compliance/controls/azure/azure_cis_v210_5_2_7.yaml old mode 100755 new mode 100644 index 520c03d6c..3058dba91 --- a/compliance/controls/azure/azure_cis_v210_5_2_7.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_2_7.yaml @@ -1,65 +1,60 @@ +Description: Create an activity log alert for the Create or Update SQL Server Firewall Rule event. ID: azure_cis_v210_5_2_7 -Title: "5.2.7 Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule" -Description: "Create an activity log alert for the Create or Update SQL Server Firewall Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as - ( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/write"}]' - ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - ) + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/write"}]') + OR + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Create or Update SQL Server Firewall Rule.' - else 'Activity Log Alert does not exists for Create or Update SQL Server Firewall Rule.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Create or Update SQL Server Firewall Rule.' + ELSE 'Activity Log Alert does not exist for Create or Update SQL Server Firewall Rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.og_account_id, sub.og_resource_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.7 Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_2_8.yaml b/compliance/controls/azure/azure_cis_v210_5_2_8.yaml old mode 100755 new mode 100644 index c9bdde8c2..7b5ec11f8 --- a/compliance/controls/azure/azure_cis_v210_5_2_8.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_2_8.yaml @@ -1,63 +1,62 @@ +Description: Create an activity log alert for the 'Delete SQL Server Firewall Rule.' ID: azure_cis_v210_5_2_8 -Title: "5.2.8 Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule" -Description: "Create an activity log alert for the 'Delete SQL Server Firewall Rule.'" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as( - select - alert.id as alert_id, - alert.name as alert_name, + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/delete"}]' ) - or - ( - alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 - ) + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field":"operationName","equals":"Microsoft.Sql/servers/firewallRules/delete"}]') + OR + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field":"resourceType","equals":"microsoft.sql/servers/firewallrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Delete SQL Server Firewall Rule.' - else 'Activity Log Alert does not exists for Delete SQL Server Firewall Rule.' - end as reason - from + + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Delete SQL Server Firewall Rule.' + ELSE 'Activity Log Alert does not exist for Delete SQL Server Firewall Rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN + alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.og_account_id, sub.og_resource_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.8 Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_2_9.yaml b/compliance/controls/azure/azure_cis_v210_5_2_9.yaml old mode 100755 new mode 100644 index 1151468c3..10ba04958 --- a/compliance/controls/azure/azure_cis_v210_5_2_9.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_2_9.yaml @@ -1,65 +1,65 @@ +Description: Create an activity log alert for the Create or Update Public IP Addresses rule. ID: azure_cis_v210_5_2_9 -Title: "5.2.9 Ensure that Activity Log Alert exists for Create or Update Public IP Address rule" -Description: "Create an activity log alert for the Create or Update Public IP Addresses rule." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with alert_rule as + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH alert_rule AS ( - select - alert.id as alert_id, - alert.name as alert_name, + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location = 'global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/write"}]' + (alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/write"}]' ) - or + OR ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Create or Update Public IP Address rule.' - else 'Activity Log Alert does not exists for Create or Update Public IP Address rule.' - end as reason - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Create or Update Public IP Address rule.' + ELSE 'Activity Log Alert does not exist for Create or Update Public IP Address rule.' + END AS reason + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub._ctx, sub.subscription_id, sub.og_account_id, sub.og_resource_id, sub.display_name; - PrimaryTable: azure_subscription - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.2.9 Ensure that Activity Log Alert exists for Create or Update Public IP Address rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_3_1.yaml b/compliance/controls/azure/azure_cis_v210_5_3_1.yaml old mode 100755 new mode 100644 index 9ada7419a..c0abeda13 --- a/compliance/controls/azure/azure_cis_v210_5_3_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_3_1.yaml @@ -1,39 +1,40 @@ +Description: Application Insights within Azure act as an Application Performance Monitoring solution providing valuable data into how well an application performs and additional information when performing incident response. The types of log data collected include application metrics, telemetry data, and application trace logging data providing organizations with detailed information about application activity and application transactions. ID: azure_cis_v210_5_3_1 -Title: "5.3.1 Ensure Application Insights are Configured" -Description: "Application Insights within Azure act as an Application Performance Monitoring solution providing valuable data into how well an application performs and additional information when performing incident response. The types of log data collected include application metrics, telemetry data, and application trace logging data providing organizations with detailed information about application activity and application transactions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with application_insights as ( - select - subscription_id, - count(*) as no_application_insight - from - azure_application_insight - group by - subscription_id - ) - select - sub.id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when i.subscription_id is null then 'alarm' - else 'ok' - end as status, - case - when i.subscription_id is null then sub.display_name || ' does not have application insights configured.' - else sub.display_name || ' has ' || no_application_insight || ' application insights configured.' - end as reason - from - azure_subscription as sub - left join application_insights as i on i.subscription_id = sub.subscription_id; - PrimaryTable: azure_application_insight ListOfTables: - azure_application_insight - azure_subscription Parameters: [] + PrimaryTable: azure_application_insight + QueryToExecute: | + WITH application_insights AS ( + SELECT + subscription_id, + COUNT(*) AS no_application_insight + FROM + azure_application_insight + GROUP BY + subscription_id + ) + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN i.subscription_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.subscription_id IS NULL THEN sub.display_name || ' does not have application insights configured.' + ELSE sub.display_name || ' has ' || no_application_insight || ' application insights configured.' + END AS reason + FROM + azure_subscription AS sub + LEFT JOIN application_insights AS i + ON i.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.3.1 Ensure Application Insights are Configured \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_5_4.yaml b/compliance/controls/azure/azure_cis_v210_5_4.yaml old mode 100755 new mode 100644 index 8fe20f1c5..b43608882 --- a/compliance/controls/azure/azure_cis_v210_5_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_5_4.yaml @@ -1,24 +1,24 @@ +Description: Resource Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself; for example, reading or updating a secret from a Key Vault. ID: azure_cis_v210_5_4 -Title: "5.4 Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it" -Description: "Resource Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself; for example, reading or updating a secret from a Key Vault." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 5.4 Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_6_1.yaml b/compliance/controls/azure/azure_cis_v210_6_1.yaml old mode 100755 new mode 100644 index 10e9fc962..1f7b3417b --- a/compliance/controls/azure/azure_cis_v210_6_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_6_1.yaml @@ -1,54 +1,54 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required. ID: azure_cis_v210_6_1 -Title: "6.1 Ensure that RDP access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) AS dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('3389', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 3389 - and split_part(dport, '-', 2) :: integer >= 3389 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('3389', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::INTEGER <= 3389 + AND split_part(dport, '-', 2)::INTEGER >= 3389 ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts RDP access from internet.' - else sg.title || ' allows RDP access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts RDP access from internet.' + ELSE sg.title || ' allows RDP access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.1 Ensure that RDP access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_6_2.yaml b/compliance/controls/azure/azure_cis_v210_6_2.yaml old mode 100755 new mode 100644 index c2264704d..e95996d6c --- a/compliance/controls/azure/azure_cis_v210_6_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_6_2.yaml @@ -1,54 +1,54 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required. ID: azure_cis_v210_6_2 -Title: "6.2 Ensure that SSH access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) AS dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('22', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 22 - and split_part(dport, '-', 2) :: integer >= 22 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('22', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::integer <= 22 + AND split_part(dport, '-', 2)::integer >= 22 ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts SSH access from internet.' - else sg.title || ' allows SSH access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts SSH access from internet.' + ELSE sg.title || ' allows SSH access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.2 Ensure that SSH access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_6_3.yaml b/compliance/controls/azure/azure_cis_v210_6_3.yaml old mode 100755 new mode 100644 index 427403ef0..740a6966e --- a/compliance/controls/azure/azure_cis_v210_6_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_6_3.yaml @@ -1,59 +1,59 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required. ID: azure_cis_v210_6_3 -Title: "6.3 Ensure that UDP access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and sg -> 'properties' ->> 'protocol' = 'UDP' - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' = 'UDP' + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( dport = '*' - or ( - dport like '%-%' - and ( - 53 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 123 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 161 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 389 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 1900 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer + OR ( + dport LIKE '%-%' + AND ( + 53 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 123 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 161 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 389 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER + OR 1900 BETWEEN split_part(dport, '-', 1) :: INTEGER AND split_part(dport, '-', 2) :: INTEGER ) ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts UDP services from internet.' - else sg.title || ' allows UDP services from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts UDP services from internet.' + ELSE sg.title || ' allows UDP services from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.3 Ensure that UDP access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_6_4.yaml b/compliance/controls/azure/azure_cis_v210_6_4.yaml old mode 100755 new mode 100644 index 7c70614e7..bd51c45d1 --- a/compliance/controls/azure/azure_cis_v210_6_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_6_4.yaml @@ -1,23 +1,28 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured. ID: azure_cis_v210_6_4 -Title: "6.4 Ensure that HTTP(S) access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with network_sg as ( - select distinct + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT DISTINCT name sg_name - from + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, - jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip - where + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and sg -> 'properties' ->> 'protocol' ilike 'TCP' - and sip in - ( + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' ILIKE 'TCP' + AND sip IN ( '*', '0.0.0.0', '0.0.0.0/0', @@ -26,43 +31,34 @@ Query: '/0', '/0' ) - and - ( - dport in - ( + AND ( + dport IN ( '80', '*' ) - or - ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 80 - and split_part(dport, '-', 2) :: integer >= 80 + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::integer <= 80 + AND split_part(dport, '-', 2)::integer >= 80 ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts HTTPS access from internet.' - else sg.title || ' allows HTTPS access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts HTTPS access from internet.' + ELSE sg.title || ' allows HTTPS access from internet.' + END AS reason + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.4 Ensure that HTTP(S) access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_6_6.yaml b/compliance/controls/azure/azure_cis_v210_6_6.yaml old mode 100755 new mode 100644 index 24a9704af..27d2ee3d0 --- a/compliance/controls/azure/azure_cis_v210_6_6.yaml +++ b/compliance/controls/azure/azure_cis_v210_6_6.yaml @@ -1,33 +1,35 @@ +Description: Enable Network Watcher for Azure subscriptions. ID: azure_cis_v210_6_6 -Title: "6.6 Ensure that Network Watcher is 'Enabled'" -Description: "Enable Network Watcher for Azure subscriptions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - loc.id resource, - loc.og_account_id as og_account_id, - loc.og_resource_id as og_resource_id, - case - when watcher.id is null then 'alarm' - else 'ok' - end as status, - case - when watcher.id is null then 'Network watcher not enabled in ' || loc.name || '.' - else 'Network watcher enabled in ' || loc.name || '.' - end as reason, - loc.name - from - azure_location loc - left join azure_network_watcher watcher on watcher.region = loc.name - join azure_subscription sub on sub.subscription_id = loc.subscription_id; - PrimaryTable: azure_network_watcher ListOfTables: - azure_location - azure_network_watcher - azure_subscription Parameters: [] + PrimaryTable: azure_network_watcher + QueryToExecute: | + SELECT + loc.id AS resource, + loc.og_account_id AS og_account_id, + loc.og_resource_id AS og_resource_id, + CASE + WHEN watcher.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN watcher.id IS NULL THEN 'Network watcher not enabled in ' || loc.name || '.' + ELSE 'Network watcher enabled in ' || loc.name || '.' + END AS reason, + loc.name + FROM + azure_location loc + LEFT JOIN + azure_network_watcher watcher ON watcher.region = loc.name + JOIN + azure_subscription sub ON sub.subscription_id = loc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.6 Ensure that Network Watcher is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_6_7.yaml b/compliance/controls/azure/azure_cis_v210_6_7.yaml old mode 100755 new mode 100644 index 13c298ead..467bb91a0 --- a/compliance/controls/azure/azure_cis_v210_6_7.yaml +++ b/compliance/controls/azure/azure_cis_v210_6_7.yaml @@ -1,24 +1,24 @@ +Description: Public IP Addresses provide tenant accounts with Internet connectivity for resources contained within the tenant. During the creation of certain resources in Azure, a Public IP Address may be created. All Public IP Addresses within the tenant should be periodically reviewed for accuracy and necessity. ID: azure_cis_v210_6_7 -Title: "6.7 Ensure that Public IP addresses are Evaluated on a Periodic Basis" -Description: "Public IP Addresses provide tenant accounts with Internet connectivity for resources contained within the tenant. During the creation of certain resources in Azure, a Public IP Address may be created. All Public IP Addresses within the tenant should be periodically reviewed for accuracy and necessity." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 6.7 Ensure that Public IP addresses are Evaluated on a Periodic Basis \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_7_1.yaml b/compliance/controls/azure/azure_cis_v210_7_1.yaml old mode 100755 new mode 100644 index 56c493d4f..b27f7e457 --- a/compliance/controls/azure/azure_cis_v210_7_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_7_1.yaml @@ -1,45 +1,46 @@ +Description: The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service. ID: azure_cis_v210_7_1 -Title: "7.1 Ensure an Azure Bastion Host Exists" -Description: "The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with bastion_hosts as ( - select + ListOfTables: + - azure_bastion_host + - azure_subscription + Parameters: [] + PrimaryTable: azure_bastion_host + QueryToExecute: | + WITH bastion_hosts AS ( + SELECT subscription_id, _ctx, region, resource_group, - count(*) as no_bastion_host - from + COUNT(*) AS no_bastion_host + FROM azure_bastion_host - group by + GROUP BY subscription_id, _ctx, resource_group, region ) - select - sub.id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when i.subscription_id is null then 'alarm' - else 'ok' - end as status, - case - when i.subscription_id is null then sub.display_name || ' does not have bastion host.' - else sub.display_name || ' has ' || no_bastion_host || ' bastion host(s).' - end as reason - from - azure_subscription as sub - left join bastion_hosts as i on i.subscription_id = sub.subscription_id; - PrimaryTable: azure_bastion_host - ListOfTables: - - azure_bastion_host - - azure_subscription - Parameters: [] + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN i.subscription_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.subscription_id IS NULL THEN sub.display_name || ' does not have bastion host.' + ELSE sub.display_name || ' has ' || no_bastion_host || ' bastion host(s).' + END AS reason + FROM + azure_subscription AS sub + LEFT JOIN bastion_hosts AS i + ON i.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.1 Ensure an Azure Bastion Host Exists \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_7_2.yaml b/compliance/controls/azure/azure_cis_v210_7_2.yaml old mode 100755 new mode 100644 index 4630b34a1..d6fac94ff --- a/compliance/controls/azure/azure_cis_v210_7_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_7_2.yaml @@ -1,32 +1,32 @@ +Description: Migrate blob-based VHDs to Managed Disks on Virtual Machines to exploit the default features of this configuration. ID: azure_cis_v210_7_2 -Title: "7.2 Ensure Virtual Machines are utilizing Managed Disks" -Description: "Migrate blob-based VHDs to Managed Disks on Virtual Machines to exploit the default features of this configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - vm.id as resource, - vm.og_account_id as og_account_id, - vm.og_resource_id as og_resource_id, - case - when managed_disk_id is null then 'alarm' - else 'ok' - end as status, - case - when managed_disk_id is null then vm.name || ' VM not utilizing managed disks.' - else vm.name || ' VM utilizing managed disks.' - end as reason - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where - sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN managed_disk_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN managed_disk_id IS NULL THEN vm.name || ' VM not utilizing managed disks.' + ELSE vm.name || ' VM utilizing managed disks.' + END AS reason + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.2 Ensure Virtual Machines are utilizing Managed Disks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_7_3.yaml b/compliance/controls/azure/azure_cis_v210_7_3.yaml old mode 100755 new mode 100644 index 5c5d1f39c..cb70a6fd3 --- a/compliance/controls/azure/azure_cis_v210_7_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_7_3.yaml @@ -1,33 +1,33 @@ +Description: Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE or Server Side Encryption(SSE). ID: azure_cis_v210_7_3 -Title: "7.3 Ensure that 'OS and Data' disks are encrypted with Customer Managed Key (CMK)" -Description: "Ensure that OS disks (boot volumes) and data disks (non-boot volumes) are encrypted with CMK (Customer Managed Keys). Customer Managed keys can be either ADE or Server Side Encryption(SSE)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.' - else disk.name || ' not encrypted with CMK.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state = 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state = 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.3 Ensure that 'OS and Data' disks are encrypted with Customer Managed Key (CMK) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_7_4.yaml b/compliance/controls/azure/azure_cis_v210_7_4.yaml old mode 100755 new mode 100644 index bc235da05..7a87ae845 --- a/compliance/controls/azure/azure_cis_v210_7_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_7_4.yaml @@ -1,33 +1,33 @@ +Description: Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK). ID: azure_cis_v210_7_4 -Title: "7.4 Ensure that 'Unattached disks' are encrypted with 'Customer Managed Key' (CMK)" -Description: "Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.' - else disk.name || ' not encrypted with CMK.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state != 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state != 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 7.4 Ensure that 'Unattached disks' are encrypted with 'Customer Managed Key' (CMK) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_7_5.yaml b/compliance/controls/azure/azure_cis_v210_7_5.yaml old mode 100755 new mode 100644 index 7370cb7e7..44adb00fd --- a/compliance/controls/azure/azure_cis_v210_7_5.yaml +++ b/compliance/controls/azure/azure_cis_v210_7_5.yaml @@ -1,24 +1,24 @@ +Description: For added security, only install organization-approved extensions on VMs. ID: azure_cis_v210_7_5 -Title: "7.5 Ensure that Only Approved Extensions Are Installed" -Description: "For added security, only install organization-approved extensions on VMs." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.5 Ensure that Only Approved Extensions Are Installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_7_6.yaml b/compliance/controls/azure/azure_cis_v210_7_6.yaml old mode 100755 new mode 100644 index cdc6ddb52..c60170e7b --- a/compliance/controls/azure/azure_cis_v210_7_6.yaml +++ b/compliance/controls/azure/azure_cis_v210_7_6.yaml @@ -1,24 +1,24 @@ +Description: Install endpoint protection for all virtual machines. ID: azure_cis_v210_7_6 -Title: "7.6 Ensure that Endpoint Protection for all Virtual Machines is installed" -Description: "Install endpoint protection for all virtual machines." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.6 Ensure that Endpoint Protection for all Virtual Machines is installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_7_7.yaml b/compliance/controls/azure/azure_cis_v210_7_7.yaml old mode 100755 new mode 100644 index 46ebd4f1c..a0700f2f6 --- a/compliance/controls/azure/azure_cis_v210_7_7.yaml +++ b/compliance/controls/azure/azure_cis_v210_7_7.yaml @@ -1,24 +1,24 @@ +Description: VHD (Virtual Hard Disks) are stored in blob storage and are the old-style disks that were attached to Virtual Machines. The blob VHD was then leased to the VM. By default, storage accounts are not encrypted, and Microsoft Defender will then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK. This should be turned on for storage accounts containing VHDs. ID: azure_cis_v210_7_7 -Title: "7.7 [Legacy] Ensure that VHDs are Encrypted" -Description: "VHD (Virtual Hard Disks) are stored in blob storage and are the old-style disks that were attached to Virtual Machines. The blob VHD was then leased to the VM. By default, storage accounts are not encrypted, and Microsoft Defender will then recommend that the OS disks should be encrypted. Storage accounts can be encrypted as a whole using PMK or CMK. This should be turned on for storage accounts containing VHDs." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.7 [Legacy] Ensure that VHDs are Encrypted \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_7_8.yaml b/compliance/controls/azure/azure_cis_v210_7_8.yaml old mode 100755 new mode 100644 index 1cbacb8e4..ca0aab1c5 --- a/compliance/controls/azure/azure_cis_v210_7_8.yaml +++ b/compliance/controls/azure/azure_cis_v210_7_8.yaml @@ -1,24 +1,24 @@ +Description: Verify identities without MFA that can log in to a privileged virtual machine using separate login credentials. An adversary can leverage the access to move laterally and perform actions with the virtual machine's managed identity. Make sure the virtual machine only has necessary permissions, and revoke the admin-level permissions according to the least privileges principal. ID: azure_cis_v210_7_8 -Title: "7.8 Ensure only MFA enabled identities can access privileged Virtual Machine" -Description: "Verify identities without MFA that can log in to a privileged virtual machine using separate login credentials. An adversary can leverage the access to move laterally and perform actions with the virtual machine's managed identity. Make sure the virtual machine only has necessary permissions, and revoke the admin-level permissions according to the least privileges principal." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.8 Ensure only MFA enabled identities can access privileged Virtual Machine \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_7_9.yaml b/compliance/controls/azure/azure_cis_v210_7_9.yaml old mode 100755 new mode 100644 index b73f85201..f342df438 --- a/compliance/controls/azure/azure_cis_v210_7_9.yaml +++ b/compliance/controls/azure/azure_cis_v210_7_9.yaml @@ -1,24 +1,24 @@ +Description: When Secure Boot and vTPM are enabled together, they provide a strong foundation for protecting your VM from boot attacks. For example, if an attacker attempts to replace the bootloader with a malicious version, Secure Boot will prevent the VM from booting. ID: azure_cis_v210_7_9 -Title: "7.9 Ensure Trusted Launch is enabled on Virtual Machines" -Description: "When Secure Boot and vTPM are enabled together, they provide a strong foundation for protecting your VM from boot attacks. For example, if an attacker attempts to replace the bootloader with a malicious version, Secure Boot will prevent the VM from booting." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 7.9 Ensure Trusted Launch is enabled on Virtual Machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_8_1.yaml b/compliance/controls/azure/azure_cis_v210_8_1.yaml old mode 100755 new mode 100644 index 0fc7d5fc2..942759328 --- a/compliance/controls/azure/azure_cis_v210_8_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_8_1.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set. ID: azure_cis_v210_8_1 -Title: "8.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults" -Description: "Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_key + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + WITH rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where enable_rbac_authorization + WHERE + enable_rbac_authorization ) - select - kvk.id as resource, - kvk.og_account_id as og_account_id, - kvk.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvk.name || - case - when v.name is null then ' not RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' not RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_key kvk - left join rbac_vault as v on v.name = kvk.vault_name, + LEFT JOIN rbac_vault AS v ON v.name = kvk.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvk.subscription_id; - PrimaryTable: azure_key_vault_key - ListOfTables: - - azure_key_vault - - azure_key_vault_key - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_8_2.yaml b/compliance/controls/azure/azure_cis_v210_8_2.yaml old mode 100755 new mode 100644 index 1c73257ef..02721c6d6 --- a/compliance/controls/azure/azure_cis_v210_8_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_8_2.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set. ID: azure_cis_v210_8_2 -Title: "8.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults" -Description: "Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with non_rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_key + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + WITH non_rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where not enable_rbac_authorization + WHERE + NOT enable_rbac_authorization ) - select - kvk.id as resource, - kvk.og_account_id as og_account_id, - kvk.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvk.name || - case - when v.name is null then ' RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_key kvk - left join non_rbac_vault as v on v.name = kvk.vault_name, + LEFT JOIN non_rbac_vault AS v ON v.name = kvk.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvk.subscription_id; - PrimaryTable: azure_key_vault_key - ListOfTables: - - azure_key_vault - - azure_key_vault_key - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.2 Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_8_3.yaml b/compliance/controls/azure/azure_cis_v210_8_3.yaml old mode 100755 new mode 100644 index de1b574e9..9591c9c7b --- a/compliance/controls/azure/azure_cis_v210_8_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_8_3.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set. ID: azure_cis_v210_8_3 -Title: "8.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults" -Description: "Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_secret + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + WITH rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where enable_rbac_authorization + WHERE + enable_rbac_authorization ) - select - kvs.id as resource, - kvs.og_account_id as og_account_id, - kvs.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvs.name || - case - when v.name is null then ' not RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' not RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_secret kvs - left join rbac_vault as v on v.name = kvs.vault_name, + LEFT JOIN rbac_vault AS v ON v.name = kvs.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvs.subscription_id; - PrimaryTable: azure_key_vault_secret - ListOfTables: - - azure_key_vault - - azure_key_vault_secret - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.3 Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_8_4.yaml b/compliance/controls/azure/azure_cis_v210_8_4.yaml old mode 100755 new mode 100644 index ff58caa24..789c09bea --- a/compliance/controls/azure/azure_cis_v210_8_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_8_4.yaml @@ -1,45 +1,46 @@ +Description: Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set. ID: azure_cis_v210_8_4 -Title: "8.4 Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults" -Description: "Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with non_rbac_vault as ( - select + ListOfTables: + - azure_key_vault + - azure_key_vault_secret + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + WITH non_rbac_vault AS ( + SELECT name - from + FROM azure_key_vault - where not enable_rbac_authorization + WHERE + NOT enable_rbac_authorization ) - select - kvs.id as resource, - kvs.og_account_id as og_account_id, - kvs.og_resource_id as og_resource_id, - case - when v.name is null then 'skip' - when enabled and expires_at is null then 'alarm' - else 'ok' - end as status, + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, vault_name || ' key ' || kvs.name || - case - when v.name is null then ' RBAC enabled vault.' - when enabled and expires_at is null then ' expiration date not set.' - when not enabled then ' disabled.' - else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.' - end as reason - from + CASE + WHEN v.name IS NULL THEN ' RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason + FROM azure_key_vault_secret kvs - left join non_rbac_vault as v on v.name = kvs.vault_name, + LEFT JOIN non_rbac_vault AS v ON v.name = kvs.vault_name, azure_subscription sub - where + WHERE sub.subscription_id = kvs.subscription_id; - PrimaryTable: azure_key_vault_secret - ListOfTables: - - azure_key_vault - - azure_key_vault_secret - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.4 Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_8_5.yaml b/compliance/controls/azure/azure_cis_v210_8_5.yaml old mode 100755 new mode 100644 index f073147fc..ae5b2d907 --- a/compliance/controls/azure/azure_cis_v210_8_5.yaml +++ b/compliance/controls/azure/azure_cis_v210_8_5.yaml @@ -1,34 +1,34 @@ +Description: The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the "Do Not Purge" and "Soft Delete" functions. ID: azure_cis_v210_8_5 -Title: "8.5 Ensure the Key Vault is Recoverable" -Description: "The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the \\\"Do Not Purge\\\" and \\\"Soft Delete\\\" functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when soft_delete_enabled and purge_protection_enabled then 'ok' - else 'alarm' - end as status, - case - when not soft_delete_enabled and not purge_protection_enabled then name || ' "soft delete" and "do not purge" not enabled.' - when not soft_delete_enabled then name || ' "soft delete" not enabled.' - when not purge_protection_enabled then name || ' "do not purge" not enabled.' - else name || ' "soft delete" and "do not purge" enabled.' - end as reason - from - azure_key_vault kv, - azure_subscription sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN soft_delete_enabled AND purge_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT soft_delete_enabled AND NOT purge_protection_enabled THEN name || ' "soft delete" and "do not purge" not enabled.' + WHEN NOT soft_delete_enabled THEN name || ' "soft delete" not enabled.' + WHEN NOT purge_protection_enabled THEN name || ' "do not purge" not enabled.' + ELSE name || ' "soft delete" and "do not purge" enabled.' + END AS reason + FROM + azure_key_vault kv, + azure_subscription sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.5 Ensure the Key Vault is Recoverable \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_8_6.yaml b/compliance/controls/azure/azure_cis_v210_8_6.yaml old mode 100755 new mode 100644 index 2056e2db0..e728e20ef --- a/compliance/controls/azure/azure_cis_v210_8_6.yaml +++ b/compliance/controls/azure/azure_cis_v210_8_6.yaml @@ -1,32 +1,32 @@ +Description: Role assignments disappear when a Key Vault has been deleted (soft-delete) and recovered. Afterwards it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services. ID: azure_cis_v210_8_6 -Title: "8.6 Enable Role Based Access Control for Azure Key Vault" -Description: "Role assignments disappear when a Key Vault has been deleted (soft-delete) and recovered. Afterwards it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when enable_rbac_authorization then 'ok' - else 'alarm' - end as status, - case - when enable_rbac_authorization then name || ' has RBAC enabled.' - else name || ' have RBAC disabled.' - end as reason - from - azure_key_vault as kv, - azure_subscription as sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN enable_rbac_authorization THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_rbac_authorization THEN name || ' has RBAC enabled.' + ELSE name || ' have RBAC disabled.' + END AS reason + FROM + azure_key_vault AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.6 Enable Role Based Access Control for Azure Key Vault \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_8_8.yaml b/compliance/controls/azure/azure_cis_v210_8_8.yaml old mode 100755 new mode 100644 index 46f3d7b53..1c9100a87 --- a/compliance/controls/azure/azure_cis_v210_8_8.yaml +++ b/compliance/controls/azure/azure_cis_v210_8_8.yaml @@ -1,24 +1,24 @@ +Description: Automatic Key Rotation is available in Public Preview. The currently supported applications are Key Vault, Managed Disks, and Storage accounts accessing keys within Key Vault. The number of supported applications will incrementally increased. ID: azure_cis_v210_8_8 -Title: "8.8 Ensure Automatic Key Rotation is Enabled Within Azure Key Vault for the Supported Services" -Description: "Automatic Key Rotation is available in Public Preview. The currently supported applications are Key Vault, Managed Disks, and Storage accounts accessing keys within Key Vault. The number of supported applications will incrementally increased." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 8.8 Ensure Automatic Key Rotation is Enabled Within Azure Key Vault for the Supported Services \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_9_1.yaml b/compliance/controls/azure/azure_cis_v210_9_1.yaml old mode 100755 new mode 100644 index a69d9f4c3..1e8aa5b33 --- a/compliance/controls/azure/azure_cis_v210_9_1.yaml +++ b/compliance/controls/azure/azure_cis_v210_9_1.yaml @@ -1,32 +1,38 @@ +Description: Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented. + ID: azure_cis_v210_9_1 -Title: "9.1 Ensure App Service Authentication is set up for apps in Azure App Service" -Description: "Azure App Service Authentication is a feature that can prevent anonymous HTTP requests from reaching a Web Application or authenticate those with tokens before they reach the app. If an anonymous request is received from a browser, App Service will redirect to a logon page. To handle the logon process, a choice from a set of identity providers can be made, or a custom authentication mechanism can be implemented." + +IntegrationType: + - azure_subscription + Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (auth_settings -> 'properties' ->> 'enabled') :: boolean then name || ' authentication not set.' - else name || ' authentication set.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::boolean THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (auth_settings -> 'properties' ->> 'enabled')::boolean THEN name || ' authentication not set.' + ELSE name || ' authentication set.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; + Severity: low + Tags: {} -IntegrationType: - - azure_subscription + +Title: 9.1 Ensure App Service Authentication is set up for apps in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_9_10.yaml b/compliance/controls/azure/azure_cis_v210_9_10.yaml old mode 100755 new mode 100644 index 815104abc..777dcfa85 --- a/compliance/controls/azure/azure_cis_v210_9_10.yaml +++ b/compliance/controls/azure/azure_cis_v210_9_10.yaml @@ -1,24 +1,24 @@ +Description: Azure Key Vault will store multiple types of sensitive information such as encryption keys, certificate thumbprints, and Managed Identity Credentials. Access to these 'Secrets' can be controlled through granular permissions. ID: azure_cis_v210_9_10 -Title: "9.10 Ensure Azure Key Vaults are Used to Store Secrets" -Description: "Azure Key Vault will store multiple types of sensitive information such as encryption keys, certificate thumbprints, and Managed Identity Credentials. Access to these 'Secrets' can be controlled through granular permissions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: 9.10 Ensure Azure Key Vaults are Used to Store Secrets \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_9_2.yaml b/compliance/controls/azure/azure_cis_v210_9_2.yaml old mode 100755 new mode 100644 index 7c385e1d6..cf04daff4 --- a/compliance/controls/azure/azure_cis_v210_9_2.yaml +++ b/compliance/controls/azure/azure_cis_v210_9_2.yaml @@ -1,32 +1,32 @@ +Description: Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic. ID: azure_cis_v210_9_2 -Title: "9.2 Ensure Web App Redirects All HTTP traffic to HTTPS in Azure App Service" -Description: "Azure Web Apps allows sites to run under both HTTP and HTTPS by default. Web apps can be accessed by anyone using non-secure HTTP links by default. Non-secure HTTP requests can be restricted and all HTTP requests redirected to the secure HTTPS port. It is recommended to enforce HTTPS-only traffic." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not https_only then 'alarm' - else 'ok' - end as status, - case - when not https_only then name || ' does not redirect all HTTP traffic to HTTPS.' - else name || ' redirects all HTTP traffic to HTTPS.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT https_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT https_only THEN name || ' does not redirect all HTTP traffic to HTTPS.' + ELSE name || ' redirects all HTTP traffic to HTTPS.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.2 Ensure Web App Redirects All HTTP traffic to HTTPS in Azure App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_9_3.yaml b/compliance/controls/azure/azure_cis_v210_9_3.yaml old mode 100755 new mode 100644 index eac8b832f..a56e28010 --- a/compliance/controls/azure/azure_cis_v210_9_3.yaml +++ b/compliance/controls/azure/azure_cis_v210_9_3.yaml @@ -1,32 +1,32 @@ +Description: The TLS (Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards such as PCI DSS. ID: azure_cis_v210_9_3 -Title: "9.3 Ensure Web App is using the latest version of TLS encryption" -Description: "The TLS (Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards such as PCI DSS." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then 'alarm' - else 'ok' - end as status, - case - when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then name || ' not using the latest version of TLS encryption.' - else name || ' using the latest version of TLS encryption.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN name || ' not using the latest version of TLS encryption.' + ELSE name || ' using the latest version of TLS encryption.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.3 Ensure Web App is using the latest version of TLS encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_9_4.yaml b/compliance/controls/azure/azure_cis_v210_9_4.yaml old mode 100755 new mode 100644 index 29284790b..c2ba76b40 --- a/compliance/controls/azure/azure_cis_v210_9_4.yaml +++ b/compliance/controls/azure/azure_cis_v210_9_4.yaml @@ -1,32 +1,32 @@ +Description: Managed service identity in App Service provides more security by eliminating secrets from the app, such as credentials in the connection strings. When registering an App Service with Entra ID, the app will connect to other Azure services securely without the need for usernames and passwords. ID: azure_cis_v210_9_4 -Title: "9.4 Ensure that Register with Entra ID is enabled on App Service" -Description: "Managed service identity in App Service provides more security by eliminating secrets from the app, such as credentials in the connection strings. When registering an App Service with Entra ID, the app will connect to other Azure services securely without the need for usernames and passwords." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when identity = '{}' then 'alarm' - else 'ok' - end as status, - case - when identity = '{}' then name || ' register with azure active directory disabled.' - else name || ' register with azure active directory enabled.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN identity = '{}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity = '{}' THEN name || ' register with azure active directory disabled.' + ELSE name || ' register with azure active directory enabled.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.4 Ensure that Register with Entra ID is enabled on App Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_9_5.yaml b/compliance/controls/azure/azure_cis_v210_9_5.yaml old mode 100755 new mode 100644 index 2fb9ac600..415c42dea --- a/compliance/controls/azure/azure_cis_v210_9_5.yaml +++ b/compliance/controls/azure/azure_cis_v210_9_5.yaml @@ -1,59 +1,59 @@ +Description: Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version. ID: azure_cis_v210_9_5 -Title: "9.5 Ensure That 'PHP version' is the Latest, If Used to Run the Web App" -Description: "Periodically newer versions are released for PHP software either due to security flaws or to include additional functionality. Using the latest PHP version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with all_web_app as ( - select + ListOfTables: + - azure_app_service_web_app + - azure_subscription + Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_web_app AS ( + SELECT id - from + FROM azure_app_service_web_app - where - exists ( - select - from - unnest(regexp_split_to_array(kind, ',')) elem - where - elem like 'app%' + WHERE + EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE + elem LIKE 'app%' ) - and - exists ( - select - from - unnest(regexp_split_to_array(kind, ',')) elem - where + AND EXISTS ( + SELECT + FROM + UNNEST(regexp_split_to_array(kind, ',')) elem + WHERE elem = 'linux' ) ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.id is null then 'skip' - when configuration -> 'properties' ->> 'linuxFxVersion' not like 'PHP%' then 'ok' - when configuration -> 'properties' ->> 'linuxFxVersion' = 'PHP|8.0' then 'ok' - else 'alarm' - end as status, - case - when b.id is null then a.title || ' is ' || a.kind || ' kind.' - when configuration -> 'properties' ->> 'linuxFxVersion' not like 'PHP%' then a.name || ' not using php version.' - when configuration -> 'properties' ->> 'linuxFxVersion' = 'PHP|8.0' then a.name || ' using the latest php version.' - else a.name || ' not using latest php version.' - end as reason - from - azure_app_service_web_app as a - left join all_web_app as b on a.id = b.id, - azure_subscription as sub - where + + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'PHP%' THEN 'ok' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' = 'PHP|8.0' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'PHP%' THEN a.name || ' not using php version.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' = 'PHP|8.0' THEN a.name || ' using the latest php version.' + ELSE a.name || ' not using latest php version.' + END AS reason + FROM + azure_app_service_web_app AS a + LEFT JOIN all_web_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE sub.subscription_id = a.subscription_id; - PrimaryTable: azure_app_service_web_app - ListOfTables: - - azure_app_service_web_app - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.5 Ensure That 'PHP version' is the Latest, If Used to Run the Web App \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_9_6.yaml b/compliance/controls/azure/azure_cis_v210_9_6.yaml old mode 100755 new mode 100644 index d14460da7..9d2ec23b2 --- a/compliance/controls/azure/azure_cis_v210_9_6.yaml +++ b/compliance/controls/azure/azure_cis_v210_9_6.yaml @@ -1,59 +1,58 @@ +Description: Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest full Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version. ID: azure_cis_v210_9_6 -Title: "9.6 Ensure that 'Python version' is the Latest Stable Version, if Used to Run the Web App" -Description: "Periodically, newer versions are released for Python software either due to security flaws or to include additional functionality. Using the latest full Python version for web apps is recommended in order to take advantage of security fixes, if any, and/or additional functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with all_web_app as ( - select + ListOfTables: + - azure_app_service_web_app + - azure_subscription + Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_web_app AS ( + SELECT id - from + FROM azure_app_service_web_app - where - exists ( - select - from - unnest(regexp_split_to_array(kind, ',')) elem - where - elem like 'app%' + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE 'app%' ) - and - exists ( - select - from - unnest(regexp_split_to_array(kind, ',')) elem - where + AND EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE elem = 'linux' ) ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.id is null then 'skip' - when configuration -> 'properties' ->> 'linuxFxVersion' not like 'PYTHON%' then 'ok' - when configuration -> 'properties' ->> 'linuxFxVersion' = 'PYTHON|3.9' then 'ok' - else 'alarm' - end as status, - case - when b.id is null then a.title || ' is not of linux kind.' - when configuration -> 'properties' ->> 'linuxFxVersion' not like 'PYTHON%' then a.name || ' not using python version.' - when configuration -> 'properties' ->> 'linuxFxVersion' = 'PYTHON|3.9' then a.name || ' using the latest python version.' - else a.name || ' not using latest python version.' - end as reason - from - azure_app_service_web_app as a - left join all_web_app as b on a.id = b.id, - azure_subscription as sub - where + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'PYTHON%' THEN 'ok' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' = 'PYTHON|3.9' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is not of linux kind.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'PYTHON%' THEN a.name || ' not using python version.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' = 'PYTHON|3.9' THEN a.name || ' using the latest python version.' + ELSE a.name || ' not using latest python version.' + END AS reason + FROM + azure_app_service_web_app AS a + LEFT JOIN all_web_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE sub.subscription_id = a.subscription_id; - PrimaryTable: azure_app_service_web_app - ListOfTables: - - azure_app_service_web_app - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.6 Ensure that 'Python version' is the Latest Stable Version, if Used to Run the Web App \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_9_7.yaml b/compliance/controls/azure/azure_cis_v210_9_7.yaml old mode 100755 new mode 100644 index 9570a4afd..add02ae6f --- a/compliance/controls/azure/azure_cis_v210_9_7.yaml +++ b/compliance/controls/azure/azure_cis_v210_9_7.yaml @@ -1,59 +1,60 @@ +Description: Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version. ID: azure_cis_v210_9_7 -Title: "9.7 Ensure that 'Java version' is the latest, if used to run the Web App" -Description: "Periodically, newer versions are released for Java software either due to security flaws or to include additional functionality. Using the latest Java version for web apps is recommended in order to take advantage of security fixes, if any, and/or new functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with all_web_app as ( - select + ListOfTables: + - azure_app_service_web_app + - azure_subscription + Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + WITH all_web_app AS ( + SELECT id - from + FROM azure_app_service_web_app - where - exists ( - select - from - unnest(regexp_split_to_array(kind, ',')) elem - where - elem like 'app%' + WHERE + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE + elem LIKE 'app%' ) - and - exists ( - select - from - unnest(regexp_split_to_array(kind, ',')) elem - where + AND + EXISTS ( + SELECT + FROM + UNNEST(REGEXP_SPLIT_TO_ARRAY(kind, ',')) elem + WHERE elem = 'linux' ) ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when b.id is null then 'skip' - when configuration -> 'properties' ->> 'linuxFxVersion' not like 'JAVA%' then 'ok' - when configuration -> 'properties' ->> 'linuxFxVersion' like '%11' then 'ok' - else 'alarm' - end as status, - case - when b.id is null then a.title || ' is ' || a.kind || ' kind.' - when configuration -> 'properties' ->> 'linuxFxVersion' not like 'JAVA%' then a.name || ' not using JAVA version.' - when configuration -> 'properties' ->> 'linuxFxVersion' like '%11' then a.name || ' using the latest JAVA version.' - else a.name || ' not using latest JAVA version.' - end as reason - from - azure_app_service_web_app as a - left join all_web_app as b on a.id = b.id, - azure_subscription as sub - where + + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NULL THEN 'skip' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'JAVA%' THEN 'ok' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' LIKE '%11' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.id IS NULL THEN a.title || ' is ' || a.kind || ' kind.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' NOT LIKE 'JAVA%' THEN a.name || ' not using JAVA version.' + WHEN configuration -> 'properties' ->> 'linuxFxVersion' LIKE '%11' THEN a.name || ' using the latest JAVA version.' + ELSE a.name || ' not using latest JAVA version.' + END AS reason + FROM + azure_app_service_web_app AS a + LEFT JOIN all_web_app AS b ON a.id = b.id, + azure_subscription AS sub + WHERE sub.subscription_id = a.subscription_id; - PrimaryTable: azure_app_service_web_app - ListOfTables: - - azure_app_service_web_app - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.7 Ensure that 'Java version' is the latest, if used to run the Web App \ No newline at end of file diff --git a/compliance/controls/azure/azure_cis_v210_9_8.yaml b/compliance/controls/azure/azure_cis_v210_9_8.yaml old mode 100755 new mode 100644 index fb3993420..bb7f3f861 --- a/compliance/controls/azure/azure_cis_v210_9_8.yaml +++ b/compliance/controls/azure/azure_cis_v210_9_8.yaml @@ -1,32 +1,32 @@ +Description: Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version. ID: azure_cis_v210_9_8 -Title: "9.8 Ensure that 'HTTP Version' is the Latest, if Used to Run the Web App" -Description: "Periodically, newer versions are released for HTTP either due to security flaws or to include additional functionality. Using the latest HTTP version for web apps to take advantage of security fixes, if any, and/or new functionalities of the newer version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - app.id as resource, - app.og_account_id as og_account_id, - app.og_resource_id as og_resource_id, - case - when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then 'alarm' - else 'ok' - end as status, - case - when not (configuration -> 'properties' ->> 'http20Enabled') :: boolean then name || ' HTTP version not latest.' - else name || ' HTTP version is latest.' - end as reason - from - azure_app_service_web_app as app, - azure_subscription as sub - where - sub.subscription_id = app.subscription_id; - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + app.id AS resource, + app.og_account_id AS og_account_id, + app.og_resource_id AS og_resource_id, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::BOOLEAN THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (configuration -> 'properties' ->> 'http20Enabled')::BOOLEAN THEN name || ' HTTP version not latest.' + ELSE name || ' HTTP version is latest.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.8 Ensure that 'HTTP Version' is the Latest, if Used to Run the Web App \ No newline at end of file diff --git a/compliance/controls/azure/azure_cognitive_account_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_cognitive_account_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index c3e4c83f4..9ac999663 --- a/compliance/controls/azure/azure_cognitive_account_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_cognitive_account_encrypted_with_cmk.yaml @@ -1,19 +1,50 @@ +Description: Customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data stored in Cognitive Services to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_cognitive_account_encrypted_with_cmk -Title: "Cognitive Services accounts should enable data encryption with a customer-managed key" -Description: "Customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data stored in Cognitive Services to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with cognitive_account_cmk as (\n select\n distinct a.id\n from\n azure_cognitive_account as a,\n jsonb_array_elements(capabilities ) as c\n where\n c ->> 'name' = 'CustomerManagedKey'\n)\nselect\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when c.id is null then 'ok'\n when c.id is not null and encryption ->> 'keySource' = 'Microsoft.KeyVault' then 'ok'\n else 'alarm'\n end as status,\n case\n when c.id is null then name || ' encryption not supported.'\n when c.id is not null and encryption ->> 'keySource' = 'Microsoft.KeyVault' then name || ' encrypted with CMK.'\n else name || ' not encrypted with CMK.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_cognitive_account as s\n left join cognitive_account_cmk as c on c.id = s.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_cognitive_account ListOfTables: - azure_cognitive_account - azure_subscription Parameters: [] + PrimaryTable: azure_cognitive_account + QueryToExecute: | + WITH cognitive_account_cmk AS ( + SELECT + DISTINCT a.id + FROM + azure_cognitive_account AS a, + jsonb_array_elements(capabilities) AS c + WHERE + c ->> 'name' = 'CustomerManagedKey' + ) + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'ok' + WHEN c.id IS NOT NULL AND encryption ->> 'keySource' = 'Microsoft.KeyVault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.id IS NULL THEN name || ' encryption not supported.' + WHEN c.id IS NOT NULL AND encryption ->> 'keySource' = 'Microsoft.KeyVault' THEN name || ' encrypted with CMK.' + ELSE name || ' not encrypted with CMK.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cognitive_account AS s + LEFT JOIN cognitive_account_cmk AS c ON c.id = s.id, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/CognitiveServices -IntegrationType: - - azure_subscription +Title: Cognitive Services accounts should enable data encryption with a customer-managed key \ No newline at end of file diff --git a/compliance/controls/azure/azure_cognitive_account_private_link_used.yaml b/compliance/controls/azure/azure_cognitive_account_private_link_used.yaml old mode 100755 new mode 100644 index 3446bf17d..087c2e086 --- a/compliance/controls/azure/azure_cognitive_account_private_link_used.yaml +++ b/compliance/controls/azure/azure_cognitive_account_private_link_used.yaml @@ -1,19 +1,52 @@ +Description: Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Cognitive Services, you'll reduce the potential for data leakage. ID: azure_cognitive_account_private_link_used -Title: "Cognitive Services should use private link" -Description: "Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Cognitive Services, you'll reduce the potential for data leakage." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with cognitive_account as (\n select\n distinct a.id\n from\n azure_cognitive_account as a,\n jsonb_array_elements(capabilities ) as c\n where\n c ->> 'name' = 'VirtualNetworks'\n),\ncognitive_account_connections as (\n select\n distinct a.id\n from\n cognitive_account as a\n left join azure_cognitive_account as b on a.id = b.id,\n jsonb_array_elements(private_endpoint_connections ) as c\n where\n c -> 'PrivateLinkServiceConnectionState' ->> 'status' = 'Approved'\n)\nselect\n b.id as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when jsonb_array_length(b.private_endpoint_connections) = 0 then 'info'\n when c.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when jsonb_array_length(b.private_endpoint_connections) = 0 then b.name || ' no private link exists.'\n when c.id is not null then b.name || ' uses private link.'\n else b.name || ' not uses private link.'\n end as reason\n \n , b.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_cognitive_account as b\n left join cognitive_account_connections as c on b.id = c.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = b.subscription_id;\n" - PrimaryTable: azure_cognitive_account ListOfTables: - azure_cognitive_account - azure_subscription Parameters: [] + PrimaryTable: azure_cognitive_account + QueryToExecute: | + WITH cognitive_account AS ( + SELECT DISTINCT a.id + FROM azure_cognitive_account AS a, + jsonb_array_elements(capabilities) AS c + WHERE c ->> 'name' = 'VirtualNetworks' + ), + cognitive_account_connections AS ( + SELECT DISTINCT a.id + FROM cognitive_account AS a + LEFT JOIN azure_cognitive_account AS b ON a.id = b.id, + jsonb_array_elements(private_endpoint_connections) AS c + WHERE c -> 'PrivateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + b.id AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(b.private_endpoint_connections) = 0 THEN 'info' + WHEN c.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(b.private_endpoint_connections) = 0 THEN b.name || ' no private link exists.' + WHEN c.id IS NOT NULL THEN b.name || ' uses private link.' + ELSE b.name || ' not uses private link.' + END AS reason, + b.resource_group AS resource_group, + sub.display_name AS subscription + FROM azure_cognitive_account AS b + LEFT JOIN cognitive_account_connections AS c ON b.id = c.id, + azure_subscription AS sub + WHERE sub.subscription_id = b.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/CognitiveServices -IntegrationType: - - azure_subscription +Title: Cognitive Services should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_cognitive_account_public_network_access_disabled.yaml b/compliance/controls/azure/azure_cognitive_account_public_network_access_disabled.yaml old mode 100755 new mode 100644 index 2564b426f..4377258ce --- a/compliance/controls/azure/azure_cognitive_account_public_network_access_disabled.yaml +++ b/compliance/controls/azure/azure_cognitive_account_public_network_access_disabled.yaml @@ -1,19 +1,38 @@ +Description: Disabling public network access improves security by ensuring that Cognitive Services account isn't exposed on the public internet. Creating private endpoints can limit exposure of Cognitive Services account. ID: azure_cognitive_account_public_network_access_disabled -Title: "Cognitive Services accounts should disable public network access" -Description: "Disabling public network access improves security by ensuring that Cognitive Services account isn't exposed on the public internet. Creating private endpoints can limit exposure of Cognitive Services account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when public_network_access = 'Enabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when public_network_access = 'Enabled' then name || ' public network access enabled.'\n else name || ' public network access disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_cognitive_account as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_cognitive_account ListOfTables: - azure_cognitive_account - azure_subscription Parameters: [] + PrimaryTable: azure_cognitive_account + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN name || ' public network access enabled.' + ELSE name || ' public network access disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cognitive_account AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/CognitiveServices -IntegrationType: - - azure_subscription +Title: Cognitive Services accounts should disable public network access \ No newline at end of file diff --git a/compliance/controls/azure/azure_cognitive_account_restrict_public_access.yaml b/compliance/controls/azure/azure_cognitive_account_restrict_public_access.yaml old mode 100755 new mode 100644 index 8e82300e3..a94919a95 --- a/compliance/controls/azure/azure_cognitive_account_restrict_public_access.yaml +++ b/compliance/controls/azure/azure_cognitive_account_restrict_public_access.yaml @@ -1,19 +1,50 @@ +Description: Network access to Cognitive Services accounts should be restricted. Configure network rules so only applications from allowed networks can access the Cognitive Services account. To allow connections from specific internet or on-premises clients, access can be granted to traffic from specific Azure virtual networks or to public internet IP address ranges. ID: azure_cognitive_account_restrict_public_access -Title: "Cognitive Services accounts should restrict network access" -Description: "Network access to Cognitive Services accounts should be restricted. Configure network rules so only applications from allowed networks can access the Cognitive Services account. To allow connections from specific internet or on-premises clients, access can be granted to traffic from specific Azure virtual networks or to public internet IP address ranges." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with account_with_public_access_restricted as (\n select\n a.id\n from\n azure_cognitive_account as a,\n jsonb_array_elements(capabilities) as c\n where\n c ->> 'name' = 'VirtualNetworks' and network_acls ->> 'defaultAction' <> 'Deny'\n)\nselect\n distinct a.name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.id is not null then 'alarm'\n else 'ok'\n end as status,\n case\n when b.id is not null then a.name || ' publicly accessible.'\n else a.name || ' publicly not accessible.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_cognitive_account as a\n left join account_with_public_access_restricted as b on a.id = b.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_cognitive_account ListOfTables: - azure_cognitive_account - azure_subscription Parameters: [] + PrimaryTable: azure_cognitive_account + QueryToExecute: | + WITH account_with_public_access_restricted AS ( + SELECT + a.id + FROM + azure_cognitive_account AS a, + jsonb_array_elements(capabilities) AS c + WHERE + c ->> 'name' = 'VirtualNetworks' + AND network_acls ->> 'defaultAction' <> 'Deny' + ) + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.id IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.id IS NOT NULL THEN a.name || ' publicly accessible.' + ELSE a.name || ' publicly not accessible.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cognitive_account AS a + LEFT JOIN account_with_public_access_restricted AS b + ON a.id = b.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/CognitiveServices -IntegrationType: - - azure_subscription +Title: Cognitive Services accounts should restrict network access \ No newline at end of file diff --git a/compliance/controls/azure/azure_cognitive_service_local_auth_disabled.yaml b/compliance/controls/azure/azure_cognitive_service_local_auth_disabled.yaml old mode 100755 new mode 100644 index 2e3148535..e85baae30 --- a/compliance/controls/azure/azure_cognitive_service_local_auth_disabled.yaml +++ b/compliance/controls/azure/azure_cognitive_service_local_auth_disabled.yaml @@ -1,19 +1,36 @@ +Description: Disabling local authentication methods improves security by ensuring that Cognitive Services accounts require Azure Active Directory identities exclusively for authentication. ID: azure_cognitive_service_local_auth_disabled -Title: "Cognitive Services accounts should have local authentication methods disabled" -Description: "Disabling local authentication methods improves security by ensuring that Cognitive Services accounts require Azure Active Directory identities exclusively for authentication." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when disable_local_auth then 'ok'\n else 'alarm'\n end as status,\n case\n when disable_local_auth then a.name || ' account local authentication enabled.'\n else a.name || ' account local authentication disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_cognitive_account a,\n azure_subscription sub;\n" - PrimaryTable: azure_cognitive_account ListOfTables: - azure_cognitive_account - azure_subscription Parameters: [] + PrimaryTable: azure_cognitive_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN disable_local_auth THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN disable_local_auth THEN a.name || ' account local authentication enabled.' + ELSE a.name || ' account local authentication disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cognitive_account a, + azure_subscription sub; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/CognitiveServices -IntegrationType: - - azure_subscription +Title: Cognitive Services accounts should have local authentication methods disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_disk_access_uses_private_link.yaml b/compliance/controls/azure/azure_compute_disk_access_uses_private_link.yaml old mode 100755 new mode 100644 index 06025e25a..8d3549997 --- a/compliance/controls/azure/azure_compute_disk_access_uses_private_link.yaml +++ b/compliance/controls/azure/azure_compute_disk_access_uses_private_link.yaml @@ -1,19 +1,43 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to diskAccesses, data leakage risks are reduced. ID: azure_compute_disk_access_uses_private_link -Title: "Disk access resources should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to diskAccesses, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with compute_disk_connection as (\n select\n distinct a.id\n from\n azure_compute_disk_access as a,\n jsonb_array_elements(private_endpoint_connections) as connection\n where\n connection ->> 'PrivateLinkServiceConnectionStateStatus' = 'Approved'\n)\nselect\n b.id as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when c.id is null then b.name || ' not uses private link.'\n else b.name || ' uses private link.'\n end as reason\n \n , b.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_disk_access as b\n left join compute_disk_connection as c on b.id = c.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = b.subscription_id;\n" - PrimaryTable: azure_compute_disk_access ListOfTables: - azure_compute_disk_access - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk_access + QueryToExecute: | + WITH compute_disk_connection AS ( + SELECT DISTINCT a.id + FROM azure_compute_disk_access AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE connection ->> 'PrivateLinkServiceConnectionStateStatus' = 'Approved' + ) + SELECT + b.id AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN b.name || ' not uses private link.' + ELSE b.name || ' uses private link.' + END AS reason, + b.resource_group AS resource_group, + sub.display_name AS subscription + FROM azure_compute_disk_access AS b + LEFT JOIN compute_disk_connection AS c ON b.id = c.id, + azure_subscription AS sub + WHERE sub.subscription_id = b.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Disk access resources should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_disk_unattached_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_compute_disk_unattached_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 9059ccb81..b5e6ddad2 --- a/compliance/controls/azure/azure_compute_disk_unattached_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_compute_disk_unattached_encrypted_with_cmk.yaml @@ -1,41 +1,41 @@ +Description: This policy identifies the disks which are unattached and are encrypted with default encryption instead of ADE/CMK. Azure encrypts disks by default Server-Side Encryption (SSE) with platform-managed keys [SSE with PMK]. It is recommended to use either SSE with Azure Disk Encryption [SSE with PMK+ADE] or Customer Managed Key [SSE with CMK] which improves on platform-managed keys by giving you control of the encryption keys to meet your compliance need. ID: azure_compute_disk_unattached_encrypted_with_cmk -Title: "Unattached Compute disks should be encrypted with ADE/CMK" -Description: "This policy identifies the disks which are unattached and are encrypted with default encryption instead of ADE/CMK. Azure encrypts disks by default Server-Side Encryption (SSE) with platform-managed keys [SSE with PMK]. It is recommended to use either SSE with Azure Disk Encryption [SSE with PMK+ADE] or Customer Managed Key [SSE with CMK] which improves on platform-managed keys by giving you control of the encryption keys to meet your compliance need." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - disk.id as resource, - disk.og_account_id as og_account_id, - disk.og_resource_id as og_resource_id, - case - when managed_by is not null - or managed_by != '' - or encryption_type = 'EncryptionAtRestWithCustomerKey' - or encryption_type = 'EncryptionAtRestWithPlatformAndCustomerKeys' - then 'ok' - else 'alarm' - end as status, - case - when managed_by is not null - or managed_by != '' - or encryption_type = 'EncryptionAtRestWithCustomerKey' - or encryption_type = 'EncryptionAtRestWithPlatformAndCustomerKeys' - then disk.name || ' attached and encrypted with ADE/CMK.' - else disk.name || ' unattached and encrypted with default encryption key.' - end as reason - from - azure_compute_disk disk, - azure_subscription sub - where - disk_state != 'Attached' - and sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN managed_by IS NOT NULL + OR managed_by != '' + OR encryption_type = 'EncryptionAtRestWithCustomerKey' + OR encryption_type = 'EncryptionAtRestWithPlatformAndCustomerKeys' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN managed_by IS NOT NULL + OR managed_by != '' + OR encryption_type = 'EncryptionAtRestWithCustomerKey' + OR encryption_type = 'EncryptionAtRestWithPlatformAndCustomerKeys' + THEN disk.name || ' attached and encrypted with ADE/CMK.' + ELSE disk.name || ' unattached and encrypted with default encryption key.' + END AS reason + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state != 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Unattached Compute disks should be encrypted with ADE/CMK \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_os_and_data_disk_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_compute_os_and_data_disk_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index b13b5ce60..499e40ea1 --- a/compliance/controls/azure/azure_compute_os_and_data_disk_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_compute_os_and_data_disk_encrypted_with_cmk.yaml @@ -1,14 +1,35 @@ +Description: Use customer-managed keys to manage the encryption at rest of the contents of your managed disks. By default, the data is encrypted at rest with platform-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/disks-cmk. ID: azure_compute_os_and_data_disk_encrypted_with_cmk -Title: "OS and data disks should be encrypted with a customer-managed key" -Description: "Use customer-managed keys to manage the encryption at rest of the contents of your managed disks. By default, the data is encrypted at rest with platform-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/disks-cmk." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n disk.id as resource,\n disk.og_account_id as og_account_id,\n disk.og_resource_id as og_resource_id,\n case\n when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.'\n else disk.name || ' not encrypted with CMK.'\n end as reason\n \n , disk.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_disk disk,\n azure_subscription sub\nwhere\n disk_state = 'Attached'\n and sub.subscription_id = disk.subscription_id;\n" - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason, + disk.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state = 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: high Tags: category: @@ -29,5 +50,4 @@ Tags: - azure service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: OS and data disks should be encrypted with a customer-managed key \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_os_and_data_disk_encrypted_with_cmk_and_platform_managed.yaml b/compliance/controls/azure/azure_compute_os_and_data_disk_encrypted_with_cmk_and_platform_managed.yaml old mode 100755 new mode 100644 index 281653744..3da1cafda --- a/compliance/controls/azure/azure_compute_os_and_data_disk_encrypted_with_cmk_and_platform_managed.yaml +++ b/compliance/controls/azure/azure_compute_os_and_data_disk_encrypted_with_cmk_and_platform_managed.yaml @@ -1,19 +1,39 @@ +Description: High security sensitive customers who are concerned of the risk associated with any particular encryption algorithm, implementation, or key being compromised can opt for additional layer of encryption using a different encryption algorithm/mode at the infrastructure layer using platform managed encryption keys. The disk encryption sets are required to use double encryption. ID: azure_compute_os_and_data_disk_encrypted_with_cmk_and_platform_managed -Title: "Managed disks should be double encrypted with both platform-managed and customer-managed keys" -Description: "High security sensitive customers who are concerned of the risk associated with any particular encryption algorithm, implementation, or key being compromised can opt for additional layer of encryption using a different encryption algorithm/mode at the infrastructure layer using platform managed encryption keys. The disk encryption sets are required to use double encryption." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n disk.id as resource,\n disk.og_account_id as og_account_id,\n disk.og_resource_id as og_resource_id,\n case\n when encryption_type = 'EncryptionAtRestWithPlatformAndCustomerKeys' then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption_type = 'EncryptionAtRestWithPlatformAndCustomerKeys' then disk.name || ' encrypted with both platform-managed and customer-managed keys.'\n else disk.name || ' not encrypted with both platform-managed and customer-managed keys.'\n end as reason\n \n , disk.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_disk disk,\n azure_subscription sub\nwhere\n disk_state = 'Attached'\n and sub.subscription_id = disk.subscription_id;\n" - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithPlatformAndCustomerKeys' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithPlatformAndCustomerKeys' THEN disk.name || ' encrypted with both platform-managed and customer-managed keys.' + ELSE disk.name || ' not encrypted with both platform-managed and customer-managed keys.' + END AS reason, + disk.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state = 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Managed disks should be double encrypted with both platform-managed and customer-managed keys \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_unattached_disk_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_compute_unattached_disk_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 4578f2d96..b9f8fba06 --- a/compliance/controls/azure/azure_compute_unattached_disk_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_compute_unattached_disk_encrypted_with_cmk.yaml @@ -1,14 +1,35 @@ +Description: Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK). ID: azure_compute_unattached_disk_encrypted_with_cmk -Title: "Ensure that 'Unattached disks' are encrypted with 'Customer Managed Key' (CMK)" -Description: "Ensure that unattached disks in a subscription are encrypted with a Customer Managed Key (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n disk.id as resource,\n disk.og_account_id as og_account_id,\n disk.og_resource_id as og_resource_id,\n case\n when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption_type = 'EncryptionAtRestWithCustomerKey' then disk.name || ' encrypted with CMK.'\n else disk.name || ' not encrypted with CMK.'\n end as reason\n \n , disk.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_disk disk,\n azure_subscription sub\nwhere\n disk_state != 'Attached'\n and sub.subscription_id = disk.subscription_id;\n" - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id AS og_account_id, + disk.og_resource_id AS og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN disk.name || ' encrypted with CMK.' + ELSE disk.name || ' not encrypted with CMK.' + END AS reason, + disk.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_disk disk, + azure_subscription sub + WHERE + disk_state != 'Attached' + AND sub.subscription_id = disk.subscription_id; Severity: medium Tags: category: @@ -29,5 +50,4 @@ Tags: - azure service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Ensure that 'Unattached disks' are encrypted with 'Customer Managed Key' (CMK) \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_account_with_password_linux.yaml b/compliance/controls/azure/azure_compute_vm_account_with_password_linux.yaml old mode 100755 new mode 100644 index 4a8ea8d5a..0d8a3f66e --- a/compliance/controls/azure/azure_compute_vm_account_with_password_linux.yaml +++ b/compliance/controls/azure/azure_compute_vm_account_with_password_linux.yaml @@ -1,19 +1,51 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Linux machines have accounts without passwords. ID: azure_compute_vm_account_with_password_linux -Title: "Audit Linux machines that have accounts without passwords" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Linux machines that have accounts without passwords." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_ssh_key_auth as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(guest_configuration_assignments) as b\n where\n b -> 'guestConfiguration' ->> 'name'= 'PasswordPolicy_msid232'\n and b ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Linux' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Linux' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' have accounts with passwords.'\n else a.title || ' does not have have accounts with passwords.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join vm_ssh_key_auth as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_ssh_key_auth AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + JSONB_ARRAY_ELEMENTS(guest_configuration_assignments) AS b + WHERE + b -> 'guestConfiguration' ->> 'name' = 'PasswordPolicy_msid232' + AND b ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Linux' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Linux' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' have accounts with passwords.' + ELSE a.title || ' does not have accounts with passwords.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN vm_ssh_key_auth AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Audit Linux machines that have accounts without passwords \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_adaptive_application_controls_enabled.yaml b/compliance/controls/azure/azure_compute_vm_adaptive_application_controls_enabled.yaml old mode 100755 new mode 100644 index 69e7cfecc..05e729c05 --- a/compliance/controls/azure/azure_compute_vm_adaptive_application_controls_enabled.yaml +++ b/compliance/controls/azure/azure_compute_vm_adaptive_application_controls_enabled.yaml @@ -1,24 +1,24 @@ +Description: Enable application controls to define the list of known-safe applications running on your machines, and alert you when other applications run. This helps harden your machines against malware. To simplify the process of configuring and maintaining your rules, Security Center uses machine learning to analyze the applications running on each machine and suggest the list of known-safe applications. ID: azure_compute_vm_adaptive_application_controls_enabled -Title: "Adaptive application controls for defining safe applications should be enabled on your machines" -Description: "Enable application controls to define the list of known-safe applications running on your machines, and alert you when other applications run. This helps harden your machines against malware. To simplify the process of configuring and maintaining your rules, Security Center uses machine learning to analyze the applications running on each machine and suggest the list of known-safe applications." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Adaptive application controls for defining safe applications should be enabled on your machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_adaptive_network_hardening_recommendation_applied.yaml b/compliance/controls/azure/azure_compute_vm_adaptive_network_hardening_recommendation_applied.yaml old mode 100755 new mode 100644 index a46e0ca4f..fc8d0b227 --- a/compliance/controls/azure/azure_compute_vm_adaptive_network_hardening_recommendation_applied.yaml +++ b/compliance/controls/azure/azure_compute_vm_adaptive_network_hardening_recommendation_applied.yaml @@ -1,24 +1,24 @@ +Description: Azure Security Center analyzes the traffic patterns of Internet facing virtual machines and provides Network Security Group rule recommendations that reduce the potential attack surface. ID: azure_compute_vm_adaptive_network_hardening_recommendation_applied -Title: "Adaptive network hardening recommendations should be applied on internet facing virtual machines" -Description: "Azure Security Center analyzes the traffic patterns of Internet facing virtual machines and provides Network Security Group rule recommendations that reduce the potential attack surface." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Adaptive network hardening recommendations should be applied on internet facing virtual machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_administrators_group_with_extra_accounts_windows.yaml b/compliance/controls/azure/azure_compute_vm_administrators_group_with_extra_accounts_windows.yaml old mode 100755 new mode 100644 index 7a6e5e2f6..1358e368d --- a/compliance/controls/azure/azure_compute_vm_administrators_group_with_extra_accounts_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_administrators_group_with_extra_accounts_windows.yaml @@ -1,24 +1,24 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the local Administrators group contains members that are not listed in the policy parameter. ID: azure_compute_vm_administrators_group_with_extra_accounts_windows -Title: "Audit Windows machines that have extra accounts in the Administrators group" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the local Administrators group contains members that are not listed in the policy parameter." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Audit Windows machines that have extra accounts in the Administrators group \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_administrators_group_with_no_specified_members_windows.yaml b/compliance/controls/azure/azure_compute_vm_administrators_group_with_no_specified_members_windows.yaml old mode 100755 new mode 100644 index 5ecd9591d..d50757f86 --- a/compliance/controls/azure/azure_compute_vm_administrators_group_with_no_specified_members_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_administrators_group_with_no_specified_members_windows.yaml @@ -1,24 +1,24 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the local Administrators group does not contain one or more members that are listed in the policy parameter. ID: azure_compute_vm_administrators_group_with_no_specified_members_windows -Title: "Audit Windows machines missing any of specified members in the Administrators group" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the local Administrators group does not contain one or more members that are listed in the policy parameter." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Audit Windows machines missing any of specified members in the Administrators group \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_administrators_group_with_specified_members_windows.yaml b/compliance/controls/azure/azure_compute_vm_administrators_group_with_specified_members_windows.yaml old mode 100755 new mode 100644 index 4164c7a41..1d267616e --- a/compliance/controls/azure/azure_compute_vm_administrators_group_with_specified_members_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_administrators_group_with_specified_members_windows.yaml @@ -1,24 +1,24 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the local Administrators group contains one or more of the members listed in the policy parameter. ID: azure_compute_vm_administrators_group_with_specified_members_windows -Title: "Audit Windows machines that have the specified members in the Administrators group" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the local Administrators group contains one or more of the members listed in the policy parameter." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Audit Windows machines that have the specified members in the Administrators group \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_allowlist_rules_in_adaptive_application_control_policy_updated.yaml b/compliance/controls/azure/azure_compute_vm_allowlist_rules_in_adaptive_application_control_policy_updated.yaml old mode 100755 new mode 100644 index 551ed01e0..344261bf5 --- a/compliance/controls/azure/azure_compute_vm_allowlist_rules_in_adaptive_application_control_policy_updated.yaml +++ b/compliance/controls/azure/azure_compute_vm_allowlist_rules_in_adaptive_application_control_policy_updated.yaml @@ -1,24 +1,24 @@ +Description: Monitor for changes in behavior on groups of machines configured for auditing by Azure Security Center's adaptive application controls. Security Center uses machine learning to analyze the running processes on your machines and suggest a list of known-safe applications. These are presented as recommended apps to allow in adaptive application control policies. ID: azure_compute_vm_allowlist_rules_in_adaptive_application_control_policy_updated -Title: "Allowlist rules in your adaptive application control policy should be updated" -Description: "Monitor for changes in behavior on groups of machines configured for auditing by Azure Security Center's adaptive application controls. Security Center uses machine learning to analyze the running processes on your machines and suggest a list of known-safe applications. These are presented as recommended apps to allow in adaptive application control policies." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Allowlist rules in your adaptive application control policy should be updated \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_and_sacle_set_encryption_at_host_enabled.yaml b/compliance/controls/azure/azure_compute_vm_and_sacle_set_encryption_at_host_enabled.yaml old mode 100755 new mode 100644 index 736ca913b..281ac3fd3 --- a/compliance/controls/azure/azure_compute_vm_and_sacle_set_encryption_at_host_enabled.yaml +++ b/compliance/controls/azure/azure_compute_vm_and_sacle_set_encryption_at_host_enabled.yaml @@ -1,20 +1,65 @@ +Description: Use encryption at host to get end-to-end encryption for your virtual machine and virtual machine scale set data. Encryption at host enables encryption at rest for your temporary disk and OS/data disk caches. Temporary and ephemeral OS disks are encrypted with platform-managed keys when encryption at host is enabled. OS/data disk caches are encrypted at rest with either customer-managed or platform-managed key, depending on the encryption type selected on the disk. ID: azure_compute_vm_and_sacle_set_encryption_at_host_enabled -Title: "Virtual machines and virtual machine scale sets should have encryption at host enabled" -Description: "Use encryption at host to get end-to-end encryption for your virtual machine and virtual machine scale set data. Encryption at host enables encryption at rest for your temporary disk and OS/data disk caches. Temporary and ephemeral OS disks are encrypted with platform-managed keys when encryption at host is enabled. OS/data disk caches are encrypted at rest with either customer-managed or platform-managed key, depending on the encryption type selected on the disk." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\n select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n 'azure_compute_virtual_machine' as og_table_name,\n case\n when security_profile -> 'encryptionAtHost' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when security_profile -> 'encryptionAtHost' = 'true' then a.name || ' encryption at host enabled.'\n else a.name || ' encryption at host disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\n from\n azure_compute_virtual_machine as a,\n azure_subscription as sub\n where\n sub.subscription_id = a.subscription_id\n)\nunion\n(\n select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n 'azure_compute_virtual_machine_scale_set' as og_table_name,\n case\n when virtual_machine_security_profile -> 'encryptionAtHost' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when virtual_machine_security_profile -> 'encryptionAtHost' = 'true' then a.name || ' encryption at host enabled.'\n else a.name || ' encryption at host disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\n from\n azure_compute_virtual_machine_scale_set as a,\n azure_subscription as sub\n where\n sub.subscription_id = a.subscription_id\n)\n" - PrimaryTable: "" ListOfTables: - azure_compute_virtual_machine - azure_compute_virtual_machine_scale_set - azure_subscription Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + 'azure_compute_virtual_machine' AS og_table_name, + CASE + WHEN security_profile -> 'encryptionAtHost' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN security_profile -> 'encryptionAtHost' = 'true' THEN a.name || ' encryption at host enabled.' + ELSE a.name || ' encryption at host disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id + ) + UNION + ( + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + 'azure_compute_virtual_machine_scale_set' AS og_table_name, + CASE + WHEN virtual_machine_security_profile -> 'encryptionAtHost' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN virtual_machine_security_profile -> 'encryptionAtHost' = 'true' THEN a.name || ' encryption at host enabled.' + ELSE a.name || ' encryption at host disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine_scale_set AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id + ) Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Virtual machines and virtual machine scale sets should have encryption at host enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_attached_with_network.yaml b/compliance/controls/azure/azure_compute_vm_attached_with_network.yaml old mode 100755 new mode 100644 index 2a344b259..518ffa6aa --- a/compliance/controls/azure/azure_compute_vm_attached_with_network.yaml +++ b/compliance/controls/azure/azure_compute_vm_attached_with_network.yaml @@ -1,20 +1,66 @@ +Description: This policy audits any virtual machine connected to a virtual network that is not approved. ID: azure_compute_vm_attached_with_network -Title: "Virtual machines should be connected to an approved virtual network" -Description: "This policy audits any virtual machine connected to a virtual network that is not approved." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_with_network_interfaces as (\n select\n vm.id as vm_id,\n n ->> 'id' as network_id\n from\n azure_compute_virtual_machine as vm,\n jsonb_array_elements(network_interfaces) as n\n),\nvm_with_appoved_networks as (\n select\n vn.vm_id as vm_id,\n vn.network_id as network_id,\n t.title as title\n from\n vm_with_network_interfaces as vn\n left join azure_network_interface as t on t.id = vn.network_id\n where exists\n (select\n ip -> 'properties' -> 'subnet' ->> 'id' as ip\n FROM\n azure_network_interface,\n jsonb_array_elements(ip_configurations) as ip\n where\n ip -> 'properties' -> 'subnet' ->> 'id' is not null)\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.vm_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when b.vm_id is null then a.title || ' not attached with virtual network.'\n else a.name || ' attached with virtual network ' || b.title || '.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join vm_with_appoved_networks as b on a.id = b.vm_id,\n azure_subscription sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_network_interface - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_with_network_interfaces AS ( + SELECT + vm.id AS vm_id, + n ->> 'id' AS network_id + FROM + azure_compute_virtual_machine AS vm, + jsonb_array_elements(network_interfaces) AS n + ), + vm_with_approved_networks AS ( + SELECT + vn.vm_id AS vm_id, + vn.network_id AS network_id, + t.title AS title + FROM + vm_with_network_interfaces AS vn + LEFT JOIN azure_network_interface AS t ON t.id = vn.network_id + WHERE EXISTS ( + SELECT + ip -> 'properties' -> 'subnet' ->> 'id' AS ip + FROM + azure_network_interface, + jsonb_array_elements(ip_configurations) AS ip + WHERE + ip -> 'properties' -> 'subnet' ->> 'id' IS NOT NULL + ) + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.vm_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.vm_id IS NULL THEN a.title || ' not attached with virtual network.' + ELSE a.name || ' attached with virtual network ' || b.title || '.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN vm_with_approved_networks AS b ON a.id = b.vm_id, + azure_subscription sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Virtual machines should be connected to an approved virtual network \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_azure_backup_enabled.yaml b/compliance/controls/azure/azure_compute_vm_azure_backup_enabled.yaml old mode 100755 new mode 100644 index 38ea9f15e..59259c526 --- a/compliance/controls/azure/azure_compute_vm_azure_backup_enabled.yaml +++ b/compliance/controls/azure/azure_compute_vm_azure_backup_enabled.yaml @@ -1,24 +1,24 @@ +Description: Ensure protection of your Azure Virtual Machines by enabling Azure Backup. Azure Backup is a secure and cost effective data protection solution for Azure. ID: azure_compute_vm_azure_backup_enabled -Title: "Azure Backup should be enabled for Virtual Machines" -Description: "Ensure protection of your Azure Virtual Machines by enabling Azure Backup. Azure Backup is a secure and cost effective data protection solution for Azure." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Azure Backup should be enabled for Virtual Machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_container_security_configurations_vulnerabilities_remediated.yaml b/compliance/controls/azure/azure_compute_vm_container_security_configurations_vulnerabilities_remediated.yaml old mode 100755 new mode 100644 index 40ec23a27..a6e62f43a --- a/compliance/controls/azure/azure_compute_vm_container_security_configurations_vulnerabilities_remediated.yaml +++ b/compliance/controls/azure/azure_compute_vm_container_security_configurations_vulnerabilities_remediated.yaml @@ -1,24 +1,24 @@ +Description: Audit vulnerabilities in security configuration on machines with Docker installed and display as recommendations in Azure Security Center. ID: azure_compute_vm_container_security_configurations_vulnerabilities_remediated -Title: "Vulnerabilities in container security configurations should be remediated" -Description: "Audit vulnerabilities in security configuration on machines with Docker installed and display as recommendations in Azure Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Vulnerabilities in container security configurations should be remediated \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_data_and_os_disk_uses_managed_disk.yaml b/compliance/controls/azure/azure_compute_vm_data_and_os_disk_uses_managed_disk.yaml old mode 100755 new mode 100644 index 5ee6e2cbe..ac3a4fbaf --- a/compliance/controls/azure/azure_compute_vm_data_and_os_disk_uses_managed_disk.yaml +++ b/compliance/controls/azure/azure_compute_vm_data_and_os_disk_uses_managed_disk.yaml @@ -1,49 +1,49 @@ +Description: This control checks whether virtual machines use managed disks for OS and data disks. ID: azure_compute_vm_data_and_os_disk_uses_managed_disk -Title: "Compute virtual machines should use managed disk for OS and data disk" -Description: "This control checks whether virtual machines use managed disks for OS and data disks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with data_disk_with_no_managed_disk as ( - select - id as vm_id, - count(*) as count - from - azure_compute_virtual_machine, - jsonb_array_elements(data_disks) as d - where - d -> 'managedDisk' ->> 'id' is null - group by - id - ) - select - vm.id as resource, - vm.og_account_id as og_account_id, - vm.og_resource_id as og_resource_id, - case - when managed_disk_id is null and d.count > 0 then 'alarm' - when managed_disk_id is null then 'alarm' - when d.count > 0 then 'alarm' - else 'ok' - end as status, - case - when managed_disk_id is null and d.count > 0 then vm.name || ' not utilizing managed disks for both data and OS disk.' - when managed_disk_id is null then vm.name || ' not utilizing managed disks for OS disk.' - when d.count > 0 then vm.name || ' not utilizing managed disks for data disk.' - else vm.name || ' utilizing managed disks for both data and OS disk.' - end as reason - from - azure_compute_virtual_machine as vm - left join data_disk_with_no_managed_disk as d on d.vm_id = vm.id, - azure_subscription as sub - where - sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH data_disk_with_no_managed_disk AS ( + SELECT + id AS vm_id, + COUNT(*) AS count + FROM + azure_compute_virtual_machine, + jsonb_array_elements(data_disks) AS d + WHERE + d -> 'managedDisk' ->> 'id' IS NULL + GROUP BY + id + ) + SELECT + vm.id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN managed_disk_id IS NULL AND d.count > 0 THEN 'alarm' + WHEN managed_disk_id IS NULL THEN 'alarm' + WHEN d.count > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN managed_disk_id IS NULL AND d.count > 0 THEN vm.name || ' not utilizing managed disks for both data and OS disk.' + WHEN managed_disk_id IS NULL THEN vm.name || ' not utilizing managed disks for OS disk.' + WHEN d.count > 0 THEN vm.name || ' not utilizing managed disks for data disk.' + ELSE vm.name || ' utilizing managed disks for both data and OS disk.' + END AS reason + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN data_disk_with_no_managed_disk AS d ON d.vm_id = vm.id, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Compute virtual machines should use managed disk for OS and data disk \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_disaster_recovery_enabled.yaml b/compliance/controls/azure/azure_compute_vm_disaster_recovery_enabled.yaml old mode 100755 new mode 100644 index e2a8ae376..f30152278 --- a/compliance/controls/azure/azure_compute_vm_disaster_recovery_enabled.yaml +++ b/compliance/controls/azure/azure_compute_vm_disaster_recovery_enabled.yaml @@ -1,20 +1,51 @@ +Description: Audit virtual machines which do not have disaster recovery configured. ID: azure_compute_vm_disaster_recovery_enabled -Title: "Audit virtual machines without disaster recovery configured" -Description: "Audit virtual machines which do not have disaster recovery configured." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_dr_enabled as (\n select\n substr(source_id, 0, length(source_id)) as source_id\n from\n azure_resource_link as l\n left join azure_compute_virtual_machine as vm on lower(substr(source_id, 0, length(source_id)))= lower(vm.id)\n where\n l.name like 'ASR-Protect-%'\n)\nselect\n vm.vm_id as resource,\n vm.og_account_id as og_account_id,\n vm.og_resource_id as og_resource_id,\n case\n when l.source_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when l.source_id is null then vm.title || ' disaster recovery disabled.'\n else vm.title || ' disaster recovery enabled.'\n end as reason\n \n , vm.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as vm\n left join vm_dr_enabled as l on lower(vm.id) = lower(l.source_id),\n azure_subscription sub\nwhere\n sub.subscription_id = vm.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_resource_link - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_dr_enabled AS ( + SELECT + SUBSTR(source_id, 0, LENGTH(source_id)) AS source_id + FROM + azure_resource_link AS l + LEFT JOIN azure_compute_virtual_machine AS vm + ON LOWER(SUBSTR(source_id, 0, LENGTH(source_id))) = LOWER(vm.id) + WHERE + l.name LIKE 'ASR-Protect-%' + ) + SELECT + vm.vm_id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN l.source_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN l.source_id IS NULL THEN vm.title || ' disaster recovery disabled.' + ELSE vm.title || ' disaster recovery enabled.' + END AS reason, + vm.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN vm_dr_enabled AS l + ON LOWER(vm.id) = LOWER(l.source_id), + azure_subscription sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Audit virtual machines without disaster recovery configured \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_endpoint_protection_agent_installed.yaml b/compliance/controls/azure/azure_compute_vm_endpoint_protection_agent_installed.yaml old mode 100755 new mode 100644 index b467299ba..674b1e5a4 --- a/compliance/controls/azure/azure_compute_vm_endpoint_protection_agent_installed.yaml +++ b/compliance/controls/azure/azure_compute_vm_endpoint_protection_agent_installed.yaml @@ -1,24 +1,24 @@ +Description: Servers without an installed Endpoint Protection agent will be monitored by Azure Security Center as recommendations. ID: azure_compute_vm_endpoint_protection_agent_installed -Title: "Monitor missing Endpoint Protection in Azure Security Center" -Description: "Servers without an installed Endpoint Protection agent will be monitored by Azure Security Center as recommendations." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Monitor missing Endpoint Protection in Azure Security Center \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_guest_configuration_installed.yaml b/compliance/controls/azure/azure_compute_vm_guest_configuration_installed.yaml old mode 100755 new mode 100644 index 87b643f35..d4c31f6bd --- a/compliance/controls/azure/azure_compute_vm_guest_configuration_installed.yaml +++ b/compliance/controls/azure/azure_compute_vm_guest_configuration_installed.yaml @@ -1,19 +1,49 @@ +Description: To ensure secure configurations of in-guest settings of your machine, install the Guest Configuration extension. In-guest settings that the extension monitors include the configuration of the operating system, application configuration or presence, and environment settings. Once installed, in-guest policies will be available such as 'Windows Exploit guard should be enabled'. ID: azure_compute_vm_guest_configuration_installed -Title: "Guest Configuration extension should be installed on your machines" -Description: "To ensure secure configurations of in-guest settings of your machine, install the Guest Configuration extension. In-guest settings that the extension monitors include the configuration of the operating system, application configuration or presence, and environment settings. Once installed, in-guest policies will be available such as 'Windows Exploit guard should be enabled'." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with agent_installed_vm as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.GuestConfiguration'\n and b ->> 'ProvisioningState' = 'Succeeded'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.vm_id is not null then a.title || ' have guest configuration extension installed.'\n else a.title || ' guest configuration extension not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH agent_installed_vm AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.GuestConfiguration' + AND b ->> 'ProvisioningState' = 'Succeeded' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.vm_id IS NOT NULL THEN a.title || ' have guest configuration extension installed.' + ELSE a.title || ' guest configuration extension not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Guest Configuration extension should be installed on your machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_guest_configuration_installed_linux.yaml b/compliance/controls/azure/azure_compute_vm_guest_configuration_installed_linux.yaml old mode 100755 new mode 100644 index b407312d2..579b4812f --- a/compliance/controls/azure/azure_compute_vm_guest_configuration_installed_linux.yaml +++ b/compliance/controls/azure/azure_compute_vm_guest_configuration_installed_linux.yaml @@ -1,19 +1,53 @@ +Description: This policy deploys the Linux Guest Configuration extension to Linux virtual machines hosted in Azure that are supported by Guest Configuration. The Linux Guest Configuration extension is a prerequisite for all Linux Guest Configuration assignments and must be deployed to machines before using any Linux Guest Configuration policy definition. ID: azure_compute_vm_guest_configuration_installed_linux -Title: "Deploy the Linux Guest Configuration extension to enable Guest Configuration assignments on Linux VMs" -Description: "This policy deploys the Linux Guest Configuration extension to Linux virtual machines hosted in Azure that are supported by Guest Configuration. The Linux Guest Configuration extension is a prerequisite for all Linux Guest Configuration assignments and must be deployed to machines before using any Linux Guest Configuration policy definition." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with agent_installed_vm as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.GuestConfiguration'\n and b ->> 'ProvisioningState' = 'Succeeded'\n and b ->> 'ExtensionType' = 'ConfigurationforLinux'\n and b ->> 'Name' like '%AzurePolicyforLinux'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Linux' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Linux' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' have guest configuration extension installed.'\n else a.title || ' guest configuration extension not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH agent_installed_vm AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + JSONB_ARRAY_ELEMENTS(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.GuestConfiguration' + AND b ->> 'ProvisioningState' = 'Succeeded' + AND b ->> 'ExtensionType' = 'ConfigurationforLinux' + AND b ->> 'Name' LIKE '%AzurePolicyforLinux' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Linux' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Linux' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' have guest configuration extension installed.' + ELSE a.title || ' guest configuration extension not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Deploy the Linux Guest Configuration extension to enable Guest Configuration assignments on Linux VMs \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_guest_configuration_installed_windows.yaml b/compliance/controls/azure/azure_compute_vm_guest_configuration_installed_windows.yaml old mode 100755 new mode 100644 index b5d44d924..412bb2f97 --- a/compliance/controls/azure/azure_compute_vm_guest_configuration_installed_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_guest_configuration_installed_windows.yaml @@ -1,14 +1,49 @@ +Description: This policy deploys the Windows Guest Configuration extension to Windows virtual machines hosted in Azure that are supported by Guest Configuration. The Windows Guest Configuration extension is a prerequisite for all Windows Guest Configuration assignments and must be deployed to machines before using any Windows Guest Configuration policy definition. ID: azure_compute_vm_guest_configuration_installed_windows -Title: "Deploy the Windows Guest Configuration extension to enable Guest Configuration assignments on Windows VMs" -Description: "This policy deploys the Windows Guest Configuration extension to Windows virtual machines hosted in Azure that are supported by Guest Configuration. The Windows Guest Configuration extension is a prerequisite for all Windows Guest Configuration assignments and must be deployed to machines before using any Windows Guest Configuration policy definition." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with agent_installed_vm as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.GuestConfiguration'\n and b ->> 'ProvisioningState' = 'Succeeded'\n and b ->> 'ExtensionType' = 'ConfigurationforWindows'\n and b ->> 'Name' like '%AzurePolicyforWindows'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' have guest configuration extension installed.'\n else a.title || ' guest configuration extension not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH agent_installed_vm AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.GuestConfiguration' + AND b ->> 'ProvisioningState' = 'Succeeded' + AND b ->> 'ExtensionType' = 'ConfigurationforWindows' + AND b ->> 'Name' LIKE '%AzurePolicyforWindows' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' have guest configuration extension installed.' + ELSE a.title || ' guest configuration extension not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: @@ -17,5 +52,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Deploy the Windows Guest Configuration extension to enable Guest Configuration assignments on Windows VMs \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_guest_configuration_with_no_managed_identity.yaml b/compliance/controls/azure/azure_compute_vm_guest_configuration_with_no_managed_identity.yaml old mode 100755 new mode 100644 index b449c19b9..35c574435 --- a/compliance/controls/azure/azure_compute_vm_guest_configuration_with_no_managed_identity.yaml +++ b/compliance/controls/azure/azure_compute_vm_guest_configuration_with_no_managed_identity.yaml @@ -1,19 +1,51 @@ +Description: This policy adds a system-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration but do not have any managed identities. A system-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions. ID: azure_compute_vm_guest_configuration_with_no_managed_identity -Title: "Add system-assigned managed identity to enable Guest Configuration assignments on virtual machines with no identities" -Description: "This policy adds a system-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration but do not have any managed identities. A system-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with gc_installed_vm as (\n select\n distinct a.vm_id,\n title\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.GuestConfiguration'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.vm_id is null then 'skip'\n when b.vm_id is not null and identity ->> 'type' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.vm_id is null then a.title || ' guest configuration extension not installed.'\n when b.vm_id is not null and identity ->> 'type' is not null then a.title || ' guest configuration extension installed with ' || (identity ->> 'type') || ' managed identity.'\n else a.title || ' guest configuration extension not installed with managed identity.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join gc_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH gc_installed_vm AS ( + SELECT + DISTINCT a.vm_id, + title + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.GuestConfiguration' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.vm_id IS NULL THEN 'skip' + WHEN b.vm_id IS NOT NULL AND identity ->> 'type' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.vm_id IS NULL THEN a.title || ' guest configuration extension not installed.' + WHEN b.vm_id IS NOT NULL AND identity ->> 'type' IS NOT NULL THEN a.title || ' guest configuration extension installed with ' || (identity ->> 'type') || ' managed identity.' + ELSE a.title || ' guest configuration extension not installed with managed identity.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN gc_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: pci_dss_v321: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Add system-assigned managed identity to enable Guest Configuration assignments on virtual machines with no identities \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_guest_configuration_with_system_assigned_managed_identity.yaml b/compliance/controls/azure/azure_compute_vm_guest_configuration_with_system_assigned_managed_identity.yaml old mode 100755 new mode 100644 index a293ea3ee..4a1d68475 --- a/compliance/controls/azure/azure_compute_vm_guest_configuration_with_system_assigned_managed_identity.yaml +++ b/compliance/controls/azure/azure_compute_vm_guest_configuration_with_system_assigned_managed_identity.yaml @@ -1,19 +1,51 @@ +Description: The Guest Configuration extension requires a system assigned managed identity. Azure virtual machines in the scope of this policy will be non-compliant when they have the Guest Configuration extension installed but do not have a system assigned managed identity. ID: azure_compute_vm_guest_configuration_with_system_assigned_managed_identity -Title: "Virtual machines' Guest Configuration extension should be deployed with system-assigned managed identity" -Description: "The Guest Configuration extension requires a system assigned managed identity. Azure virtual machines in the scope of this policy will be non-compliant when they have the Guest Configuration extension installed but do not have a system assigned managed identity." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with gc_installed_vm as (\n select\n distinct a.vm_id,\n title\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.GuestConfiguration'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.vm_id is null then 'skip'\n when b.vm_id is not null and string_to_array(identity ->> 'type' , ', ') @> array['SystemAssigned'] then 'ok'\n else 'alarm'\n end as status,\n case\n when b.vm_id is null then a.title || ' guest configuration extension not installed.'\n when b.vm_id is not null and string_to_array(identity ->> 'type' , ', ') @> array['SystemAssigned'] then a.title || ' guest configuration extension installed with system-assigned managed identity.'\n else a.title || ' guest configuration extension not installed with system-assigned managed identity.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join gc_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH gc_installed_vm AS ( + SELECT + DISTINCT a.vm_id, + title + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.GuestConfiguration' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.vm_id IS NULL THEN 'skip' + WHEN b.vm_id IS NOT NULL AND string_to_array(identity ->> 'type', ', ') @> ARRAY['SystemAssigned'] THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.vm_id IS NULL THEN a.title || ' guest configuration extension not installed.' + WHEN b.vm_id IS NOT NULL AND string_to_array(identity ->> 'type', ', ') @> ARRAY['SystemAssigned'] THEN a.title || ' guest configuration extension installed with system-assigned managed identity.' + ELSE a.title || ' guest configuration extension not installed with system-assigned managed identity.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN gc_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Virtual machines' Guest Configuration extension should be deployed with system-assigned managed identity \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_guest_configuration_with_user_and_system_assigned_managed_identity.yaml b/compliance/controls/azure/azure_compute_vm_guest_configuration_with_user_and_system_assigned_managed_identity.yaml old mode 100755 new mode 100644 index 20c0b42aa..4e14b4ba9 --- a/compliance/controls/azure/azure_compute_vm_guest_configuration_with_user_and_system_assigned_managed_identity.yaml +++ b/compliance/controls/azure/azure_compute_vm_guest_configuration_with_user_and_system_assigned_managed_identity.yaml @@ -1,14 +1,50 @@ +Description: This policy adds a system-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration and have at least one user-assigned identity but do not have a system-assigned managed identity. A system-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions. ID: azure_compute_vm_guest_configuration_with_user_and_system_assigned_managed_identity -Title: "Add system-assigned managed identity to enable Guest Configuration assignments on VMs with a user-assigned identity" -Description: "This policy adds a system-assigned managed identity to virtual machines hosted in Azure that are supported by Guest Configuration and have at least one user-assigned identity but do not have a system-assigned managed identity. A system-assigned managed identity is a prerequisite for all Guest Configuration assignments and must be added to machines before using any Guest Configuration policy definitions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with gc_installed_vm as (\n select\n distinct a.vm_id,\n title\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.GuestConfiguration'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.vm_id is null then 'skip'\n when not string_to_array(a.identity ->> 'type' , ', ') @> array['UserAssigned'] then 'skip'\n when string_to_array(identity ->> 'type' , ', ') @> array['UserAssigned', 'SystemAssigned'] then 'ok'\n else 'alarm'\n end as status,\n case\n when b.vm_id is null then a.title || ' guest configuration extension not installed.'\n when not string_to_array(a.identity ->> 'type' , ', ') @> array['UserAssigned'] then a.title || ' does not have user assigned managed identity.'\n when string_to_array(identity ->> 'type' , ', ') @> array['UserAssigned', 'SystemAssigned'] then a.title || ' guest configuration extension installed with user and system assigned managed identity.'\n else a.title || ' guest configuration extension not installed with user and system assigned managed identity.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join gc_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH gc_installed_vm AS ( + SELECT + DISTINCT a.vm_id, + title + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.GuestConfiguration' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.vm_id IS NULL THEN 'skip' + WHEN NOT string_to_array(a.identity ->> 'type', ', ') @> ARRAY['UserAssigned'] THEN 'skip' + WHEN string_to_array(a.identity ->> 'type', ', ') @> ARRAY['UserAssigned', 'SystemAssigned'] THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.vm_id IS NULL THEN a.title || ' guest configuration extension not installed.' + WHEN NOT string_to_array(a.identity ->> 'type', ', ') @> ARRAY['UserAssigned'] THEN a.title || ' does not have user assigned managed identity.' + WHEN string_to_array(a.identity ->> 'type', ', ') @> ARRAY['UserAssigned', 'SystemAssigned'] THEN a.title || ' guest configuration extension installed with user and system assigned managed identity.' + ELSE a.title || ' guest configuration extension not installed with user and system assigned managed identity.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN + gc_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: @@ -17,5 +53,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Add system-assigned managed identity to enable Guest Configuration assignments on VMs with a user-assigned identity \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_image_builder_uses_private_link.yaml b/compliance/controls/azure/azure_compute_vm_image_builder_uses_private_link.yaml old mode 100755 new mode 100644 index 58b9c8291..ecfc38e0f --- a/compliance/controls/azure/azure_compute_vm_image_builder_uses_private_link.yaml +++ b/compliance/controls/azure/azure_compute_vm_image_builder_uses_private_link.yaml @@ -1,24 +1,24 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your VM Image Builder building resources, data leakage risks are reduced. ID: azure_compute_vm_image_builder_uses_private_link -Title: "VM Image Builder templates should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your VM Image Builder building resources, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: VM Image Builder templates should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_jit_access_protected.yaml b/compliance/controls/azure/azure_compute_vm_jit_access_protected.yaml old mode 100755 new mode 100644 index b32943d83..1777d0339 --- a/compliance/controls/azure/azure_compute_vm_jit_access_protected.yaml +++ b/compliance/controls/azure/azure_compute_vm_jit_access_protected.yaml @@ -1,15 +1,51 @@ +Description: Possible network Just In Time (JIT) access will be monitored by Azure Security Center as recommendations ID: azure_compute_vm_jit_access_protected -Title: "Management ports of virtual machines should be protected with just-in-time network access control" -Description: "Possible network Just In Time (JIT) access will be monitored by Azure Security Center as recommendations" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with compute as (\n select\n vm.id as resource,\n 'alarm' as status,\n vm.name || ' not JIT protected.' as reason,\n vm.resource_group,\n sub.display_name as subscription\n from\n azure_compute_virtual_machine as vm,\n azure_subscription sub\n where\n vm.subscription_id = sub.subscription_id\n)\nselect\n distinct vm.vm_id as resource,\n vm.og_account_id as og_account_id,\n vm.og_resource_id as og_resource_id,\n case\n when lower(vm.id) = lower(vms ->> 'id') then 'ok'\n else 'alarm'\n end as status,\n case\n when lower(vms ->> 'id') = lower(vm.id) then vm.name || ' JIT protected.'\n else vm.name || ' not JIT protected.'\n end as reason\n \n , vm.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as vm,\n azure_security_center_jit_network_access_policy as jit,\n jsonb_array_elements(virtual_machines) as vms,\n azure_subscription as sub\n left join compute on true\nwhere\n jit.subscription_id = sub.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_security_center_jit_network_access_policy - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH compute AS ( + SELECT + vm.id AS resource, + 'alarm' AS status, + vm.name || ' not JIT protected.' AS reason, + vm.resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription sub + WHERE + vm.subscription_id = sub.subscription_id + ) + SELECT + DISTINCT vm.vm_id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(vm.id) = LOWER(vms ->> 'id') THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN LOWER(vms ->> 'id') = LOWER(vm.id) THEN vm.name || ' JIT protected.' + ELSE vm.name || ' not JIT protected.' + END AS reason, + vm.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_security_center_jit_network_access_policy AS jit, + jsonb_array_elements(virtual_machines) AS vms, + azure_subscription AS sub + LEFT JOIN compute ON TRUE + WHERE + jit.subscription_id = sub.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -18,5 +54,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Management ports of virtual machines should be protected with just-in-time network access control \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_log_analytics_agent_installed.yaml b/compliance/controls/azure/azure_compute_vm_log_analytics_agent_installed.yaml old mode 100755 new mode 100644 index cb3fe4457..212780985 --- a/compliance/controls/azure/azure_compute_vm_log_analytics_agent_installed.yaml +++ b/compliance/controls/azure/azure_compute_vm_log_analytics_agent_installed.yaml @@ -1,14 +1,47 @@ +Description: This policy audits any Windows/Linux virtual machines if the Log Analytics extension is not installed. ID: azure_compute_vm_log_analytics_agent_installed -Title: "Log Analytics agent should be installed on your virtual machine for Azure Security Center monitoring" -Description: "This policy audits any Windows/Linux virtual machines if the Log Analytics extension is not installed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with agent_installed_vm as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.EnterpriseCloud.Monitoring'\n and b ->> 'ExtensionType' = any(ARRAY ['MicrosoftMonitoringAgent', 'OmsAgentForLinux'])\n and b ->> 'ProvisioningState' = 'Succeeded'\n and b -> 'Settings' ->> 'workspaceId' is not null\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.vm_id is not null then a.title || ' have log analytics agent installed.'\n else a.title || ' log analytics agent not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH agent_installed_vm AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.EnterpriseCloud.Monitoring' + AND b ->> 'ExtensionType' = ANY(ARRAY ['MicrosoftMonitoringAgent', 'OmsAgentForLinux']) + AND b ->> 'ProvisioningState' = 'Succeeded' + AND b -> 'Settings' ->> 'workspaceId' IS NOT NULL + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.vm_id IS NOT NULL THEN a.title || ' have log analytics agent installed.' + ELSE a.title || ' log analytics agent not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +50,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Log Analytics agent should be installed on your virtual machine for Azure Security Center monitoring \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_log_analytics_agent_installed_windows.yaml b/compliance/controls/azure/azure_compute_vm_log_analytics_agent_installed_windows.yaml old mode 100755 new mode 100644 index b772885bd..09e8d8d6c --- a/compliance/controls/azure/azure_compute_vm_log_analytics_agent_installed_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_log_analytics_agent_installed_windows.yaml @@ -1,19 +1,53 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the agent is not installed, or if it is installed but the COM object AgentConfigManager.MgmtSvcCfg returns that it is registered to a workspace other than the ID specified in the policy parameter. ID: azure_compute_vm_log_analytics_agent_installed_windows -Title: "Audit Windows machines on which the Log Analytics agent is not connected as expected" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the agent is not installed, or if it is installed but the COM object AgentConfigManager.MgmtSvcCfg returns that it is registered to a workspace other than the ID specified in the policy parameter." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with agent_installed_vm as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.EnterpriseCloud.Monitoring'\n and b ->> 'ExtensionType' = any(ARRAY ['MicrosoftMonitoringAgent', 'OmsAgentForLinux'])\n and b ->> 'ProvisioningState' = 'Succeeded'\n and b -> 'Settings' ->> 'workspaceId' is not null\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating syetem.'\n when b.vm_id is not null then a.title || ' have log analytics agent installed.'\n else a.title || ' log analytics agent not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH agent_installed_vm AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.EnterpriseCloud.Monitoring' + AND b ->> 'ExtensionType' = ANY(ARRAY ['MicrosoftMonitoringAgent', 'OmsAgentForLinux']) + AND b ->> 'ProvisioningState' = 'Succeeded' + AND b -> 'Settings' ->> 'workspaceId' IS NOT NULL + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' have log analytics agent installed.' + ELSE a.title || ' log analytics agent not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: high Tags: hipaa_hitrust_v92: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Audit Windows machines on which the Log Analytics agent is not connected as expected \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_malware_agent_automatic_upgrade_enabled.yaml b/compliance/controls/azure/azure_compute_vm_malware_agent_automatic_upgrade_enabled.yaml old mode 100755 new mode 100644 index 2136216b7..13fcfb8c5 --- a/compliance/controls/azure/azure_compute_vm_malware_agent_automatic_upgrade_enabled.yaml +++ b/compliance/controls/azure/azure_compute_vm_malware_agent_automatic_upgrade_enabled.yaml @@ -1,19 +1,52 @@ +Description: This policy audits any Windows virtual machine not configured with automatic update of Microsoft Antimalware protection signatures. ID: azure_compute_vm_malware_agent_automatic_upgrade_enabled -Title: "Microsoft Antimalware for Azure should be configured to automatically update protection signatures" -Description: "This policy audits any Windows virtual machine not configured with automatic update of Microsoft Antimalware protection signatures." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with malware_agent_installed_vm as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.Azure.Security'\n and b ->> 'ExtensionType' = 'IaaSAntimalware'\n and b ->> 'AutoUpgradeMinorVersion' = 'true'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating syetem.'\n when b.vm_id is not null then a.title || ' automatic update of Microsoft Antimalware protection signatures enabled.'\n else a.title || ' automatic update of Microsoft Antimalware protection signatures not enabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join malware_agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH malware_agent_installed_vm AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.Azure.Security' + AND b ->> 'ExtensionType' = 'IaaSAntimalware' + AND b ->> 'AutoUpgradeMinorVersion' = 'true' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating syetem.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' automatic update of Microsoft Antimalware protection signatures enabled.' + ELSE a.title || ' automatic update of Microsoft Antimalware protection signatures not enabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN malware_agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Microsoft Antimalware for Azure should be configured to automatically update protection signatures \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_malware_agent_installed.yaml b/compliance/controls/azure/azure_compute_vm_malware_agent_installed.yaml old mode 100755 new mode 100644 index 35604288d..6b2ddc06e --- a/compliance/controls/azure/azure_compute_vm_malware_agent_installed.yaml +++ b/compliance/controls/azure/azure_compute_vm_malware_agent_installed.yaml @@ -1,19 +1,49 @@ +Description: This policy deploys a Microsoft IaaSAntimalware extension with a default configuration when a VM is not configured with the antimalware extension. ID: azure_compute_vm_malware_agent_installed -Title: "Deploy default Microsoft IaaSAntimalware extension for Windows Server" -Description: "This policy deploys a Microsoft IaaSAntimalware extension with a default configuration when a VM is not configured with the antimalware extension." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with malware_agent_installed_vm as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.Azure.Security'\n and b ->> 'ExtensionType' = 'IaaSAntimalware'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.vm_id is not null then a.title || ' IaaSAntimalware extension installed.'\n else a.title || ' IaaSAntimalware extension not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join malware_agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH malware_agent_installed_vm AS ( + SELECT DISTINCT + a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.Azure.Security' + AND b ->> 'ExtensionType' = 'IaaSAntimalware' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.vm_id IS NOT NULL THEN a.title || ' IaaSAntimalware extension installed.' + ELSE a.title || ' IaaSAntimalware extension not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN malware_agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Deploy default Microsoft IaaSAntimalware extension for Windows Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_max_password_age_70_days_windows.yaml b/compliance/controls/azure/azure_compute_vm_max_password_age_70_days_windows.yaml old mode 100755 new mode 100644 index 5fa1bf4bd..c084a2568 --- a/compliance/controls/azure/azure_compute_vm_max_password_age_70_days_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_max_password_age_70_days_windows.yaml @@ -1,14 +1,47 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines do not have a maximum password age of 70 days. ID: azure_compute_vm_max_password_age_70_days_windows -Title: "Audit Windows machines that do not have a maximum password age of 70 days" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that do not have a maximum password age of 70 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_maximum_password_age as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(guest_configuration_assignments) as b\n where\n b -> 'guestConfiguration' ->> 'name'= 'MaximumPasswordAge'\n and b ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' maximum password age is 70 days.'\n else a.title || ' maximum password age is not 70 days.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join vm_maximum_password_age as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_maximum_password_age AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(guest_configuration_assignments) AS b + WHERE + b -> 'guestConfiguration' ->> 'name' = 'MaximumPasswordAge' + AND b ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' maximum password age is 70 days.' + ELSE a.title || ' maximum password age is not 70 days.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN vm_maximum_password_age AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: @@ -17,5 +50,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Audit Windows machines that do not have a maximum password age of 70 days \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_meet_firewall_properties_windows.yaml b/compliance/controls/azure/azure_compute_vm_meet_firewall_properties_windows.yaml old mode 100755 new mode 100644 index 4b4f3f5d8..c77c87813 --- a/compliance/controls/azure/azure_compute_vm_meet_firewall_properties_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_meet_firewall_properties_windows.yaml @@ -1,24 +1,24 @@ +Description: Windows machines should have the specified Group Policy settings in the category 'Windows Firewall Properties' for firewall state, connections, rule management, and notifications. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope. ID: azure_compute_vm_meet_firewall_properties_windows -Title: "Windows machines should meet requirements for 'Windows Firewall Properties'" -Description: "Windows machines should have the specified Group Policy settings in the category 'Windows Firewall Properties' for firewall state, connections, rule management, and notifications. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Windows machines should meet requirements for 'Windows Firewall Properties' \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_meet_security_baseline_requirements_linux.yaml b/compliance/controls/azure/azure_compute_vm_meet_security_baseline_requirements_linux.yaml old mode 100755 new mode 100644 index 6c041fc42..163ebfa82 --- a/compliance/controls/azure/azure_compute_vm_meet_security_baseline_requirements_linux.yaml +++ b/compliance/controls/azure/azure_compute_vm_meet_security_baseline_requirements_linux.yaml @@ -1,19 +1,54 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the machine is not configured correctly for one of the recommendations in the Azure compute security baseline. ID: azure_compute_vm_meet_security_baseline_requirements_linux -Title: "Linux machines should meet requirements for the Azure compute security baseline" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the machine is not configured correctly for one of the recommendations in the Azure compute security baseline." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with compute_machine as(\n select\n id,\n name,\n subscription_id,\n resource_group\n from\n azure_compute_virtual_machine,\n jsonb_array_elements(guest_configuration_assignments) as e\n where\n e ->> 'name' = 'AzureLinuxBaseline'\n and e ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Linux' then 'skip'\n when m.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Linux' then a.name || ' is of ' || a.os_type || ' operating system.'\n when m.id is not null then a.name || ' meet requirements for azure compute security baseline.'\n else a.name || ' does not meet requirements for azure compute security baseline.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join compute_machine as m on m.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH compute_machine AS ( + SELECT + id, + name, + subscription_id, + resource_group + FROM + azure_compute_virtual_machine, + jsonb_array_elements(guest_configuration_assignments) AS e + WHERE + e ->> 'name' = 'AzureLinuxBaseline' + AND e ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Linux' THEN 'skip' + WHEN m.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Linux' THEN a.name || ' is of ' || a.os_type || ' operating system.' + WHEN m.id IS NOT NULL THEN a.name || ' meet requirements for azure compute security baseline.' + ELSE a.name || ' does not meet requirements for azure compute security baseline.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN compute_machine AS m ON m.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Linux machines should meet requirements for the Azure compute security baseline \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_meet_security_baseline_requirements_windows.yaml b/compliance/controls/azure/azure_compute_vm_meet_security_baseline_requirements_windows.yaml old mode 100755 new mode 100644 index 6e5ccf218..0ea3cc3ba --- a/compliance/controls/azure/azure_compute_vm_meet_security_baseline_requirements_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_meet_security_baseline_requirements_windows.yaml @@ -1,19 +1,54 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the machine is not configured correctly for one of the recommendations in the Azure compute security baseline. ID: azure_compute_vm_meet_security_baseline_requirements_windows -Title: "Windows machines should meet requirements of the Azure compute security baseline" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the machine is not configured correctly for one of the recommendations in the Azure compute security baseline." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with compute_machine as(\n select\n id,\n name,\n subscription_id,\n resource_group\n from\n azure_compute_virtual_machine,\n jsonb_array_elements(guest_configuration_assignments) as e\n where\n e ->> 'name' = 'AzureWindowsBaseline'\n and e ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when m.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.name || ' is of ' || a.os_type || ' operating system.'\n when m.id is not null then a.name || ' meet requirements for azure compute security baseline.'\n else a.name || ' does not meet requirements for azure compute security baseline.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join compute_machine as m on m.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH compute_machine AS ( + SELECT + id, + name, + subscription_id, + resource_group + FROM + azure_compute_virtual_machine, + jsonb_array_elements(guest_configuration_assignments) AS e + WHERE + e ->> 'name' = 'AzureWindowsBaseline' + AND e ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN m.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.name || ' is of ' || a.os_type || ' operating system.' + WHEN m.id IS NOT NULL THEN a.name || ' meet requirements for azure compute security baseline.' + ELSE a.name || ' does not meet requirements for azure compute security baseline.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN compute_machine AS m ON m.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Windows machines should meet requirements of the Azure compute security baseline \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_meet_security_option_audit_requirement_windows.yaml b/compliance/controls/azure/azure_compute_vm_meet_security_option_audit_requirement_windows.yaml old mode 100755 new mode 100644 index 138c887a6..e062dc540 --- a/compliance/controls/azure/azure_compute_vm_meet_security_option_audit_requirement_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_meet_security_option_audit_requirement_windows.yaml @@ -1,24 +1,24 @@ +Description: Windows machines should have the specified Group Policy settings in the category 'Security Options - Audit' for forcing audit policy subcategory and shutting down if unable to log security audits. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope. ID: azure_compute_vm_meet_security_option_audit_requirement_windows -Title: "Windows machines should meet requirements for 'Security Options - Audit'" -Description: "Windows machines should have the specified Group Policy settings in the category 'Security Options - Audit' for forcing audit policy subcategory and shutting down if unable to log security audits. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Windows machines should meet requirements for 'Security Options - Audit' \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_meet_security_option_requirement_windows.yaml b/compliance/controls/azure/azure_compute_vm_meet_security_option_requirement_windows.yaml old mode 100755 new mode 100644 index d831e0856..7cd895729 --- a/compliance/controls/azure/azure_compute_vm_meet_security_option_requirement_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_meet_security_option_requirement_windows.yaml @@ -1,24 +1,24 @@ +Description: Windows machines should have the specified Group Policy settings in the category 'Security Options - Accounts' for limiting local account use of blank passwords and guest account status. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope. ID: azure_compute_vm_meet_security_option_requirement_windows -Title: "Windows machines should meet requirements for 'Security Options - Accounts'" -Description: "Windows machines should have the specified Group Policy settings in the category 'Security Options - Accounts' for limiting local account use of blank passwords and guest account status. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Windows machines should meet requirements for 'Security Options - Accounts' \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_meet_security_options_network_access_requirement_windows.yaml b/compliance/controls/azure/azure_compute_vm_meet_security_options_network_access_requirement_windows.yaml old mode 100755 new mode 100644 index 35642dca7..7f1232dd2 --- a/compliance/controls/azure/azure_compute_vm_meet_security_options_network_access_requirement_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_meet_security_options_network_access_requirement_windows.yaml @@ -1,24 +1,24 @@ +Description: Windows machines should have the specified Group Policy settings in the category 'Security Options - Network Access' for including access for anonymous users, local accounts, and remote access to the registry. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. ID: azure_compute_vm_meet_security_options_network_access_requirement_windows -Title: "Windows machines should meet requirements for 'Security Options - Network Access'" -Description: "Windows machines should have the specified Group Policy settings in the category 'Security Options - Network Access' for including access for anonymous users, local accounts, and remote access to the registry. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Windows machines should meet requirements for 'Security Options - Network Access' \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_meet_security_options_requirement_windows.yaml b/compliance/controls/azure/azure_compute_vm_meet_security_options_requirement_windows.yaml old mode 100755 new mode 100644 index 5aca3551d..b3a9046db --- a/compliance/controls/azure/azure_compute_vm_meet_security_options_requirement_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_meet_security_options_requirement_windows.yaml @@ -1,24 +1,24 @@ +Description: Windows machines should have the specified Group Policy settings in the category 'Security Options - Recovery console' for allowing floppy copy and access to all drives and folders. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope. ID: azure_compute_vm_meet_security_options_requirement_windows -Title: "Windows machines should meet requirements for 'Security Options - Recovery console'" -Description: "Windows machines should have the specified Group Policy settings in the category 'Security Options - Recovery console' for allowing floppy copy and access to all drives and folders. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Windows machines should meet requirements for 'Security Options - Recovery console' \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_meet_security_options_user_account_control_requirement_windows.yaml b/compliance/controls/azure/azure_compute_vm_meet_security_options_user_account_control_requirement_windows.yaml old mode 100755 new mode 100644 index a0752f727..f1d316c2b --- a/compliance/controls/azure/azure_compute_vm_meet_security_options_user_account_control_requirement_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_meet_security_options_user_account_control_requirement_windows.yaml @@ -1,24 +1,24 @@ +Description: Windows machines should have the specified Group Policy settings in the category 'Security Options - User Account Control' for mode for admins, behavior of elevation prompt, and virtualizing file and registry write failures. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol. ID: azure_compute_vm_meet_security_options_user_account_control_requirement_windows -Title: "Windows machines should meet requirements for 'Security Options - User Account Control'" -Description: "Windows machines should have the specified Group Policy settings in the category 'Security Options - User Account Control' for mode for admins, behavior of elevation prompt, and virtualizing file and registry write failures. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope. For details, visit https://aka.ms/gcpol." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Windows machines should meet requirements for 'Security Options - User Account Control' \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_meet_system_audit_policies_requirement_windows.yaml b/compliance/controls/azure/azure_compute_vm_meet_system_audit_policies_requirement_windows.yaml old mode 100755 new mode 100644 index a5f600153..c496bea82 --- a/compliance/controls/azure/azure_compute_vm_meet_system_audit_policies_requirement_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_meet_system_audit_policies_requirement_windows.yaml @@ -1,24 +1,24 @@ +Description: Windows machines should have the specified Group Policy settings in the category 'System Audit Policies - Detailed Tracking' for auditing DPAPI, process creation/termination, RPC events, and PNP activity. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope. ID: azure_compute_vm_meet_system_audit_policies_requirement_windows -Title: "Windows machines should meet requirements for 'System Audit Policies - Detailed Tracking'" -Description: "Windows machines should have the specified Group Policy settings in the category 'System Audit Policies - Detailed Tracking' for auditing DPAPI, process creation/termination, RPC events, and PNP activity. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Windows machines should meet requirements for 'System Audit Policies - Detailed Tracking' \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_min_password_age_1_day_windows.yaml b/compliance/controls/azure/azure_compute_vm_min_password_age_1_day_windows.yaml old mode 100755 new mode 100644 index 17db21e80..d0eca4503 --- a/compliance/controls/azure/azure_compute_vm_min_password_age_1_day_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_min_password_age_1_day_windows.yaml @@ -1,19 +1,51 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that do not have a minimum password age of 1 day. ID: azure_compute_vm_min_password_age_1_day_windows -Title: "Audit Windows machines that do not have a minimum password age of 1 day" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that do not have a minimum password age of 1 day." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_min_password_age as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(guest_configuration_assignments) as b\n where\n b -> 'guestConfiguration' ->> 'name'= 'MinimumPasswordAge'\n and b ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' minimum password age is 1 day.'\n else a.title || ' minimum password age is not 1 day.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join vm_min_password_age as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_min_password_age AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(guest_configuration_assignments) AS b + WHERE + b -> 'guestConfiguration' ->> 'name' = 'MinimumPasswordAge' + AND b ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' minimum password age is 1 day.' + ELSE a.title || ' minimum password age is not 1 day.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN vm_min_password_age AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Audit Windows machines that do not have a minimum password age of 1 day \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_min_password_length_14_windows.yaml b/compliance/controls/azure/azure_compute_vm_min_password_length_14_windows.yaml old mode 100755 new mode 100644 index 08b3dd561..095fd6028 --- a/compliance/controls/azure/azure_compute_vm_min_password_length_14_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_min_password_length_14_windows.yaml @@ -1,14 +1,47 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that do not restrict the minimum password length to 14 characters. ID: azure_compute_vm_min_password_length_14_windows -Title: "Audit Windows machines that do not restrict the minimum password length to 14 characters" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that do not restrict the minimum password length to 14 characters." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_min_password_age as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(guest_configuration_assignments) as b\n where\n b -> 'guestConfiguration' ->> 'name'= 'MinimumPasswordLength'\n and b ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' minimum password length is 14 characters.'\n else a.title || ' minimum password length is not 14 characters.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join vm_min_password_age as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_min_password_age AS ( + SELECT DISTINCT + a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(guest_configuration_assignments) AS b + WHERE + b -> 'guestConfiguration' ->> 'name' = 'MinimumPasswordLength' + AND b ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' minimum password length is 14 characters.' + ELSE a.title || ' minimum password length is not 14 characters.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN vm_min_password_age AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: @@ -17,5 +50,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Audit Windows machines that do not restrict the minimum password length to 14 characters \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_monitor_missing_endpoint_protection_in_asc.yaml b/compliance/controls/azure/azure_compute_vm_monitor_missing_endpoint_protection_in_asc.yaml old mode 100755 new mode 100644 index ade36adc1..67a7bfbe7 --- a/compliance/controls/azure/azure_compute_vm_monitor_missing_endpoint_protection_in_asc.yaml +++ b/compliance/controls/azure/azure_compute_vm_monitor_missing_endpoint_protection_in_asc.yaml @@ -1,24 +1,24 @@ +Description: Servers without an installed Endpoint Protection agent will be monitored by Azure Security Center as recommendations. ID: azure_compute_vm_monitor_missing_endpoint_protection_in_asc -Title: "Monitor missing Endpoint Protection in Azure Security Center" -Description: "Servers without an installed Endpoint Protection agent will be monitored by Azure Security Center as recommendations." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Monitor missing Endpoint Protection in Azure Security Center \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_network_traffic_data_collection_linux_agent_installed.yaml b/compliance/controls/azure/azure_compute_vm_network_traffic_data_collection_linux_agent_installed.yaml old mode 100755 new mode 100644 index 83592f41f..eaf9dfd56 --- a/compliance/controls/azure/azure_compute_vm_network_traffic_data_collection_linux_agent_installed.yaml +++ b/compliance/controls/azure/azure_compute_vm_network_traffic_data_collection_linux_agent_installed.yaml @@ -1,14 +1,48 @@ +Description: Security Center uses the Microsoft Dependency agent to collect network traffic data from your Azure virtual machines to enable advanced network protection features such as traffic visualization on the network map, network hardening recommendations and specific network threats. ID: azure_compute_vm_network_traffic_data_collection_linux_agent_installed -Title: "Network traffic data collection agent should be installed on Linux virtual machines" -Description: "Security Center uses the Microsoft Dependency agent to collect network traffic data from your Azure virtual machines to enable advanced network protection features such as traffic visualization on the network map, network hardening recommendations and specific network threats." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with agent_installed_vm as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'ExtensionType' = 'DependencyAgentLinux'\n and b ->> 'Publisher' = 'Microsoft.Azure.Monitoring.DependencyAgent'\n and b ->> 'ProvisioningState' = 'Succeeded'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Linux' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Linux' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' have data collection agent installed.'\n else a.title || ' data collection agent not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH agent_installed_vm AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'ExtensionType' = 'DependencyAgentLinux' + AND b ->> 'Publisher' = 'Microsoft.Azure.Monitoring.DependencyAgent' + AND b ->> 'ProvisioningState' = 'Succeeded' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Linux' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Linux' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' have data collection agent installed.' + ELSE a.title || ' data collection agent not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +51,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Network traffic data collection agent should be installed on Linux virtual machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_network_traffic_data_collection_windows_agent_installed.yaml b/compliance/controls/azure/azure_compute_vm_network_traffic_data_collection_windows_agent_installed.yaml old mode 100755 new mode 100644 index 97c00d715..848b6b695 --- a/compliance/controls/azure/azure_compute_vm_network_traffic_data_collection_windows_agent_installed.yaml +++ b/compliance/controls/azure/azure_compute_vm_network_traffic_data_collection_windows_agent_installed.yaml @@ -1,14 +1,48 @@ +Description: Security Center uses the Microsoft Dependency agent to collect network traffic data from your Azure virtual machines to enable advanced network protection features such as traffic visualization on the network map, network hardening recommendations and specific network threats. ID: azure_compute_vm_network_traffic_data_collection_windows_agent_installed -Title: "Network traffic data collection agent should be installed on Windows virtual machines" -Description: "Security Center uses the Microsoft Dependency agent to collect network traffic data from your Azure virtual machines to enable advanced network protection features such as traffic visualization on the network map, network hardening recommendations and specific network threats." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with agent_installed_vm as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'ExtensionType' = 'DependencyAgentWindows'\n and b ->> 'Publisher' = 'Microsoft.Azure.Monitoring.DependencyAgent'\n and b ->> 'ProvisioningState' = 'Succeeded'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' have data collection agent installed.'\n else a.title || ' data collection agent not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH agent_installed_vm AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'ExtensionType' = 'DependencyAgentWindows' + AND b ->> 'Publisher' = 'Microsoft.Azure.Monitoring.DependencyAgent' + AND b ->> 'ProvisioningState' = 'Succeeded' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' have data collection agent installed.' + ELSE a.title || ' data collection agent not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +51,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Network traffic data collection agent should be installed on Windows virtual machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_non_internet_facing_protected_with_nsg.yaml b/compliance/controls/azure/azure_compute_vm_non_internet_facing_protected_with_nsg.yaml old mode 100755 new mode 100644 index 58205da9c..384872326 --- a/compliance/controls/azure/azure_compute_vm_non_internet_facing_protected_with_nsg.yaml +++ b/compliance/controls/azure/azure_compute_vm_non_internet_facing_protected_with_nsg.yaml @@ -1,24 +1,24 @@ +Description: Protect your non-internet-facing virtual machines from potential threats by restricting access with network security groups (NSG). ID: azure_compute_vm_non_internet_facing_protected_with_nsg -Title: "Non-internet-facing virtual machines should be protected with network security groups" -Description: "Protect your non-internet-facing virtual machines from potential threats by restricting access with network security groups (NSG)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Non-internet-facing virtual machines should be protected with network security groups \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_password_complexity_setting_enabled_windows.yaml b/compliance/controls/azure/azure_compute_vm_password_complexity_setting_enabled_windows.yaml old mode 100755 new mode 100644 index b12e23fb9..150f882eb --- a/compliance/controls/azure/azure_compute_vm_password_complexity_setting_enabled_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_password_complexity_setting_enabled_windows.yaml @@ -1,19 +1,51 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that do not have the password complexity setting enabled. ID: azure_compute_vm_password_complexity_setting_enabled_windows -Title: "Audit Windows machines that do not have the password complexity setting enabled" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that do not have the password complexity setting enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_password_complexity_setting as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(guest_configuration_assignments) as b\n where\n b -> 'guestConfiguration' ->> 'name'= 'PasswordMustMeetComplexityRequirements'\n and b ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' password complexity setting enabled.'\n else a.title || ' password complexity setting disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join vm_password_complexity_setting as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_password_complexity_setting AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(guest_configuration_assignments) AS b + WHERE + b -> 'guestConfiguration' ->> 'name' = 'PasswordMustMeetComplexityRequirements' + AND b ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' password complexity setting enabled.' + ELSE a.title || ' password complexity setting disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN vm_password_complexity_setting AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Audit Windows machines that do not have the password complexity setting enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_password_file_permissions_0644_linux.yaml b/compliance/controls/azure/azure_compute_vm_password_file_permissions_0644_linux.yaml old mode 100755 new mode 100644 index 6f3a7e5b3..676777a39 --- a/compliance/controls/azure/azure_compute_vm_password_file_permissions_0644_linux.yaml +++ b/compliance/controls/azure/azure_compute_vm_password_file_permissions_0644_linux.yaml @@ -1,24 +1,24 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Linux machines that do not have the passwd file permissions set to 0644 ID: azure_compute_vm_password_file_permissions_0644_linux -Title: "Audit Linux machines that do not have the passwd file permissions set to 0644" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Linux machines that do not have the passwd file permissions set to 0644" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Audit Linux machines that do not have the passwd file permissions set to 0644 \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_passwords_stored_using_reversible_encryption_windows.yaml b/compliance/controls/azure/azure_compute_vm_passwords_stored_using_reversible_encryption_windows.yaml old mode 100755 new mode 100644 index 9bb360b1a..19673331c --- a/compliance/controls/azure/azure_compute_vm_passwords_stored_using_reversible_encryption_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_passwords_stored_using_reversible_encryption_windows.yaml @@ -1,19 +1,51 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that do not store passwords using reversible encryption. ID: azure_compute_vm_passwords_stored_using_reversible_encryption_windows -Title: "Audit Windows machines that do not store passwords using reversible encryption" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that do not store passwords using reversible encryption." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_password_reversible_encryption as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(guest_configuration_assignments) as b\n where\n b -> 'guestConfiguration' ->> 'name'= 'StorePasswordsUsingReversibleEncryption'\n and b ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' store passwords using reversible encryption.'\n else a.title || ' not store passwords using reversible encryption'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join vm_password_reversible_encryption as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_password_reversible_encryption AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(guest_configuration_assignments) AS b + WHERE + b -> 'guestConfiguration' ->> 'name' = 'StorePasswordsUsingReversibleEncryption' + AND b ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' store passwords using reversible encryption.' + ELSE a.title || ' not store passwords using reversible encryption' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN vm_password_reversible_encryption AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Audit Windows machines that do not store passwords using reversible encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_remote_access_restricted_all_ports.yaml b/compliance/controls/azure/azure_compute_vm_remote_access_restricted_all_ports.yaml old mode 100755 new mode 100644 index cc5520b28..3c2b2c1e3 --- a/compliance/controls/azure/azure_compute_vm_remote_access_restricted_all_ports.yaml +++ b/compliance/controls/azure/azure_compute_vm_remote_access_restricted_all_ports.yaml @@ -1,15 +1,49 @@ +Description: Azure Security Center has identified some of your network security groups' inbound rules to be too permissive. Inbound rules should not allow access from 'Any' or 'Internet' ranges. This can potentially enable attackers to target your resources. ID: azure_compute_vm_remote_access_restricted_all_ports -Title: "All network ports should be restricted on network security groups associated to your virtual machine" -Description: "Azure Security Center has identified some of your network security groups' inbound rules to be too permissive. Inbound rules should not allow access from 'Any' or 'Internet' ranges. This can potentially enable attackers to target your resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with network_sg as (\n select\n distinct name as sg_name,\n network_interfaces\n from\n azure_network_security_group as nsg,\n jsonb_array_elements(security_rules) as sg,\n jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) as dport,\n jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) as sip\n where\n sg -> 'properties' ->> 'access' = 'Allow'\n and sg -> 'properties' ->> 'direction' = 'Inbound'\n and sg -> 'properties' ->> 'protocol' in ('TCP','*')\n and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', '/0', '/0')\n)\nselect\n vm.vm_id as resource,\n vm.og_account_id as og_account_id,\n vm.og_resource_id as og_resource_id,\n case\n when sg.sg_name is null then 'ok'\n else 'alarm'\n end as status,\n case\n when sg.sg_name is null then vm.title || ' restricts remote access from internet.'\n else vm.title || ' allows remote access from internet.'\n end as reason\n \n , vm.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as vm\n left join network_sg as sg on sg.network_interfaces @> vm.network_interfaces\n join azure_subscription as sub on sub.subscription_id = vm.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name AS sg_name, + network_interfaces + FROM + azure_network_security_group AS nsg, + jsonb_array_elements(security_rules) AS sg, + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange')::jsonb) AS dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) AS sip + WHERE + sg -> 'properties' ->> 'access' = 'Allow' + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' IN ('TCP', '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', '/0', '/0') + ) + SELECT + vm.vm_id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN sg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sg.sg_name IS NULL THEN vm.title || ' restricts remote access from internet.' + ELSE vm.title || ' allows remote access from internet.' + END AS reason, + vm.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN network_sg AS sg ON sg.network_interfaces @> vm.network_interfaces + JOIN azure_subscription AS sub ON sub.subscription_id = vm.subscription_id; Severity: high Tags: hipaa_hitrust_v92: @@ -20,5 +54,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: All network ports should be restricted on network security groups associated to your virtual machine \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_restrict_previous_24_passwords_resuse_windows.yaml b/compliance/controls/azure/azure_compute_vm_restrict_previous_24_passwords_resuse_windows.yaml old mode 100755 new mode 100644 index 3a483cb28..488bd2677 --- a/compliance/controls/azure/azure_compute_vm_restrict_previous_24_passwords_resuse_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_restrict_previous_24_passwords_resuse_windows.yaml @@ -1,14 +1,48 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that allow re-use of the previous 24 passwords. ID: azure_compute_vm_restrict_previous_24_passwords_resuse_windows -Title: "Audit Windows machines that allow re-use of the previous 24 passwords" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Windows machines that allow re-use of the previous 24 passwords." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_enforce_password_history as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(guest_configuration_assignments) as b\n where\n b -> 'guestConfiguration' ->> 'name'= 'EnforcePasswordHistory'\n and b ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' enforce password history.'\n else a.title || ' doest not enforce password history.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join vm_enforce_password_history as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_enforce_password_history AS ( + SELECT DISTINCT + a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(guest_configuration_assignments) AS b + WHERE + b -> 'guestConfiguration' ->> 'name' = 'EnforcePasswordHistory' + AND + b ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' enforce password history.' + ELSE a.title || ' does not enforce password history.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN vm_enforce_password_history AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: @@ -17,5 +51,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Audit Windows machines that allow re-use of the previous 24 passwords \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_restrict_remote_connection_from_accounts_without_password_linux.yaml b/compliance/controls/azure/azure_compute_vm_restrict_remote_connection_from_accounts_without_password_linux.yaml old mode 100755 new mode 100644 index f362ad403..18557569a --- a/compliance/controls/azure/azure_compute_vm_restrict_remote_connection_from_accounts_without_password_linux.yaml +++ b/compliance/controls/azure/azure_compute_vm_restrict_remote_connection_from_accounts_without_password_linux.yaml @@ -1,19 +1,54 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Linux machines that allow remote connections from accounts without passwords. ID: azure_compute_vm_restrict_remote_connection_from_accounts_without_password_linux -Title: "Audit Linux machines that allow remote connections from accounts without passwords" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if Linux machines that allow remote connections from accounts without passwords." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with compute_machine as(\n select\n id,\n name,\n subscription_id,\n resource_group\n from\n azure_compute_virtual_machine,\n jsonb_array_elements(guest_configuration_assignments) as e\n where\n e ->> 'name' = 'PasswordPolicy_msid110'\n and e ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Linux' then 'skip'\n when m.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Linux' then a.name || ' is of ' || a.os_type || ' operating system.'\n when m.id is not null then a.name || ' restrict remote connections from accounts without passwords.'\n else a.name || ' allows remote connections from accounts without passwords.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join compute_machine as m on m.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH compute_machine AS ( + SELECT + id, + name, + subscription_id, + resource_group + FROM + azure_compute_virtual_machine, + jsonb_array_elements(guest_configuration_assignments) AS e + WHERE + e ->> 'name' = 'PasswordPolicy_msid110' + AND e ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Linux' THEN 'skip' + WHEN m.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Linux' THEN a.name || ' is of ' || a.os_type || ' operating system.' + WHEN m.id IS NOT NULL THEN a.name || ' restrict remote connections from accounts without passwords.' + ELSE a.name || ' allows remote connections from accounts without passwords.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN compute_machine AS m ON m.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Audit Linux machines that allow remote connections from accounts without passwords \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_scale_set_automatic_upgrade_enabled.yaml b/compliance/controls/azure/azure_compute_vm_scale_set_automatic_upgrade_enabled.yaml old mode 100755 new mode 100644 index 8905de861..200a10b77 --- a/compliance/controls/azure/azure_compute_vm_scale_set_automatic_upgrade_enabled.yaml +++ b/compliance/controls/azure/azure_compute_vm_scale_set_automatic_upgrade_enabled.yaml @@ -1,34 +1,34 @@ +Description: This control checks whether virtual machine scale sets have automatic OS image patching enabled. ID: azure_compute_vm_scale_set_automatic_upgrade_enabled -Title: "Compute virtual machine scale sets should have automatic OS image patching enabled" -Description: "This control checks whether virtual machine scale sets have automatic OS image patching enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when upgrade_policy is null then 'skip' - when upgrade_policy ->> 'mode' = 'Automatic' then 'ok' - else 'alarm' - end as status, - case - when upgrade_policy is null then a.title || ' upgrade policy not applicable.' - when upgrade_policy ->> 'mode' = 'Automatic' then a.title || ' automatic update enabled.' - else a.title || ' automatic update disabled.' - end as reason - from - azure_compute_virtual_machine_scale_set as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_compute_virtual_machine_scale_set ListOfTables: - azure_compute_virtual_machine_scale_set - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN upgrade_policy IS NULL THEN 'skip' + WHEN upgrade_policy ->> 'mode' = 'Automatic' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN upgrade_policy IS NULL THEN a.title || ' upgrade policy not applicable.' + WHEN upgrade_policy ->> 'mode' = 'Automatic' THEN a.title || ' automatic update enabled.' + ELSE a.title || ' automatic update disabled.' + END AS reason + FROM + azure_compute_virtual_machine_scale_set AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Compute virtual machine scale sets should have automatic OS image patching enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_scale_set_boot_diagnostics_enabled.yaml b/compliance/controls/azure/azure_compute_vm_scale_set_boot_diagnostics_enabled.yaml old mode 100755 new mode 100644 index 491828299..42d3e8ebb --- a/compliance/controls/azure/azure_compute_vm_scale_set_boot_diagnostics_enabled.yaml +++ b/compliance/controls/azure/azure_compute_vm_scale_set_boot_diagnostics_enabled.yaml @@ -1,32 +1,32 @@ +Description: This policy identifies Azure Virtual Machines scale sets which has Boot Diagnostics setting Disabled. Boot Diagnostics when enabled for virtual machine, captures Screenshot and Console Output during virtual machine startup. This would help in troubleshooting virtual machine when it enters a non-bootable state. ID: azure_compute_vm_scale_set_boot_diagnostics_enabled -Title: "Virtual Machine scale sets boot diagnostics should be enabled" -Description: "This policy identifies Azure Virtual Machines scale sets which has Boot Diagnostics setting Disabled. Boot Diagnostics when enabled for virtual machine, captures Screenshot and Console Output during virtual machine startup. This would help in troubleshooting virtual machine when it enters a non-bootable state." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when (virtual_machine_diagnostics_profile -> 'bootDiagnostics' ->> 'enabled') :: boolean then 'ok' - else 'alarm' - end as status, - case - when (virtual_machine_diagnostics_profile -> 'bootDiagnostics' ->> 'enabled') :: boolean then a.title || ' boot diagnostics enabled.' - else a.title || ' boot diagnostics disabled.' - end as reason - from - azure_compute_virtual_machine_scale_set as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_compute_virtual_machine_scale_set ListOfTables: - azure_compute_virtual_machine_scale_set - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN (virtual_machine_diagnostics_profile -> 'bootDiagnostics' ->> 'enabled') :: boolean THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (virtual_machine_diagnostics_profile -> 'bootDiagnostics' ->> 'enabled') :: boolean THEN a.title || ' boot diagnostics enabled.' + ELSE a.title || ' boot diagnostics disabled.' + END AS reason + FROM + azure_compute_virtual_machine_scale_set AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Virtual Machine scale sets boot diagnostics should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_scale_set_endpoint_protection_solution_installed.yaml b/compliance/controls/azure/azure_compute_vm_scale_set_endpoint_protection_solution_installed.yaml old mode 100755 new mode 100644 index c7fb6e6d0..d3b3aa049 --- a/compliance/controls/azure/azure_compute_vm_scale_set_endpoint_protection_solution_installed.yaml +++ b/compliance/controls/azure/azure_compute_vm_scale_set_endpoint_protection_solution_installed.yaml @@ -1,24 +1,24 @@ +Description: Audit the existence and health of an endpoint protection solution on your virtual machines scale sets, to protect them from threats and vulnerabilities. ID: azure_compute_vm_scale_set_endpoint_protection_solution_installed -Title: "Endpoint protection solution should be installed on virtual machine scale sets" -Description: "Audit the existence and health of an endpoint protection solution on your virtual machines scale sets, to protect them from threats and vulnerabilities." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Endpoint protection solution should be installed on virtual machine scale sets \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_scale_set_log_analytics_agent_installed.yaml b/compliance/controls/azure/azure_compute_vm_scale_set_log_analytics_agent_installed.yaml old mode 100755 new mode 100644 index 20b0bb344..7893a821d --- a/compliance/controls/azure/azure_compute_vm_scale_set_log_analytics_agent_installed.yaml +++ b/compliance/controls/azure/azure_compute_vm_scale_set_log_analytics_agent_installed.yaml @@ -1,19 +1,52 @@ +Description: This policy audits any Windows/Linux Virtual Machine Scale Sets if the Log Analytics extension is not installed. ID: azure_compute_vm_scale_set_log_analytics_agent_installed -Title: "Log Analytics agent should be installed on your virtual machine scale sets for Azure Security Center monitoring" -Description: "This policy audits any Windows/Linux Virtual Machine Scale Sets if the Log Analytics extension is not installed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with agent_installed_vm_scale_set as (\n select\n distinct a.id as vm_id\n from\n azure_compute_virtual_machine_scale_set as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.EnterpriseCloud.Monitoring'\n and b ->> 'ExtensionType' = any(ARRAY ['MicrosoftMonitoringAgent', 'OmsAgentForLinux'])\n and b ->> 'ProvisioningState' = 'Succeeded'\n and b -> 'Settings' ->> 'workspaceId' is not null\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.vm_id is not null then a.title || ' have log analytics agent installed.'\n else a.title || ' log analytics agent not installed.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine_scale_set as a\n left join agent_installed_vm_scale_set as b on a.id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine_scale_set ListOfTables: - azure_compute_virtual_machine_scale_set - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set + QueryToExecute: | + WITH agent_installed_vm_scale_set AS ( + SELECT + DISTINCT a.id AS vm_id + FROM + azure_compute_virtual_machine_scale_set AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.EnterpriseCloud.Monitoring' + AND b ->> 'ExtensionType' = ANY(ARRAY ['MicrosoftMonitoringAgent', 'OmsAgentForLinux']) + AND b ->> 'ProvisioningState' = 'Succeeded' + AND b -> 'Settings' ->> 'workspaceId' IS NOT NULL + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.vm_id IS NOT NULL THEN a.title || ' have log analytics agent installed.' + ELSE a.title || ' log analytics agent not installed.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine_scale_set AS a + LEFT JOIN agent_installed_vm_scale_set AS b + ON a.id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Log Analytics agent should be installed on your virtual machine scale sets for Azure Security Center monitoring \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_scale_set_logging_enabled.yaml b/compliance/controls/azure/azure_compute_vm_scale_set_logging_enabled.yaml old mode 100755 new mode 100644 index a3e44dc55..4f4ec7c6e --- a/compliance/controls/azure/azure_compute_vm_scale_set_logging_enabled.yaml +++ b/compliance/controls/azure/azure_compute_vm_scale_set_logging_enabled.yaml @@ -1,14 +1,48 @@ +Description: It is recommended to enable Logs so that activity trail can be recreated when investigations are required in the event of an incident or a compromise. ID: azure_compute_vm_scale_set_logging_enabled -Title: "Resource logs in Virtual Machine Scale Sets should be enabled" -Description: "It is recommended to enable Logs so that activity trail can be recreated when investigations are required in the event of an incident or a compromise." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with malware_agent_installed_vm as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Microsoft.Azure.Security'\n and b ->> 'ExtensionType' = 'IaaSAntimalware'\n and b ->> 'AutoUpgradeMinorVersion' = 'true'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.title || ' is of ' || a.os_type || ' operating syetem.'\n when b.vm_id is not null then a.title || ' automatic update of Microsoft Antimalware protection signatures enabled.'\n else a.title || ' automatic update of Microsoft Antimalware protection signatures not enabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join malware_agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH malware_agent_installed_vm AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Microsoft.Azure.Security' + AND b ->> 'ExtensionType' = 'IaaSAntimalware' + AND b ->> 'AutoUpgradeMinorVersion' = 'true' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' automatic update of Microsoft Antimalware protection signatures enabled.' + ELSE a.title || ' automatic update of Microsoft Antimalware protection signatures not enabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN malware_agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +51,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Resource logs in Virtual Machine Scale Sets should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_scale_set_security_configuration_vulnerabilities_remediated.yaml b/compliance/controls/azure/azure_compute_vm_scale_set_security_configuration_vulnerabilities_remediated.yaml old mode 100755 new mode 100644 index 634dfcf67..d0f0480a7 --- a/compliance/controls/azure/azure_compute_vm_scale_set_security_configuration_vulnerabilities_remediated.yaml +++ b/compliance/controls/azure/azure_compute_vm_scale_set_security_configuration_vulnerabilities_remediated.yaml @@ -1,24 +1,24 @@ +Description: Audit the OS vulnerabilities on your virtual machine scale sets to protect them from attacks. ID: azure_compute_vm_scale_set_security_configuration_vulnerabilities_remediated -Title: "Vulnerabilities in security configuration on your virtual machine scale sets should be remediated" -Description: "Audit the OS vulnerabilities on your virtual machine scale sets to protect them from attacks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Vulnerabilities in security configuration on your virtual machine scale sets should be remediated \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_scale_set_ssh_key_authentication_linux.yaml b/compliance/controls/azure/azure_compute_vm_scale_set_ssh_key_authentication_linux.yaml old mode 100755 new mode 100644 index 9d2d8f98b..7ecd42411 --- a/compliance/controls/azure/azure_compute_vm_scale_set_ssh_key_authentication_linux.yaml +++ b/compliance/controls/azure/azure_compute_vm_scale_set_ssh_key_authentication_linux.yaml @@ -1,34 +1,34 @@ +Description: This control checks whether virtual machine scale sets have SSH key authentication enabled. This control is only applicable for Linux-type operating systems. ID: azure_compute_vm_scale_set_ssh_key_authentication_linux -Title: "Compute virtual machine scale sets with linux OS should have SSH key authentication enabled" -Description: "This control checks whether virtual machine scale sets have SSH key authentication enabled. This control is only applicable for Linux-type operating systems." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when virtual_machine_storage_profile -> 'osDisk' ->> 'osType' = 'Windows' then 'skip' - when virtual_machine_os_profile -> 'linuxConfiguration' ->> 'disablePasswordAuthentication' = 'true' then 'ok' - else 'alarm' - end as status, - case - when virtual_machine_storage_profile -> 'osDisk' ->> 'osType' = 'Windows' then a.title || ' is using windows OS.' - when virtual_machine_os_profile -> 'linuxConfiguration' ->> 'disablePasswordAuthentication' = 'true' then a.title || ' has SSK key authentication enabled.' - else a.title || ' has password authentication enabled.' - end as reason - from - azure_compute_virtual_machine_scale_set as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_compute_virtual_machine_scale_set ListOfTables: - azure_compute_virtual_machine_scale_set - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN virtual_machine_storage_profile -> 'osDisk' ->> 'osType' = 'Windows' THEN 'skip' + WHEN virtual_machine_os_profile -> 'linuxConfiguration' ->> 'disablePasswordAuthentication' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN virtual_machine_storage_profile -> 'osDisk' ->> 'osType' = 'Windows' THEN a.title || ' is using windows OS.' + WHEN virtual_machine_os_profile -> 'linuxConfiguration' ->> 'disablePasswordAuthentication' = 'true' THEN a.title || ' has SSH key authentication enabled.' + ELSE a.title || ' has password authentication enabled.' + END AS reason + FROM + azure_compute_virtual_machine_scale_set AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Compute virtual machine scale sets with linux OS should have SSH key authentication enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_scale_set_system_updates_installed.yaml b/compliance/controls/azure/azure_compute_vm_scale_set_system_updates_installed.yaml old mode 100755 new mode 100644 index 12b043c8b..7275d5a54 --- a/compliance/controls/azure/azure_compute_vm_scale_set_system_updates_installed.yaml +++ b/compliance/controls/azure/azure_compute_vm_scale_set_system_updates_installed.yaml @@ -1,24 +1,24 @@ +Description: Audit whether there are any missing system security updates and critical updates that should be installed to ensure that your Windows and Linux virtual machine scale sets are secure. ID: azure_compute_vm_scale_set_system_updates_installed -Title: "System updates on virtual machine scale sets should be installed" -Description: "Audit whether there are any missing system security updates and critical updates that should be installed to ensure that your Windows and Linux virtual machine scale sets are secure." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: System updates on virtual machine scale sets should be installed \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_scale_set_uses_managed_disks.yaml b/compliance/controls/azure/azure_compute_vm_scale_set_uses_managed_disks.yaml old mode 100755 new mode 100644 index 1ca5d838f..884dcfddc --- a/compliance/controls/azure/azure_compute_vm_scale_set_uses_managed_disks.yaml +++ b/compliance/controls/azure/azure_compute_vm_scale_set_uses_managed_disks.yaml @@ -1,32 +1,32 @@ +Description: This policy identifies Azure Virtual machine scale sets which are not utilising Managed Disks. Using Azure Managed disk over traditional BLOB storage based VHD's has more advantage features like Managed disks are by default encrypted, reduces cost over storage accounts and more resilient as Microsoft will manage the disk storage and move around if underlying hardware goes faulty. It is recommended to move BLOB based VHD's to Managed Disks. ID: azure_compute_vm_scale_set_uses_managed_disks -Title: "Virtual machine scale sets should use managed disks" -Description: "This policy identifies Azure Virtual machine scale sets which are not utilising Managed Disks. Using Azure Managed disk over traditional BLOB storage based VHD's has more advantage features like Managed disks are by default encrypted, reduces cost over storage accounts and more resilient as Microsoft will manage the disk storage and move around if underlying hardware goes faulty. It is recommended to move BLOB based VHD's to Managed Disks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when virtual_machine_storage_profile -> 'osDisk' -> 'osType' -> 'vhdContainers' != null then 'ok' - else 'alarm' - end as status, - case - when virtual_machine_storage_profile -> 'osDisk' -> 'osType' -> 'vhdContainers' != null then a.title || ' utilising managed disks.' - else a.title || ' not utilising managed disks.' - end as reason - from - azure_compute_virtual_machine_scale_set as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_compute_virtual_machine_scale_set ListOfTables: - azure_compute_virtual_machine_scale_set - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN virtual_machine_storage_profile -> 'osDisk' -> 'osType' -> 'vhdContainers' != NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN virtual_machine_storage_profile -> 'osDisk' -> 'osType' -> 'vhdContainers' != NULL THEN a.title || ' utilising managed disks.' + ELSE a.title || ' not utilising managed disks.' + END AS reason + FROM + azure_compute_virtual_machine_scale_set AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Virtual machine scale sets should use managed disks \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_secure_communication_protocols_configured.yaml b/compliance/controls/azure/azure_compute_vm_secure_communication_protocols_configured.yaml old mode 100755 new mode 100644 index 86f1e6314..6ae8ba4d1 --- a/compliance/controls/azure/azure_compute_vm_secure_communication_protocols_configured.yaml +++ b/compliance/controls/azure/azure_compute_vm_secure_communication_protocols_configured.yaml @@ -1,19 +1,58 @@ +Description: To protect the privacy of information communicated over the Internet, your web servers should use the latest version of the industry-standard cryptographic protocol, Transport Layer Security (TLS). TLS secures communications over a network by using security certificates to encrypt a connection between machines. ID: azure_compute_vm_secure_communication_protocols_configured -Title: "Windows web servers should be configured to use secure communication protocols" -Description: "To protect the privacy of information communicated over the Internet, your web servers should use the latest version of the industry-standard cryptographic protocol, Transport Layer Security (TLS). TLS secures communications over a network by using security certificates to encrypt a connection between machines." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with compute_machine as(\n select\n id,\n name,\n subscription_id,\n resource_group,c\n from\n azure_compute_virtual_machine,\n jsonb_array_elements(guest_configuration_assignments) as e,\n jsonb_array_elements(e -> 'guestConfiguration' -> 'configurationParameter') as c\n where\n e ->> 'name' = 'AuditSecureProtocol'\n and e ->> 'complianceStatus' = 'Compliant'\n and c ->> 'name' = 'MinimumTLSVersion'\n and c ->> 'value' = '1.3'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when m.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.name || ' is of ' || a.os_type || ' operating system.'\n when m.id is not null then a.name || ' configured to use secure communication protocols.'\n else a.name || ' not configured to use secure communication protocols.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join compute_machine as m on m.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH compute_machine AS ( + SELECT + id, + name, + subscription_id, + resource_group, + c + FROM + azure_compute_virtual_machine, + jsonb_array_elements(guest_configuration_assignments) AS e, + jsonb_array_elements(e -> 'guestConfiguration' -> 'configurationParameter') AS c + WHERE + e ->> 'name' = 'AuditSecureProtocol' + AND e ->> 'complianceStatus' = 'Compliant' + AND c ->> 'name' = 'MinimumTLSVersion' + AND c ->> 'value' = '1.3' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN m.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.name || ' is of ' || a.os_type || ' operating system.' + WHEN m.id IS NOT NULL THEN a.name || ' configured to use secure communication protocols.' + ELSE a.name || ' not configured to use secure communication protocols.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN compute_machine AS m ON m.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Windows web servers should be configured to use secure communication protocols \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_security_configuration_vulnerabilities_remediated.yaml b/compliance/controls/azure/azure_compute_vm_security_configuration_vulnerabilities_remediated.yaml old mode 100755 new mode 100644 index bd68e0eff..890d42686 --- a/compliance/controls/azure/azure_compute_vm_security_configuration_vulnerabilities_remediated.yaml +++ b/compliance/controls/azure/azure_compute_vm_security_configuration_vulnerabilities_remediated.yaml @@ -1,24 +1,24 @@ +Description: Servers which do not satisfy the configured baseline will be monitored by Azure Security Center as recommendations. ID: azure_compute_vm_security_configuration_vulnerabilities_remediated -Title: "Vulnerabilities in security configuration on your machines should be remediated" -Description: "Servers which do not satisfy the configured baseline will be monitored by Azure Security Center as recommendations." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Vulnerabilities in security configuration on your machines should be remediated \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_ssh_key_authentication_linux.yaml b/compliance/controls/azure/azure_compute_vm_ssh_key_authentication_linux.yaml old mode 100755 new mode 100644 index afb4d471e..57c99ce89 --- a/compliance/controls/azure/azure_compute_vm_ssh_key_authentication_linux.yaml +++ b/compliance/controls/azure/azure_compute_vm_ssh_key_authentication_linux.yaml @@ -1,19 +1,51 @@ +Description: Although SSH itself provides an encrypted connection, using passwords with SSH still leaves the VM vulnerable to brute-force attacks. The most secure option for authenticating to an Azure Linux virtual machine over SSH is with a public-private key pair, also known as SSH keys. ID: azure_compute_vm_ssh_key_authentication_linux -Title: "Authentication to Linux machines should require SSH keys" -Description: "Although SSH itself provides an encrypted connection, using passwords with SSH still leaves the VM vulnerable to brute-force attacks. The most secure option for authenticating to an Azure Linux virtual machine over SSH is with a public-private key pair, also known as SSH keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_ssh_key_auth as (\n select\n distinct a.vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(guest_configuration_assignments) as b\n where\n b -> 'guestConfiguration' ->> 'name'= 'LinuxNoPasswordForSSH'\n and b ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Linux' then 'skip'\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Linux' then a.title || ' is of ' || a.os_type || ' operating system.'\n when b.vm_id is not null then a.title || ' have SSH keys authentication.'\n else a.title || ' does not have SSH keys authentication.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join vm_ssh_key_auth as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_ssh_key_auth AS ( + SELECT + DISTINCT a.vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(guest_configuration_assignments) AS b + WHERE + b -> 'guestConfiguration' ->> 'name' = 'LinuxNoPasswordForSSH' + AND b ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Linux' THEN 'skip' + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Linux' THEN a.title || ' is of ' || a.os_type || ' operating system.' + WHEN b.vm_id IS NOT NULL THEN a.title || ' have SSH keys authentication.' + ELSE a.title || ' does not have SSH keys authentication.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN vm_ssh_key_auth AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Authentication to Linux machines should require SSH keys \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_system_updates_installed.yaml b/compliance/controls/azure/azure_compute_vm_system_updates_installed.yaml old mode 100755 new mode 100644 index 0ba2f62d3..a071c9a6a --- a/compliance/controls/azure/azure_compute_vm_system_updates_installed.yaml +++ b/compliance/controls/azure/azure_compute_vm_system_updates_installed.yaml @@ -1,14 +1,34 @@ +Description: Missing security system updates on your servers will be monitored by Azure Security Center as recommendations. ID: azure_compute_vm_system_updates_installed -Title: "System updates should be installed on your machines" -Description: "Missing security system updates on your servers will be monitored by Azure Security Center as recommendations." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n vm.vm_id as resource,\n vm.og_account_id as og_account_id,\n vm.og_resource_id as og_resource_id,\n case\n when enable_automatic_updates then 'ok'\n else 'alarm'\n end as status,\n case\n when enable_automatic_updates then vm.title || ' automatic system updates enabled.'\n else vm.title || ' automatic system updates disabled.'\n end as reason\n \n , vm.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as vm,\n azure_subscription as sub\nwhere\n sub.subscription_id = vm.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.vm_id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN enable_automatic_updates THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_automatic_updates THEN vm.title || ' automatic system updates enabled.' + ELSE vm.title || ' automatic system updates disabled.' + END AS reason, + vm.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: high Tags: hipaa_hitrust_v92: @@ -17,5 +37,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: System updates should be installed on your machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_tcp_udp_access_restricted_internet.yaml b/compliance/controls/azure/azure_compute_vm_tcp_udp_access_restricted_internet.yaml old mode 100755 new mode 100644 index 118102e91..86ce4a7d9 --- a/compliance/controls/azure/azure_compute_vm_tcp_udp_access_restricted_internet.yaml +++ b/compliance/controls/azure/azure_compute_vm_tcp_udp_access_restricted_internet.yaml @@ -1,20 +1,74 @@ +Description: Protect your virtual machines from potential threats by restricting access to them with network security groups (NSG). ID: azure_compute_vm_tcp_udp_access_restricted_internet -Title: "Internet-facing virtual machines should be protected with network security groups" -Description: "Protect your virtual machines from potential threats by restricting access to them with network security groups (NSG)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with network_sg as (\n select\n distinct name as sg_name,\n network_interfaces\n from\n azure_network_security_group as nsg,\n jsonb_array_elements(security_rules) as sg,\n jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) as dport,\n jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) as sip\n where\n sg -> 'properties' ->> 'access' = 'Allow'\n and sg -> 'properties' ->> 'direction' = 'Inbound'\n and sg -> 'properties' ->> 'protocol' in ('TCP', 'UDP')\n and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0')\n and (\n dport in ('22', '3389', '*')\n or (\n dport like '%-%'\n and (\n (\n 53 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer\n or 123 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer\n or 161 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer\n or 389 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer\n or 1900 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer\n )\n or (\n split_part(dport, '-', 1) :: integer <= 3389\n and split_part(dport, '-', 2) :: integer >= 3389\n )\n or (\n split_part(dport, '-', 1) :: integer <= 22\n and split_part(dport, '-', 2) :: integer >= 22\n )\n )\n )\n )\n)\nselect\n vm.vm_id as resource,\n vm.og_account_id as og_account_id,\n vm.og_resource_id as og_resource_id,\n case\n when sg.sg_name is null then 'ok'\n else 'alarm'\n end as status,\n case\n when sg.sg_name is null then vm.title || ' restricts remote access from internet.'\n else vm.title || ' allows remote access from internet.'\n end as reason\n \n , vm.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as vm\n left join network_sg as sg on sg.network_interfaces @> vm.network_interfaces\n join azure_subscription as sub on sub.subscription_id = vm.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name AS sg_name, + network_interfaces + FROM + azure_network_security_group AS nsg, + jsonb_array_elements(security_rules) AS sg, + jsonb_array_elements_text( + sg -> 'properties' -> 'destinationPortRanges' + || (sg -> 'properties' -> 'destinationPortRange') :: jsonb + ) AS dport, + jsonb_array_elements_text( + sg -> 'properties' -> 'sourceAddressPrefixes' + || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb + ) AS sip + WHERE + sg -> 'properties' ->> 'access' = 'Allow' + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' IN ('TCP', 'UDP') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('22', '3389', '*') + OR ( + dport LIKE '%-%' + AND ( + (53 BETWEEN split_part(dport, '-', 1) :: integer AND split_part(dport, '-', 2) :: integer) + OR (123 BETWEEN split_part(dport, '-', 1) :: integer AND split_part(dport, '-', 2) :: integer) + OR (161 BETWEEN split_part(dport, '-', 1) :: integer AND split_part(dport, '-', 2) :: integer) + OR (389 BETWEEN split_part(dport, '-', 1) :: integer AND split_part(dport, '-', 2) :: integer) + OR (1900 BETWEEN split_part(dport, '-', 1) :: integer AND split_part(dport, '-', 2) :: integer) + ) + OR (split_part(dport, '-', 1) :: integer <= 3389 AND split_part(dport, '-', 2) :: integer >= 3389) + OR (split_part(dport, '-', 1) :: integer <= 22 AND split_part(dport, '-', 2) :: integer >= 22) + ) + ) + ) + SELECT + vm.vm_id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN sg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sg.sg_name IS NULL THEN vm.title || ' restricts remote access from internet.' + ELSE vm.title || ' allows remote access from internet.' + END AS reason, + vm.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN network_sg AS sg ON sg.network_interfaces @> vm.network_interfaces + JOIN azure_subscription AS sub ON sub.subscription_id = vm.subscription_id; Severity: high Tags: hipaa_hitrust_v92: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Internet-facing virtual machines should be protected with network security groups \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_temp_disks_cache_and_data_flows_encrypted.yaml b/compliance/controls/azure/azure_compute_vm_temp_disks_cache_and_data_flows_encrypted.yaml old mode 100755 new mode 100644 index 1a4c77598..bf9277f72 --- a/compliance/controls/azure/azure_compute_vm_temp_disks_cache_and_data_flows_encrypted.yaml +++ b/compliance/controls/azure/azure_compute_vm_temp_disks_cache_and_data_flows_encrypted.yaml @@ -1,24 +1,24 @@ +Description: 'By default, a virtual machine''s OS and data disks are encrypted-at-rest using platform-managed keys. Temp disks, data caches and data flowing between compute and storage aren''t encrypted. Disregard this recommendation if: 1. using encryption-at-host, or 2. server-side encryption on Managed Disks meets your security requirements. Learn more in: Server-side encryption of Azure Disk Storage: https://aka.ms/disksse, Different disk encryption offerings: https://aka.ms/diskencryptioncomparison' ID: azure_compute_vm_temp_disks_cache_and_data_flows_encrypted -Title: "Virtual machines should encrypt temp disks, caches, and data flows between Compute and Storage resources" -Description: "By default, a virtual machine's OS and data disks are encrypted-at-rest using platform-managed keys. Temp disks, data caches and data flowing between compute and storage aren't encrypted. Disregard this recommendation if: 1. using encryption-at-host, or 2. server-side encryption on Managed Disks meets your security requirements. Learn more in: Server-side encryption of Azure Disk Storage: https://aka.ms/disksse, Different disk encryption offerings: https://aka.ms/diskencryptioncomparison" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Virtual machines should encrypt temp disks, caches, and data flows between Compute and Storage resources \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_uses_azure_resource_manager.yaml b/compliance/controls/azure/azure_compute_vm_uses_azure_resource_manager.yaml old mode 100755 new mode 100644 index 9e7237f1e..f5b1df9a6 --- a/compliance/controls/azure/azure_compute_vm_uses_azure_resource_manager.yaml +++ b/compliance/controls/azure/azure_compute_vm_uses_azure_resource_manager.yaml @@ -1,14 +1,34 @@ +Description: 'Use new Azure Resource Manager for your virtual machines to provide security enhancements such as: stronger access control (RBAC), better auditing, Azure Resource Manager based deployment and governance, access to managed identities, access to key vault for secrets, Azure AD-based authentication and support for tags and resource groups for easier security management.' ID: azure_compute_vm_uses_azure_resource_manager -Title: "Virtual machines should be migrated to new Azure Resource Manager resources" -Description: "Use new Azure Resource Manager for your virtual machines to provide security enhancements such as: stronger access control (RBAC), better auditing, Azure Resource Manager based deployment and governance, access to managed identities, access to key vault for secrets, Azure AD-based authentication and support for tags and resource groups for easier security management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n vm.vm_id as resource,\n vm.og_account_id as og_account_id,\n vm.og_resource_id as og_resource_id,\n case\n when resource_group is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when resource_group is not null then vm.title || ' uses azure resource manager.'\n else vm.title || ' not uses azure resource manager.'\n end as reason\n \n , vm.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as vm,\n azure_subscription as sub\nwhere\n sub.subscription_id = vm.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.vm_id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN resource_group IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN resource_group IS NOT NULL THEN vm.title || ' uses Azure Resource Manager.' + ELSE vm.title || ' not uses Azure Resource Manager.' + END AS reason, + vm.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -19,5 +39,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Virtual machines should be migrated to new Azure Resource Manager resources \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_utilizing_managed_disk.yaml b/compliance/controls/azure/azure_compute_vm_utilizing_managed_disk.yaml old mode 100755 new mode 100644 index 03105192b..0f7bb9939 --- a/compliance/controls/azure/azure_compute_vm_utilizing_managed_disk.yaml +++ b/compliance/controls/azure/azure_compute_vm_utilizing_managed_disk.yaml @@ -1,14 +1,34 @@ +Description: Migrate BLOB based VHD's to Managed Disks on Virtual Machines to exploit the default features of this configuration. ID: azure_compute_vm_utilizing_managed_disk -Title: "Ensure Virtual Machines are utilizing Managed Disks" -Description: "Migrate BLOB based VHD's to Managed Disks on Virtual Machines to exploit the default features of this configuration." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n vm.id as resource,\n vm.og_account_id as og_account_id,\n vm.og_resource_id as og_resource_id,\n case\n when managed_disk_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when managed_disk_id is null then vm.name || ' VM not utilizing managed disks.'\n else vm.name || ' VM utilizing managed disks.'\n end as reason\n \n , vm.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as vm,\n azure_subscription as sub\nwhere\n sub.subscription_id = vm.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id AS og_account_id, + vm.og_resource_id AS og_resource_id, + CASE + WHEN managed_disk_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN managed_disk_id IS NULL THEN vm.name || ' VM not utilizing managed disks.' + ELSE vm.name || ' VM utilizing managed disks.' + END AS reason, + vm.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Ensure Virtual Machines are utilizing Managed Disks \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_vulnerability_assessment_solution_enabled.yaml b/compliance/controls/azure/azure_compute_vm_vulnerability_assessment_solution_enabled.yaml old mode 100755 new mode 100644 index 52724eda9..83c7c68d3 --- a/compliance/controls/azure/azure_compute_vm_vulnerability_assessment_solution_enabled.yaml +++ b/compliance/controls/azure/azure_compute_vm_vulnerability_assessment_solution_enabled.yaml @@ -1,14 +1,57 @@ +Description: Audits virtual machines to detect whether they are running a supported vulnerability assessment solution. A core component of every cyber risk and security program is the identification and analysis of vulnerabilities. Azure Security Center's standard pricing tier includes vulnerability scanning for your virtual machines at no extra cost. Additionally, Security Center can automatically deploy this tool for you. ID: azure_compute_vm_vulnerability_assessment_solution_enabled -Title: "A vulnerability assessment solution should be enabled on your virtual machines" -Description: "Audits virtual machines to detect whether they are running a supported vulnerability assessment solution. A core component of every cyber risk and security program is the identification and analysis of vulnerabilities. Azure Security Center's standard pricing tier includes vulnerability scanning for your virtual machines at no extra cost. Additionally, Security Center can automatically deploy this tool for you." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with defender_enabled_vms as (\n select\n distinct a.vm_id as vm_id\n from\n azure_compute_virtual_machine as a,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'ExtensionType' = any(ARRAY ['MDE.Linux', 'MDE.Windows'])\n and b ->> 'ProvisioningState' = 'Succeeded'\n),\nagent_installed_vm as (\n select\n distinct a.vm_id as vm_id\n from\n defender_enabled_vms as a\n left join azure_compute_virtual_machine as w on w.vm_id = a.vm_id,\n jsonb_array_elements(extensions) as b\n where\n b ->> 'Publisher' = 'Qualys'\n and b ->> 'ExtensionType' = any(ARRAY ['WindowsAgent.AzureSecurityCenter', 'LinuxAgent.AzureSecurityCenter'])\n and b ->> 'ProvisioningState' = 'Succeeded'\n)\nselect\n a.vm_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.vm_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when b.vm_id is not null then a.title || ' have vulnerability assessment solution enabled.'\n else a.title || ' have vulnerability assessment solution disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join agent_installed_vm as b on a.vm_id = b.vm_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH defender_enabled_vms AS ( + SELECT + DISTINCT a.vm_id AS vm_id + FROM + azure_compute_virtual_machine AS a, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'ExtensionType' = ANY(ARRAY ['MDE.Linux', 'MDE.Windows']) + AND b ->> 'ProvisioningState' = 'Succeeded' + ), + agent_installed_vm AS ( + SELECT + DISTINCT a.vm_id AS vm_id + FROM + defender_enabled_vms AS a + LEFT JOIN azure_compute_virtual_machine AS w ON w.vm_id = a.vm_id, + jsonb_array_elements(extensions) AS b + WHERE + b ->> 'Publisher' = 'Qualys' + AND b ->> 'ExtensionType' = ANY(ARRAY ['WindowsAgent.AzureSecurityCenter', 'LinuxAgent.AzureSecurityCenter']) + AND b ->> 'ProvisioningState' = 'Succeeded' + ) + SELECT + a.vm_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.vm_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.vm_id IS NOT NULL THEN a.title || ' have vulnerability assessment solution enabled.' + ELSE a.title || ' have vulnerability assessment solution disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN agent_installed_vm AS b ON a.vm_id = b.vm_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -19,5 +62,4 @@ Tags: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: A vulnerability assessment solution should be enabled on your virtual machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_vulnerability_findings_resolved_for_sql_server.yaml b/compliance/controls/azure/azure_compute_vm_vulnerability_findings_resolved_for_sql_server.yaml old mode 100755 new mode 100644 index 5fd030cc1..3c845fd8d --- a/compliance/controls/azure/azure_compute_vm_vulnerability_findings_resolved_for_sql_server.yaml +++ b/compliance/controls/azure/azure_compute_vm_vulnerability_findings_resolved_for_sql_server.yaml @@ -1,24 +1,24 @@ +Description: SQL vulnerability assessment scans your database for security vulnerabilities, and exposes any deviations from best practices such as misconfigurations, excessive permissions, and unprotected sensitive data. Resolving the vulnerabilities found can greatly improve your database security posture. ID: azure_compute_vm_vulnerability_findings_resolved_for_sql_server -Title: "SQL servers on machines should have vulnerability findings resolved" -Description: "SQL vulnerability assessment scans your database for security vulnerabilities, and exposes any deviations from best practices such as misconfigurations, excessive permissions, and unprotected sensitive data. Resolving the vulnerabilities found can greatly improve your database security posture." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: SQL servers on machines should have vulnerability findings resolved \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_windows_defender_exploit_guard_enabled.yaml b/compliance/controls/azure/azure_compute_vm_windows_defender_exploit_guard_enabled.yaml old mode 100755 new mode 100644 index e3c5ed24e..e047cb510 --- a/compliance/controls/azure/azure_compute_vm_windows_defender_exploit_guard_enabled.yaml +++ b/compliance/controls/azure/azure_compute_vm_windows_defender_exploit_guard_enabled.yaml @@ -1,19 +1,54 @@ +Description: Windows Defender Exploit Guard uses the Azure Policy Guest Configuration agent. Exploit Guard has four components that are designed to lock down devices against a wide variety of attack vectors and block behaviors commonly used in malware attacks while enabling enterprises to balance their security risk and productivity requirements (Windows only). ID: azure_compute_vm_windows_defender_exploit_guard_enabled -Title: "Windows Defender Exploit Guard should be enabled on your machines" -Description: "Windows Defender Exploit Guard uses the Azure Policy Guest Configuration agent. Exploit Guard has four components that are designed to lock down devices against a wide variety of attack vectors and block behaviors commonly used in malware attacks while enabling enterprises to balance their security risk and productivity requirements (Windows only)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with compute_machine as(\n select\n id,\n name,\n subscription_id,\n resource_group\n from\n azure_compute_virtual_machine,\n jsonb_array_elements(guest_configuration_assignments) as e\n where\n e ->> 'name' = 'WindowsDefenderExploitGuard'\n and e ->> 'complianceStatus' = 'Compliant'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.os_type <> 'Windows' then 'skip'\n when m.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.os_type <> 'Windows' then a.name || ' is of ' || a.os_type || ' operating system.'\n when m.id is not null then a.name || ' windows defender exploit guard enabled.'\n else a.name || ' windows defender exploit guard disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_compute_virtual_machine as a\n left join compute_machine as m on m.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH compute_machine AS ( + SELECT + id, + name, + subscription_id, + resource_group + FROM + azure_compute_virtual_machine, + jsonb_array_elements(guest_configuration_assignments) AS e + WHERE + e ->> 'name' = 'WindowsDefenderExploitGuard' + AND e ->> 'complianceStatus' = 'Compliant' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.os_type <> 'Windows' THEN 'skip' + WHEN m.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.os_type <> 'Windows' THEN a.name || ' is of ' || a.os_type || ' operating system.' + WHEN m.id IS NOT NULL THEN a.name || ' windows defender exploit guard enabled.' + ELSE a.name || ' windows defender exploit guard disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS a + LEFT JOIN compute_machine AS m ON m.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Windows Defender Exploit Guard should be enabled on your machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_compute_vm_with_no_specified_certificates_in_trusted_root_windows.yaml b/compliance/controls/azure/azure_compute_vm_with_no_specified_certificates_in_trusted_root_windows.yaml old mode 100755 new mode 100644 index 9eee0df56..a6722be08 --- a/compliance/controls/azure/azure_compute_vm_with_no_specified_certificates_in_trusted_root_windows.yaml +++ b/compliance/controls/azure/azure_compute_vm_with_no_specified_certificates_in_trusted_root_windows.yaml @@ -1,24 +1,24 @@ +Description: Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the machine Trusted Root certificate store does not contain one or more of the certificates listed by the policy parameter. ID: azure_compute_vm_with_no_specified_certificates_in_trusted_root_windows -Title: "Audit Windows machines that do not contain the specified certificates in Trusted Root" -Description: "Requires that prerequisites are deployed to the policy assignment scope. Machines are non-compliant if the machine Trusted Root certificate store does not contain one or more of the certificates listed by the policy parameter." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required. Check control description for more details.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required. Check control description for more details.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Audit Windows machines that do not contain the specified certificates in Trusted Root \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_instance_container_group_encrypted_using_cmk.yaml b/compliance/controls/azure/azure_container_instance_container_group_encrypted_using_cmk.yaml old mode 100755 new mode 100644 index 8f8ff09ff..de80aea6d --- a/compliance/controls/azure/azure_container_instance_container_group_encrypted_using_cmk.yaml +++ b/compliance/controls/azure/azure_container_instance_container_group_encrypted_using_cmk.yaml @@ -1,32 +1,36 @@ +Description: Secure your containers with greater flexibility using customer-managed keys. When you specify a customer-managed key, that key is used to protect and control access to the key that encrypts your data. Using customer-managed keys provides additional capabilities to control rotation of the key encryption key or cryptographically erase data. ID: azure_container_instance_container_group_encrypted_using_cmk -Title: "Container Instance container group should use customer-managed key for encryption" -Description: "Secure your containers with greater flexibility using customer-managed keys. When you specify a customer-managed key, that key is used to protect and control access to the key that encrypts your data. Using customer-managed keys provides additional capabilities to control rotation of the key encryption key or cryptographically erase data." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - cg.id as resource, - cg.og_account_id as og_account_id, - cg.og_resource_id as og_resource_id, - case - when encryption_properties ->> 'keyName' is not null and encryption_properties ->> 'vaultBaseUrl' is not null then 'ok' - else 'alarm' - end as status, - case - when encryption_properties ->> 'keyName' is not null and encryption_properties ->> 'vaultBaseUrl' is not null then cg.title || ' encrypted with CMK.' - else cg.title || ' not encrypted with CMK.' - end as reason - from - azure_container_group as cg, - azure_subscription as sub - where - sub.subscription_id = cg.subscription_id; - PrimaryTable: azure_container_group ListOfTables: - azure_container_group - azure_subscription Parameters: [] + PrimaryTable: azure_container_group + QueryToExecute: | + SELECT + cg.id AS resource, + cg.og_account_id AS og_account_id, + cg.og_resource_id AS og_resource_id, + CASE + WHEN encryption_properties ->> 'keyName' IS NOT NULL + AND encryption_properties ->> 'vaultBaseUrl' IS NOT NULL + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_properties ->> 'keyName' IS NOT NULL + AND encryption_properties ->> 'vaultBaseUrl' IS NOT NULL + THEN cg.title || ' encrypted with CMK.' + ELSE cg.title || ' not encrypted with CMK.' + END AS reason + FROM + azure_container_group AS cg, + azure_subscription AS sub + WHERE + sub.subscription_id = cg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Container Instance container group should use customer-managed key for encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_instance_container_group_identity_provider_enabled.yaml b/compliance/controls/azure/azure_container_instance_container_group_identity_provider_enabled.yaml old mode 100755 new mode 100644 index 440db08f0..22a80ca59 --- a/compliance/controls/azure/azure_container_instance_container_group_identity_provider_enabled.yaml +++ b/compliance/controls/azure/azure_container_instance_container_group_identity_provider_enabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure that managed identity provider is enabled for the container instance container group. This control is non-compliant if container instance container group identity provider is disabled. ID: azure_container_instance_container_group_identity_provider_enabled -Title: "Container instance container groups identity provider should be enabled" -Description: "Ensure that managed identity provider is enabled for the container instance container group. This control is non-compliant if container instance container group identity provider is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - cg.id as resource, - cg.og_account_id as og_account_id, - cg.og_resource_id as og_resource_id, - case - when identity is null then 'alarm' - else 'ok' - end as status, - case - when identity is null then cg.name || ' identity provider disabled.' - else cg.name || ' identity provider enabled.' - end as reason - from - azure_container_group as cg, - azure_subscription as sub - where - sub.subscription_id = cg.subscription_id; - PrimaryTable: azure_container_group ListOfTables: - azure_container_group - azure_subscription Parameters: [] + PrimaryTable: azure_container_group + QueryToExecute: | + SELECT + cg.id AS resource, + cg.og_account_id AS og_account_id, + cg.og_resource_id AS og_resource_id, + CASE + WHEN identity IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity IS NULL THEN cg.name || ' identity provider disabled.' + ELSE cg.name || ' identity provider enabled.' + END AS reason + FROM + azure_container_group AS cg, + azure_subscription AS sub + WHERE + sub.subscription_id = cg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Container instance container groups identity provider should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_instance_container_group_in_virtual_network.yaml b/compliance/controls/azure/azure_container_instance_container_group_in_virtual_network.yaml old mode 100755 new mode 100644 index 9de552d0e..37e235421 --- a/compliance/controls/azure/azure_container_instance_container_group_in_virtual_network.yaml +++ b/compliance/controls/azure/azure_container_instance_container_group_in_virtual_network.yaml @@ -1,32 +1,32 @@ +Description: This control ensures that the container group is deployed into a virtual network. ID: azure_container_instance_container_group_in_virtual_network -Title: "Container instance container groups should be in virtual network" -Description: "This control ensures that the container group is deployed into a virtual network." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - cg.id as resource, - cg.og_account_id as og_account_id, - cg.og_resource_id as og_resource_id, - case - when subnet_ids is not null then 'ok' - else 'alarm' - end as status, - case - when subnet_ids is not null then cg.title || ' in virtual network.' - else cg.title || ' not in virtual network.' - end as reason - from - azure_container_group as cg, - azure_subscription as sub - where - sub.subscription_id = cg.subscription_id; - PrimaryTable: azure_container_group ListOfTables: - azure_container_group - azure_subscription Parameters: [] + PrimaryTable: azure_container_group + QueryToExecute: | + SELECT + cg.id AS resource, + cg.og_account_id AS og_account_id, + cg.og_resource_id AS og_resource_id, + CASE + WHEN subnet_ids IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN subnet_ids IS NOT NULL THEN cg.title || ' in virtual network.' + ELSE cg.title || ' not in virtual network.' + END AS reason + FROM + azure_container_group AS cg, + azure_subscription AS sub + WHERE + sub.subscription_id = cg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Container instance container groups should be in virtual network \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_instance_container_group_secured_environment_variable.yaml b/compliance/controls/azure/azure_container_instance_container_group_secured_environment_variable.yaml old mode 100755 new mode 100644 index d6c9d79ce..0d834e2c8 --- a/compliance/controls/azure/azure_container_instance_container_group_secured_environment_variable.yaml +++ b/compliance/controls/azure/azure_container_instance_container_group_secured_environment_variable.yaml @@ -1,43 +1,43 @@ +Description: Ensure that container instance container group uses secured environment variables. This control is non-compliant if container instance container group does not use secured environment variables. ID: azure_container_instance_container_group_secured_environment_variable -Title: "Container instance container groups should use secured environment variable" -Description: "Ensure that container instance container group uses secured environment variables. This control is non-compliant if container instance container group does not uses secured environment variables." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with not_secured_environment_variable_container_group as ( - select - id - from - azure_container_group, - jsonb_array_elements(containers) as c, - jsonb_array_elements(c -> 'properties' -> 'environmentVariables') as v - where - v ->'value' is not null - ) - select - cg.id as resource, - cg.og_account_id as og_account_id, - cg.og_resource_id as og_resource_id, - case - when g.id is not null then 'alarm' - else 'ok' - end as status, - case - when g.id is not null then cg.name || ' have unsecured environment variable.' - else cg.name || ' have secured environment variable.' - end as reason - from - azure_container_group as cg - left join not_secured_environment_variable_container_group as g on g.id = cg.id, - azure_subscription as sub - where - sub.subscription_id = cg.subscription_id; - PrimaryTable: azure_container_group ListOfTables: - azure_container_group - azure_subscription Parameters: [] + PrimaryTable: azure_container_group + QueryToExecute: | + WITH not_secured_environment_variable_container_group AS ( + SELECT + id + FROM + azure_container_group, + jsonb_array_elements(containers) AS c, + jsonb_array_elements(c -> 'properties' -> 'environmentVariables') AS v + WHERE + v -> 'value' IS NOT NULL + ) + SELECT + cg.id AS resource, + cg.og_account_id AS og_account_id, + cg.og_resource_id AS og_resource_id, + CASE + WHEN g.id IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN g.id IS NOT NULL THEN cg.name || ' have unsecured environment variable.' + ELSE cg.name || ' have secured environment variable.' + END AS reason + FROM + azure_container_group AS cg + LEFT JOIN not_secured_environment_variable_container_group AS g ON g.id = cg.id, + azure_subscription AS sub + WHERE + sub.subscription_id = cg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Container instance container groups should use secured environment variable \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_admin_user_disabled.yaml b/compliance/controls/azure/azure_container_registry_admin_user_disabled.yaml old mode 100755 new mode 100644 index ebde3e9b7..7ed66621f --- a/compliance/controls/azure/azure_container_registry_admin_user_disabled.yaml +++ b/compliance/controls/azure/azure_container_registry_admin_user_disabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure container registry admin user is disabled. This control is non-compliant if admin user is enabled. ID: azure_container_registry_admin_user_disabled -Title: "Container registries admin user should be disabled" -Description: "Ensure container registry admin user is disabled. This control is non-compliant if admin user is enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - distinct a.name as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when admin_user_enabled then 'alarm' - else 'ok' - end as status, - case - when admin_user_enabled then a.name || ' admin user enabled.' - else a.name || ' admin user disabled.' - end as reason - from - azure_container_registry as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_container_registry ListOfTables: - azure_container_registry - azure_subscription Parameters: [] + PrimaryTable: azure_container_registry + QueryToExecute: | + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN admin_user_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN admin_user_enabled THEN a.name || ' admin user enabled.' + ELSE a.name || ' admin user disabled.' + END AS reason + FROM + azure_container_registry AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Container registries admin user should be disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_container_registry_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index f6da18248..0956194dd --- a/compliance/controls/azure/azure_container_registry_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_container_registry_encrypted_with_cmk.yaml @@ -1,19 +1,38 @@ +Description: Use customer-managed keys to manage the encryption at rest of the contents of your registries. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_container_registry_encrypted_with_cmk -Title: "Container registries should be encrypted with a customer-managed key" -Description: "Use customer-managed keys to manage the encryption at rest of the contents of your registries. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n distinct a.name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when encryption ->> 'status' = 'enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption ->> 'status' = 'enabled' then a.name || ' encrypted with CMK.'\n else a.name || ' not encrypted with CMK.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_container_registry as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_container_registry ListOfTables: - azure_container_registry - azure_subscription Parameters: [] + PrimaryTable: azure_container_registry + QueryToExecute: | + SELECT DISTINCT + a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN encryption ->> 'status' = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption ->> 'status' = 'enabled' THEN a.name || ' encrypted with CMK.' + ELSE a.name || ' not encrypted with CMK.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_container_registry AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/ContainerRegistry -IntegrationType: - - azure_subscription +Title: Container registries should be encrypted with a customer-managed key \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_geo_replication_enabled.yaml b/compliance/controls/azure/azure_container_registry_geo_replication_enabled.yaml old mode 100755 new mode 100644 index 369767d30..1e1a57c80 --- a/compliance/controls/azure/azure_container_registry_geo_replication_enabled.yaml +++ b/compliance/controls/azure/azure_container_registry_geo_replication_enabled.yaml @@ -1,47 +1,49 @@ +Description: Ensure that container registries are geo-replicated to align with multi-region container deployments. ID: azure_container_registry_geo_replication_enabled -Title: "Container registries should be geo-replicated" -Description: "Ensure that container registries are geo-replicated to align with multi-region container deployments." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with geo_replication_count as ( - select - name as name, + ListOfTables: + - azure_container_registry + - azure_subscription + Parameters: [] + PrimaryTable: azure_container_registry + QueryToExecute: | + WITH geo_replication_count AS ( + SELECT + name AS name, subscription_id, - (v ->> 'currentValue')::int as geo_replication_count - from + (v ->> 'currentValue')::int AS geo_replication_count + FROM azure_container_registry, - jsonb_array_elements(usages -> 'value') as v - where + jsonb_array_elements(usages -> 'value') AS v + WHERE v ->> 'name' = 'Geo-replications' - and v ->> 'unit' = 'Count' + AND v ->> 'unit' = 'Count' ) - select - distinct a.name as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when sku_name <> 'Premium' then 'skip' - when c.geo_replication_count > 1 then 'ok' - else 'alarm' - end as status, - case - when sku_name <> 'Premium' then a.name || ' is of ' || sku_tier || ' tier.' - when c.geo_replication_count > 1 then a.name || ' ' || c.geo_replication_count || ' geo replication configured.' - else a.name || ' geo replication not configured.' - end as reason - from - azure_container_registry as a - left join geo_replication_count as c on a.name = c.name and a.subscription_id = c.subscription_id, - azure_subscription as sub - where + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_name <> 'Premium' THEN 'skip' + WHEN c.geo_replication_count > 1 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_name <> 'Premium' THEN a.name || ' is of ' || sku_tier || ' tier.' + WHEN c.geo_replication_count > 1 THEN a.name || ' ' || c.geo_replication_count || ' geo replication configured.' + ELSE a.name || ' geo replication not configured.' + END AS reason + FROM + azure_container_registry AS a + LEFT JOIN geo_replication_count AS c + ON a.name = c.name + AND a.subscription_id = c.subscription_id, + azure_subscription AS sub + WHERE sub.subscription_id = a.subscription_id; - PrimaryTable: azure_container_registry - ListOfTables: - - azure_container_registry - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Container registries should be geo-replicated \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_public_network_access_disabled.yaml b/compliance/controls/azure/azure_container_registry_public_network_access_disabled.yaml old mode 100755 new mode 100644 index 2a761e392..c96a3dcae --- a/compliance/controls/azure/azure_container_registry_public_network_access_disabled.yaml +++ b/compliance/controls/azure/azure_container_registry_public_network_access_disabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure that container registries public network access is disabled. ID: azure_container_registry_public_network_access_disabled -Title: "Container registries public network access should be disabled" -Description: "Ensure that container registries public network access is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - distinct a.name as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when public_network_access = 'Enabled' then 'alarm' - else 'ok' - end as status, - case - when public_network_access = 'Enabled' then a.name || ' public network access enabled.' - else a.name || ' public network access disabled.' - end as reason - from - azure_container_registry as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_container_registry ListOfTables: - azure_container_registry - azure_subscription Parameters: [] + PrimaryTable: azure_container_registry + QueryToExecute: | + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN a.name || ' public network access enabled.' + ELSE a.name || ' public network access disabled.' + END AS reason + FROM + azure_container_registry AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Container registries public network access should be disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_quarantine_policy_enabled.yaml b/compliance/controls/azure/azure_container_registry_quarantine_policy_enabled.yaml old mode 100755 new mode 100644 index c77fa6e16..83f676353 --- a/compliance/controls/azure/azure_container_registry_quarantine_policy_enabled.yaml +++ b/compliance/controls/azure/azure_container_registry_quarantine_policy_enabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure container registry quarantine policy is enabled. This control is non-compliant if quarantine policy is disabled. ID: azure_container_registry_quarantine_policy_enabled -Title: "Container registries quarantine policy should be enabled" -Description: "Ensure container registry quarantine policy is enabled. This control is non-compliant if quarantine policy is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - distinct a.name as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when policies -> 'quarantinePolicy' ->> 'status' = 'enabled' then 'ok' - else 'alarm' - end as status, - case - when policies -> 'quarantinePolicy' ->> 'status' = 'enabled' then a.name || ' quarantine policy enabled.' - else a.name || ' quarantine policy disabled.' - end as reason - from - azure_container_registry as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_container_registry ListOfTables: - azure_container_registry - azure_subscription Parameters: [] + PrimaryTable: azure_container_registry + QueryToExecute: | + SELECT DISTINCT + a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN policies -> 'quarantinePolicy' ->> 'status' = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN policies -> 'quarantinePolicy' ->> 'status' = 'enabled' THEN a.name || ' quarantine policy enabled.' + ELSE a.name || ' quarantine policy disabled.' + END AS reason + FROM + azure_container_registry AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Container registries quarantine policy should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_restrict_public_access.yaml b/compliance/controls/azure/azure_container_registry_restrict_public_access.yaml old mode 100755 new mode 100644 index aa95dc1b1..8d57233b8 --- a/compliance/controls/azure/azure_container_registry_restrict_public_access.yaml +++ b/compliance/controls/azure/azure_container_registry_restrict_public_access.yaml @@ -1,19 +1,38 @@ +Description: Azure container registries by default accept connections over the internet from hosts on any network. To protect your registries from potential threats, allow access from only specific public IP addresses or address ranges. If your registry doesn't have an IP/firewall rule or a configured virtual network, it will appear in the unhealthy resources. ID: azure_container_registry_restrict_public_access -Title: "Container registries should not allow unrestricted network access" -Description: "Azure container registries by default accept connections over the internet from hosts on any network. To protect your registries from potential threats, allow access from only specific public IP addresses or address ranges. If your registry doesn't have an IP/firewall rule or a configured virtual network, it will appear in the unhealthy resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n distinct a.name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when network_rule_set ->> 'defaultAction' = 'Deny' then 'ok'\n else 'alarm'\n end as status,\n case\n when network_rule_set ->> 'defaultAction' = 'Deny' then a.name || ' publicly not accessible.'\n else a.name || ' publicly accessible.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_container_registry as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_container_registry ListOfTables: - azure_container_registry - azure_subscription Parameters: [] + PrimaryTable: azure_container_registry + QueryToExecute: | + SELECT DISTINCT + a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN network_rule_set ->> 'defaultAction' = 'Deny' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN network_rule_set ->> 'defaultAction' = 'Deny' THEN a.name || ' publicly not accessible.' + ELSE a.name || ' publicly accessible.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_container_registry AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/ContainerRegistry -IntegrationType: - - azure_subscription +Title: Container registries should not allow unrestricted network access \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_retention_policy_enabled.yaml b/compliance/controls/azure/azure_container_registry_retention_policy_enabled.yaml old mode 100755 new mode 100644 index 97d59c4e6..8a530a2a0 --- a/compliance/controls/azure/azure_container_registry_retention_policy_enabled.yaml +++ b/compliance/controls/azure/azure_container_registry_retention_policy_enabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure container registry retention policy is enabled. This control is non-compliant if retention policy is disabled. ID: azure_container_registry_retention_policy_enabled -Title: "Container registries retention policy should be enabled" -Description: "Ensure container registry retention policy is enabled. This control is non-compliant if retention policy is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - distinct a.name as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when policies -> 'retentionPolicy' ->> 'status' = 'enabled' then 'ok' - else 'alarm' - end as status, - case - when policies -> 'retentionPolicy' ->> 'status' = 'enabled' then a.name || ' retention policy enabled.' - else a.name || ' retention policy disabled.' - end as reason - from - azure_container_registry as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_container_registry ListOfTables: - azure_container_registry - azure_subscription Parameters: [] + PrimaryTable: azure_container_registry + QueryToExecute: | + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN policies -> 'retentionPolicy' ->> 'status' = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN policies -> 'retentionPolicy' ->> 'status' = 'enabled' THEN a.name || ' retention policy enabled.' + ELSE a.name || ' retention policy disabled.' + END AS reason + FROM + azure_container_registry AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Container registries retention policy should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_trust_policy_enabled.yaml b/compliance/controls/azure/azure_container_registry_trust_policy_enabled.yaml old mode 100755 new mode 100644 index 55f8abcfe..ec3da015f --- a/compliance/controls/azure/azure_container_registry_trust_policy_enabled.yaml +++ b/compliance/controls/azure/azure_container_registry_trust_policy_enabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure container registry trust policy is enabled. This control is non-compliant if trust policy is disabled. ID: azure_container_registry_trust_policy_enabled -Title: "Container registries trust policy should be enabled" -Description: "Ensure container registry trust policy is enabled. This control is non-compliant if trust policy is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - distinct a.name as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when policies -> 'trustPolicy' ->> 'status' = 'enabled' then 'ok' - else 'alarm' - end as status, - case - when policies -> 'trustPolicy' ->> 'status' = 'enabled' then a.name || ' trust policy enabled.' - else a.name || ' trust policy disabled.' - end as reason - from - azure_container_registry as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_container_registry ListOfTables: - azure_container_registry - azure_subscription Parameters: [] + PrimaryTable: azure_container_registry + QueryToExecute: | + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN policies -> 'trustPolicy' ->> 'status' = 'enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN policies -> 'trustPolicy' ->> 'status' = 'enabled' THEN a.name || ' trust policy enabled.' + ELSE a.name || ' trust policy disabled.' + END AS reason + FROM + azure_container_registry AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Container registries trust policy should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_use_virtual_service_endpoint.yaml b/compliance/controls/azure/azure_container_registry_use_virtual_service_endpoint.yaml old mode 100755 new mode 100644 index 2ffa413d0..300812598 --- a/compliance/controls/azure/azure_container_registry_use_virtual_service_endpoint.yaml +++ b/compliance/controls/azure/azure_container_registry_use_virtual_service_endpoint.yaml @@ -1,20 +1,51 @@ +Description: This policy audits any Container Registry not configured to use a virtual network service endpoint. ID: azure_container_registry_use_virtual_service_endpoint -Title: "Container Registry should use a virtual network service endpoint" -Description: "This policy audits any Container Registry not configured to use a virtual network service endpoint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with container_registry_subnet as (\n select\n distinct a.name,\n rule ->> 'id' as id\n from\n azure_container_registry as a,\n jsonb_array_elements(network_rule_set -> 'virtualNetworkRules') as rule,\n azure_subnet as subnet\n)\nselect\n distinct a.name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when network_rule_set ->> 'defaultAction' <> 'Deny' then 'alarm'\n when s.name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when network_rule_set ->> 'defaultAction' <> 'Deny' then a.name || ' not configured with virtual service endpoint.'\n when s.name is null then a.name || ' not configured with virtual service endpoint.'\n else a.name || ' configured with virtual service endpoint.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_container_registry as a\n left join container_registry_subnet as s on a.name = s.name,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_container_registry ListOfTables: - azure_container_registry - azure_subnet - azure_subscription Parameters: [] + PrimaryTable: azure_container_registry + QueryToExecute: | + WITH container_registry_subnet AS ( + SELECT + DISTINCT a.name, + rule ->> 'id' AS id + FROM + azure_container_registry AS a, + jsonb_array_elements(network_rule_set -> 'virtualNetworkRules') AS rule, + azure_subnet AS subnet + ) + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN network_rule_set ->> 'defaultAction' <> 'Deny' THEN 'alarm' + WHEN s.name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_rule_set ->> 'defaultAction' <> 'Deny' THEN a.name || ' not configured with virtual service endpoint.' + WHEN s.name IS NULL THEN a.name || ' not configured with virtual service endpoint.' + ELSE a.name || ' configured with virtual service endpoint.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_container_registry AS a + LEFT JOIN container_registry_subnet AS s ON a.name = s.name, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/ContainerRegistry -IntegrationType: - - azure_subscription +Title: Container Registry should use a virtual network service endpoint \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_uses_private_link.yaml b/compliance/controls/azure/azure_container_registry_uses_private_link.yaml old mode 100755 new mode 100644 index 8f4136b08..0e55f4d82 --- a/compliance/controls/azure/azure_container_registry_uses_private_link.yaml +++ b/compliance/controls/azure/azure_container_registry_uses_private_link.yaml @@ -1,19 +1,48 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your container registries instead of the entire service, you'll also be protected against data leakage risks. ID: azure_container_registry_uses_private_link -Title: "Container registries should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your container registries instead of the entire service, you'll also be protected against data leakage risks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with container_registry_private_connection as (\n select\n distinct a.id\n from\n azure_container_registry as a,\n jsonb_array_elements(private_endpoint_connections) as connection\n where\n connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when c.id is null then a.name || ' not uses private link.'\n else a.name || ' uses private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_container_registry as a\n left join container_registry_private_connection as c on c.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_container_registry ListOfTables: - azure_container_registry - azure_subscription Parameters: [] + PrimaryTable: azure_container_registry + QueryToExecute: | + WITH container_registry_private_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_container_registry AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_container_registry AS a + LEFT JOIN container_registry_private_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/ContainerRegistry -IntegrationType: - - azure_subscription +Title: Container registries should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_container_registry_vulnerabilities_remediated.yaml b/compliance/controls/azure/azure_container_registry_vulnerabilities_remediated.yaml old mode 100755 new mode 100644 index 2b11151a7..7cb851ed7 --- a/compliance/controls/azure/azure_container_registry_vulnerabilities_remediated.yaml +++ b/compliance/controls/azure/azure_container_registry_vulnerabilities_remediated.yaml @@ -1,24 +1,24 @@ +Description: Container image vulnerability assessment scans your registry for security vulnerabilities and exposes detailed findings for each image. Resolving the vulnerabilities can greatly improve your containers' security posture and protect them from attacks. ID: azure_container_registry_vulnerabilities_remediated -Title: "Container registry images should have vulnerability findings resolved" -Description: "Container image vulnerability assessment scans your registry for security vulnerabilities and exposes detailed findings for each image. Resolving the vulnerabilities can greatly improve your containers' security posture and protect them from attacks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Container registry images should have vulnerability findings resolved \ No newline at end of file diff --git a/compliance/controls/azure/azure_cosmosdb_account_encryption_at_rest_using_cmk.yaml b/compliance/controls/azure/azure_cosmosdb_account_encryption_at_rest_using_cmk.yaml old mode 100755 new mode 100644 index b3ad623fc..385215187 --- a/compliance/controls/azure/azure_cosmosdb_account_encryption_at_rest_using_cmk.yaml +++ b/compliance/controls/azure/azure_cosmosdb_account_encryption_at_rest_using_cmk.yaml @@ -1,19 +1,38 @@ +Description: Use customer-managed keys to manage the encryption at rest of your Azure Cosmos DB. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_cosmosdb_account_encryption_at_rest_using_cmk -Title: "Azure Cosmos DB accounts should use customer-managed keys to encrypt data at rest" -Description: "Use customer-managed keys to manage the encryption at rest of your Azure Cosmos DB. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when key_vault_key_uri is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when key_vault_key_uri is not null then a.name || ' encrypted at rest using CMK.'\n else a.name || ' not encrypted at rest using CMK.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_cosmosdb_account as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN key_vault_key_uri IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN key_vault_key_uri IS NOT NULL THEN a.name || ' encrypted at rest using CMK.' + ELSE a.name || ' not encrypted at rest using CMK.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cosmosdb_account AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/CosmosDB -IntegrationType: - - azure_subscription +Title: Azure Cosmos DB accounts should use customer-managed keys to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_cosmosdb_account_key_based_metadata_write_access_disabled.yaml b/compliance/controls/azure/azure_cosmosdb_account_key_based_metadata_write_access_disabled.yaml old mode 100755 new mode 100644 index 26ad30021..12586f593 --- a/compliance/controls/azure/azure_cosmosdb_account_key_based_metadata_write_access_disabled.yaml +++ b/compliance/controls/azure/azure_cosmosdb_account_key_based_metadata_write_access_disabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure Cosmos DB accounts have key-based metadata write_access disabled. This control is non-compliant if Cosmos DB accounts have key-based metadata write access enabled. ID: azure_cosmosdb_account_key_based_metadata_write_access_disabled -Title: "Cosmos DB accounts should disable key based metadata write access" -Description: "Ensure Cosmos DB accounts have key-based metadata write_access disabled. This control is non-compliant if Cosmos DB accounts have key-based metadata write access enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when disable_key_based_metadata_write_access then 'ok' - else 'alarm' - end as status, - case - when disable_key_based_metadata_write_access then a.name || ' key based metadata write_access disabled.' - else a.name || ' key based metadata write_access enabled.' - end as reason - from - azure_cosmosdb_account as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN disable_key_based_metadata_write_access THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN disable_key_based_metadata_write_access THEN a.name || ' key based metadata write_access disabled.' + ELSE a.name || ' key based metadata write_access enabled.' + END AS reason + FROM + azure_cosmosdb_account AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Cosmos DB accounts should disable key based metadata write access \ No newline at end of file diff --git a/compliance/controls/azure/azure_cosmosdb_account_uses_aad_and_rbac.yaml b/compliance/controls/azure/azure_cosmosdb_account_uses_aad_and_rbac.yaml old mode 100755 new mode 100644 index f154223b3..3623eb056 --- a/compliance/controls/azure/azure_cosmosdb_account_uses_aad_and_rbac.yaml +++ b/compliance/controls/azure/azure_cosmosdb_account_uses_aad_and_rbac.yaml @@ -1,32 +1,32 @@ +Description: Azure Cosmos DB accounts should use Azure Active Directory (AAD) Client Authentication and Role-Based Access Control (RBAC) for access control. ID: azure_cosmosdb_account_uses_aad_and_rbac -Title: "Cosmos DB account 'Access Control' should be configured to use Azure Active Directory (AAD) and Role-Based Access Control (RBAC)" -Description: "Azure Cosmos DB accounts should use Azure Active Directory (AAD) Client Authentication and Role-Based Access Control (RBAC) for access control." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when disable_local_auth then 'ok' - else 'alarm' - end as status, - case - when disable_local_auth then a.name || ' is using AAD and RBAC.' - else a.name || ' is not using AAD and RBAC.' - end as reason - from - azure_cosmosdb_account as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN disable_local_auth THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN disable_local_auth THEN a.name || ' is using AAD and RBAC.' + ELSE a.name || ' is not using AAD and RBAC.' + END AS reason + FROM + azure_cosmosdb_account AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Cosmos DB account 'Access Control' should be configured to use Azure Active Directory (AAD) and Role-Based Access Control (RBAC) \ No newline at end of file diff --git a/compliance/controls/azure/azure_cosmosdb_account_uses_private_link.yaml b/compliance/controls/azure/azure_cosmosdb_account_uses_private_link.yaml old mode 100755 new mode 100644 index 6049ff69f..d13d197c0 --- a/compliance/controls/azure/azure_cosmosdb_account_uses_private_link.yaml +++ b/compliance/controls/azure/azure_cosmosdb_account_uses_private_link.yaml @@ -1,14 +1,44 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your CosmosDB account, data leakage risks are reduced. ID: azure_cosmosdb_account_uses_private_link -Title: "CosmosDB accounts should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your CosmosDB account, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with cosmosdb_private_connection as (\n select\n distinct a.id\n from\n azure_cosmosdb_account as a,\n jsonb_array_elements(private_endpoint_connections) as connection\n where\n connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when c.id is null then a.name || ' not uses private link.'\n else a.name || ' uses private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_cosmosdb_account as a\n left join cosmosdb_private_connection as c on c.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + WITH cosmosdb_private_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_cosmosdb_account AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cosmosdb_account AS a + LEFT JOIN cosmosdb_private_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: category: @@ -29,5 +59,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: CosmosDB accounts should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_cosmosdb_account_virtual_network_filter_enabled.yaml b/compliance/controls/azure/azure_cosmosdb_account_virtual_network_filter_enabled.yaml old mode 100755 new mode 100644 index 92cea9638..2b6547380 --- a/compliance/controls/azure/azure_cosmosdb_account_virtual_network_filter_enabled.yaml +++ b/compliance/controls/azure/azure_cosmosdb_account_virtual_network_filter_enabled.yaml @@ -1,14 +1,36 @@ -ID: azure_cosmosdb_account_virtual_network_filter_enabled -Title: "Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks" Description: "" +ID: azure_cosmosdb_account_virtual_network_filter_enabled +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when public_network_access = 'Disabled' then 'ok'\n when public_network_access = 'Enabled' and is_virtual_network_filter_enabled = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when public_network_access = 'Disabled' then a.name || ' public network access disabled.'\n when public_network_access = 'Enabled' and is_virtual_network_filter_enabled = 'true' then a.name || ' virtual network filter enabled.'\n else a.name || ' virtual network filter disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_cosmosdb_account as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Disabled' THEN 'ok' + WHEN public_network_access = 'Enabled' AND is_virtual_network_filter_enabled = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN public_network_access = 'Disabled' THEN a.name || ' public network access disabled.' + WHEN public_network_access = 'Enabled' AND is_virtual_network_filter_enabled = 'true' THEN a.name || ' virtual network filter enabled.' + ELSE a.name || ' virtual network filter disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cosmosdb_account AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: critical Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Ensure That 'Firewalls & Networks' Is Limited to Use Selected Networks Instead of All Networks \ No newline at end of file diff --git a/compliance/controls/azure/azure_cosmosdb_account_with_firewall_rules.yaml b/compliance/controls/azure/azure_cosmosdb_account_with_firewall_rules.yaml old mode 100755 new mode 100644 index 86f09e946..0417a159a --- a/compliance/controls/azure/azure_cosmosdb_account_with_firewall_rules.yaml +++ b/compliance/controls/azure/azure_cosmosdb_account_with_firewall_rules.yaml @@ -1,19 +1,46 @@ +Description: Firewall rules should be defined on your Azure Cosmos DB accounts to prevent traffic from unauthorized sources. Accounts that have at least one IP rule defined with the virtual network filter enabled are deemed compliant. Accounts disabling public access are also deemed compliant. ID: azure_cosmosdb_account_with_firewall_rules -Title: "Azure Cosmos DB accounts should have firewall rules" -Description: "Firewall rules should be defined on your Azure Cosmos DB accounts to prevent traffic from unauthorized sources. Accounts that have at least one IP rule defined with the virtual network filter enabled are deemed compliant. Accounts disabling public access are also deemed compliant." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when\n public_network_access = 'Enabled'\n and is_virtual_network_filter_enabled = 'false'\n and jsonb_array_length(ip_rules) = 0\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n public_network_access = 'Enabled'\n and is_virtual_network_filter_enabled = 'false'\n and jsonb_array_length(ip_rules) = 0\n then a.name || ' not have firewall rules.'\n else a.name || ' have firewall rules.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_cosmosdb_account as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN + public_network_access = 'Enabled' + AND is_virtual_network_filter_enabled = 'false' + AND jsonb_array_length(ip_rules) = 0 + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + public_network_access = 'Enabled' + AND is_virtual_network_filter_enabled = 'false' + AND jsonb_array_length(ip_rules) = 0 + THEN a.name || ' not have firewall rules.' + ELSE a.name || ' have firewall rules.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cosmosdb_account AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/CosmosDB -IntegrationType: - - azure_subscription +Title: Azure Cosmos DB accounts should have firewall rules \ No newline at end of file diff --git a/compliance/controls/azure/azure_cosmosdb_use_virtual_service_endpoint.yaml b/compliance/controls/azure/azure_cosmosdb_use_virtual_service_endpoint.yaml old mode 100755 new mode 100644 index 3b5dac87d..41fc8fdbd --- a/compliance/controls/azure/azure_cosmosdb_use_virtual_service_endpoint.yaml +++ b/compliance/controls/azure/azure_cosmosdb_use_virtual_service_endpoint.yaml @@ -1,19 +1,48 @@ +Description: This policy audits any Cosmos DB not configured to use a virtual network service endpoint. ID: azure_cosmosdb_use_virtual_service_endpoint -Title: "Cosmos DB should use a virtual network service endpoint" -Description: "This policy audits any Cosmos DB not configured to use a virtual network service endpoint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with cosmosdb_with_virtual_network as (\n select\n distinct a.id\n from\n azure_cosmosdb_account as a,\n jsonb_array_elements(virtual_network_rules) as rule\n where\n rule ->> 'id' is not null\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when c.id is null then a.name || ' not configured with virtual network service endpoint.'\n else a.name || ' configured with virtual network service endpoint.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_cosmosdb_account as a\n left join cosmosdb_with_virtual_network as c on c.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + WITH cosmosdb_with_virtual_network AS ( + SELECT + DISTINCT a.id + FROM + azure_cosmosdb_account AS a, + jsonb_array_elements(virtual_network_rules) AS rule + WHERE + rule ->> 'id' IS NOT NULL + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.name || ' not configured with virtual network service endpoint.' + ELSE a.name || ' configured with virtual network service endpoint.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cosmosdb_account AS a + LEFT JOIN cosmosdb_with_virtual_network AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/CosmosDB -IntegrationType: - - azure_subscription +Title: Cosmos DB should use a virtual network service endpoint \ No newline at end of file diff --git a/compliance/controls/azure/azure_data_factory_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_data_factory_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 5825b5285..5780da420 --- a/compliance/controls/azure/azure_data_factory_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_data_factory_encrypted_with_cmk.yaml @@ -1,19 +1,38 @@ +Description: Use customer-managed keys to manage the encryption at rest of your Azure Data Factory. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_data_factory_encrypted_with_cmk -Title: "Azure data factories should be encrypted with a customer-managed key" -Description: "Use customer-managed keys to manage the encryption at rest of your Azure Data Factory. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when encryption ->> 'vaultBaseUrl' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption ->> 'vaultBaseUrl' is not null then a.name || ' encrypted with CMK.'\n else a.name || ' not encrypted with CMK.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_data_factory as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_data_factory ListOfTables: - azure_data_factory - azure_subscription Parameters: [] + PrimaryTable: azure_data_factory + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN encryption ->> 'vaultBaseUrl' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption ->> 'vaultBaseUrl' IS NOT NULL THEN a.name || ' encrypted with CMK.' + ELSE a.name || ' not encrypted with CMK.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_data_factory AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/DataFactory -IntegrationType: - - azure_subscription +Title: Azure data factories should be encrypted with a customer-managed key \ No newline at end of file diff --git a/compliance/controls/azure/azure_data_factory_public_network_access_disabled.yaml b/compliance/controls/azure/azure_data_factory_public_network_access_disabled.yaml old mode 100755 new mode 100644 index 7554ed4bc..8556c0d69 --- a/compliance/controls/azure/azure_data_factory_public_network_access_disabled.yaml +++ b/compliance/controls/azure/azure_data_factory_public_network_access_disabled.yaml @@ -1,32 +1,32 @@ +Description: Disabling public network access improves security by ensuring that your Data Factory is not exposed on the public internet. ID: azure_data_factory_public_network_access_disabled -Title: "Data factories should disable public network access" -Description: "Disabling public network access improves security by ensuring that your Data Factory is not exposed on the public internet." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when public_network_access = 'Enabled' then 'alarm' - else 'ok' - end as status, - case - when public_network_access = 'Enabled' then a.name || ' public network access enabled.' - else a.name || ' public network access disabled.' - end as reason - from - azure_data_factory as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_data_factory ListOfTables: - azure_data_factory - azure_subscription Parameters: [] + PrimaryTable: azure_data_factory + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN a.name || ' public network access enabled.' + ELSE a.name || ' public network access disabled.' + END AS reason + FROM + azure_data_factory AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Data factories should disable public network access \ No newline at end of file diff --git a/compliance/controls/azure/azure_data_factory_uses_git_repository.yaml b/compliance/controls/azure/azure_data_factory_uses_git_repository.yaml old mode 100755 new mode 100644 index b851869ba..cc17e5547 --- a/compliance/controls/azure/azure_data_factory_uses_git_repository.yaml +++ b/compliance/controls/azure/azure_data_factory_uses_git_repository.yaml @@ -1,32 +1,32 @@ +Description: Ensure that Data Factory utilizes a Git repository as its source control mechanism. This control is non-compliant if Data Factory Git repository is not configured. ID: azure_data_factory_uses_git_repository -Title: "Data factories should use GitHub repository" -Description: "Ensure that Data Factory utilizes a Git repository as its source control mechanism. This control is non-compliant if Data Factory Git repository is not configured." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when repo_configuration ->> 'repositoryName' is not null then 'ok' - else 'alarm' - end as status, - case - when repo_configuration ->> 'repositoryName' is not null then a.name || ' uses git repository.' - else a.name || ' not uses git repository.' - end as reason - from - azure_data_factory as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_data_factory ListOfTables: - azure_data_factory - azure_subscription Parameters: [] + PrimaryTable: azure_data_factory + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN repo_configuration->>'repositoryName' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN repo_configuration->>'repositoryName' IS NOT NULL THEN a.name || ' uses git repository.' + ELSE a.name || ' not uses git repository.' + END AS reason + FROM + azure_data_factory AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Data factories should use GitHub repository \ No newline at end of file diff --git a/compliance/controls/azure/azure_data_factory_uses_private_link.yaml b/compliance/controls/azure/azure_data_factory_uses_private_link.yaml old mode 100755 new mode 100644 index 7f9e4b3a6..717920f50 --- a/compliance/controls/azure/azure_data_factory_uses_private_link.yaml +++ b/compliance/controls/azure/azure_data_factory_uses_private_link.yaml @@ -1,19 +1,48 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Data Factory, data leakage risks are reduced. ID: azure_data_factory_uses_private_link -Title: "Azure Data Factory should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Data Factory, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with data_factory_connection as (\n select\n distinct a.id\n from\n azure_data_factory as a,\n jsonb_array_elements(private_endpoint_connections) as connection\n where\n connection ->> 'PrivateLinkServiceConnectionStateStatus' = 'Approved'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when c.id is null then a.name || ' not uses private link.'\n else a.name || ' uses private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_data_factory as a\n left join data_factory_connection as c on c.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_data_factory ListOfTables: - azure_data_factory - azure_subscription Parameters: [] + PrimaryTable: azure_data_factory + QueryToExecute: | + WITH data_factory_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_data_factory AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection ->> 'PrivateLinkServiceConnectionStateStatus' = 'Approved' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_data_factory AS a + LEFT JOIN data_factory_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/DataFactory -IntegrationType: - - azure_subscription +Title: Azure Data Factory should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_databox_edge_device_double_encryption_enabled.yaml b/compliance/controls/azure/azure_databox_edge_device_double_encryption_enabled.yaml old mode 100755 new mode 100644 index 0c0b6b585..4f51848db --- a/compliance/controls/azure/azure_databox_edge_device_double_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_databox_edge_device_double_encryption_enabled.yaml @@ -1,19 +1,38 @@ +Description: 'To secure the data at rest on the device, ensure it''s double-encrypted, the access to data is controlled, and once the device is deactivated, the data is securely erased off the data disks. Double encryption is the use of two layers of encryption: BitLocker XTS-AES 256-bit encryption on the data volumes and built-in encryption of the hard drives. Learn more in the security overview documentation for the specific Stack Edge device.' ID: azure_databox_edge_device_double_encryption_enabled -Title: "Azure Stack Edge devices should use double-encryption" -Description: "To secure the data at rest on the device, ensure it's double-encrypted, the access to data is controlled, and once the device is deactivated, the data is securely erased off the data disks. Double encryption is the use of two layers of encryption: BitLocker XTS-AES 256-bit encryption on the data volumes and built-in encryption of the hard drives. Learn more in the security overview documentation for the specific Stack Edge device." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when sku_name = any (ARRAY ['TEA_1Node', 'TEA_1Node_UPS', 'TEA_1Node_Heater', 'TEA_1Node_UPS_Heater', 'TEA_4Node_Heater', 'TEA_4Node_UPS_Heater', 'TMA', 'EdgePR_Base', 'EdgePR_Base_UPS', 'EdgeMR_Mini']) then 'ok'\n else 'alarm'\n end as status,\n case\n when sku_name = any (ARRAY ['TEA_1Node', 'TEA_1Node_UPS', 'TEA_1Node_Heater', 'TEA_1Node_UPS_Heater', 'TEA_4Node_Heater', 'TEA_4Node_UPS_Heater', 'TMA', 'EdgePR_Base', 'EdgePR_Base_UPS', 'EdgeMR_Mini']) then a.name || ' double encryption enabled.'\n else a.name || ' double encryption disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_databox_edge_device as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_databox_edge_device ListOfTables: - azure_databox_edge_device - azure_subscription Parameters: [] + PrimaryTable: azure_databox_edge_device + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_name = ANY (ARRAY ['TEA_1Node', 'TEA_1Node_UPS', 'TEA_1Node_Heater', 'TEA_1Node_UPS_Heater', 'TEA_4Node_Heater', 'TEA_4Node_UPS_Heater', 'TMA', 'EdgePR_Base', 'EdgePR_Base_UPS', 'EdgeMR_Mini']) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_name = ANY (ARRAY ['TEA_1Node', 'TEA_1Node_UPS', 'TEA_1Node_Heater', 'TEA_1Node_UPS_Heater', 'TEA_4Node_Heater', 'TEA_4Node_UPS_Heater', 'TMA', 'EdgePR_Base', 'EdgePR_Base_UPS', 'EdgeMR_Mini']) THEN a.name || ' double encryption enabled.' + ELSE a.name || ' double encryption disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_databox_edge_device AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/DataBox -IntegrationType: - - azure_subscription +Title: Azure Stack Edge devices should use double-encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_databox_job_double_encryption_enabled.yaml b/compliance/controls/azure/azure_databox_job_double_encryption_enabled.yaml old mode 100755 new mode 100644 index ac961ec8a..ac87211c5 --- a/compliance/controls/azure/azure_databox_job_double_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_databox_job_double_encryption_enabled.yaml @@ -1,24 +1,24 @@ +Description: Enable a second layer of software-based encryption for data at rest on the device. The device is already protected via Advanced Encryption Standard 256-bit encryption for data at rest. This option adds a second layer of data encryption. ID: azure_databox_job_double_encryption_enabled -Title: "Azure Data Box jobs should enable double encryption for data at rest on the device" -Description: "Enable a second layer of software-based encryption for data at rest on the device. The device is already protected via Advanced Encryption Standard 256-bit encryption for data at rest. This option adds a second layer of data encryption." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Azure Data Box jobs should enable double encryption for data at rest on the device \ No newline at end of file diff --git a/compliance/controls/azure/azure_databox_job_unlock_password_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_databox_job_unlock_password_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 0406b7455..8f2b5258c --- a/compliance/controls/azure/azure_databox_job_unlock_password_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_databox_job_unlock_password_encrypted_with_cmk.yaml @@ -1,24 +1,24 @@ +Description: Use a customer-managed key to control the encryption of the device unlock password for Azure Data Box. Customer-managed keys also help manage access to the device unlock password by the Data Box service in order to prepare the device and copy data in an automated manner. The data on the device itself is already encrypted at rest with Advanced Encryption Standard 256-bit encryption, and the device unlock password is encrypted by default with a Microsoft managed key. ID: azure_databox_job_unlock_password_encrypted_with_cmk -Title: "Azure Data Box jobs should use a customer-managed key to encrypt the device unlock password" -Description: "Use a customer-managed key to control the encryption of the device unlock password for Azure Data Box. Customer-managed keys also help manage access to the device unlock password by the Data Box service in order to prepare the device and copy data in an automated manner. The data on the device itself is already encrypted at rest with Advanced Encryption Standard 256-bit encryption, and the device unlock password is encrypted by default with a Microsoft managed key." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Azure Data Box jobs should use a customer-managed key to encrypt the device unlock password \ No newline at end of file diff --git a/compliance/controls/azure/azure_datalake_analytics_account_logging_enabled.yaml b/compliance/controls/azure/azure_datalake_analytics_account_logging_enabled.yaml old mode 100755 new mode 100644 index 7db3c6e38..272b9e3c2 --- a/compliance/controls/azure/azure_datalake_analytics_account_logging_enabled.yaml +++ b/compliance/controls/azure/azure_datalake_analytics_account_logging_enabled.yaml @@ -1,14 +1,62 @@ +Description: Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised. ID: azure_datalake_analytics_account_logging_enabled -Title: "Resource logs in Data Lake Analytics should be enabled" -Description: "Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n distinct account_id as account_id\n from\n azure_data_lake_analytics_account,\n jsonb_array_elements(diagnostic_settings) setting,\n jsonb_array_elements(setting -> 'properties' -> 'logs') log\n where\n diagnostic_settings is not null\n and (\n (\n (log ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy' ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy') :: JSONB ? 'days'\n )\n or\n (\n (log ->> 'enabled') :: boolean\n and (\n log -> 'retentionPolicy' ->> 'enabled' <> 'true'\n or setting -> 'properties' ->> 'storageAccountId' = ''\n )\n )\n )\n)\nselect\n a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.diagnostic_settings is null then 'alarm'\n when l.account_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.diagnostic_settings is null then a.name || ' logging disabled.'\n when l.account_id is not null then a.name || ' logging enabled.'\n else a.name || ' logging disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_data_lake_analytics_account as a\n left join logging_details as l on a.account_id = l.account_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_data_lake_analytics_account ListOfTables: - azure_data_lake_analytics_account - azure_subscription Parameters: [] + PrimaryTable: azure_data_lake_analytics_account + QueryToExecute: | + WITH logging_details AS ( + SELECT + DISTINCT account_id AS account_id + FROM + azure_data_lake_analytics_account, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND ( + ( + (log ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy' ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy')::JSONB ? 'days' + ) + OR + ( + (log ->> 'enabled')::BOOLEAN + AND ( + log -> 'retentionPolicy' ->> 'enabled' <> 'true' + OR setting -> 'properties' ->> 'storageAccountId' = '' + ) + ) + ) + ) + SELECT + a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.account_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.diagnostic_settings IS NULL THEN a.name || ' logging disabled.' + WHEN l.account_id IS NOT NULL THEN a.name || ' logging enabled.' + ELSE a.name || ' logging disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_data_lake_analytics_account AS a + LEFT JOIN logging_details AS l ON a.account_id = l.account_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +65,4 @@ Tags: - "true" service: - Azure/DataLakeAnalytics -IntegrationType: - - azure_subscription +Title: Resource logs in Data Lake Analytics should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_datalake_store_account_encryption_enabled.yaml b/compliance/controls/azure/azure_datalake_store_account_encryption_enabled.yaml old mode 100755 new mode 100644 index c79e8cdc1..2b8e1dc55 --- a/compliance/controls/azure/azure_datalake_store_account_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_datalake_store_account_encryption_enabled.yaml @@ -1,19 +1,38 @@ +Description: This policy ensures encryption is enabled on all Data Lake Store accounts. ID: azure_datalake_store_account_encryption_enabled -Title: "Require encryption on Data Lake Store accounts" -Description: "This policy ensures encryption is enabled on all Data Lake Store accounts." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n b.account_id as resource,\n b.og_account_id as og_account_id,\n b.og_resource_id as og_resource_id,\n case\n when encryption_state = 'Enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption_state = 'Enabled' then b.name || ' encryption enabled.'\n else b.name || ' encryption disabled.'\n end as reason\n \n , b.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_data_lake_store as b,\n azure_subscription as sub\nwhere\n sub.subscription_id = b.subscription_id;\n" - PrimaryTable: azure_data_lake_store ListOfTables: - azure_data_lake_store - azure_subscription Parameters: [] + PrimaryTable: azure_data_lake_store + QueryToExecute: | + SELECT + b.account_id AS resource, + b.og_account_id AS og_account_id, + b.og_resource_id AS og_resource_id, + CASE + WHEN encryption_state = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_state = 'Enabled' THEN b.name || ' encryption enabled.' + ELSE b.name || ' encryption disabled.' + END AS reason, + b.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_data_lake_store AS b, + azure_subscription AS sub + WHERE + sub.subscription_id = b.subscription_id; Severity: high Tags: hipaa_hitrust_v92: - "true" service: - Azure/DataLakeStorage -IntegrationType: - - azure_subscription +Title: Require encryption on Data Lake Store accounts \ No newline at end of file diff --git a/compliance/controls/azure/azure_datalake_store_account_logging_enabled.yaml b/compliance/controls/azure/azure_datalake_store_account_logging_enabled.yaml old mode 100755 new mode 100644 index 71fb30241..d6a49662d --- a/compliance/controls/azure/azure_datalake_store_account_logging_enabled.yaml +++ b/compliance/controls/azure/azure_datalake_store_account_logging_enabled.yaml @@ -1,14 +1,62 @@ +Description: Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised. ID: azure_datalake_store_account_logging_enabled -Title: "Resource logs in Azure Data Lake Store should be enabled" -Description: "Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n distinct account_id as account_id\n from\n azure_data_lake_store,\n jsonb_array_elements(diagnostic_settings) setting,\n jsonb_array_elements(setting -> 'properties' -> 'logs') log\n where\n diagnostic_settings is not null\n and (\n (\n (log ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy' ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy') :: JSONB ? 'days'\n )\n or\n (\n (log ->> 'enabled') :: boolean\n and (\n log -> 'retentionPolicy' ->> 'enabled' <> 'true'\n or setting -> 'properties' ->> 'storageAccountId' = ''\n )\n )\n )\n)\nselect\n a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.diagnostic_settings is null then 'alarm'\n when l.account_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.diagnostic_settings is null then a.name || ' logging disabled.'\n when l.account_id is not null then a.name || ' logging enabled.'\n else a.name || ' logging disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_data_lake_store as a\n left join logging_details as l on a.account_id = l.account_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_data_lake_store ListOfTables: - azure_data_lake_store - azure_subscription Parameters: [] + PrimaryTable: azure_data_lake_store + QueryToExecute: | + WITH logging_details AS ( + SELECT DISTINCT + account_id AS account_id + FROM + azure_data_lake_store, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND ( + ( + (log ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy' ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy')::JSONB ? 'days' + ) + OR + ( + (log ->> 'enabled')::BOOLEAN + AND ( + log -> 'retentionPolicy' ->> 'enabled' <> 'true' + OR setting -> 'properties' ->> 'storageAccountId' = '' + ) + ) + ) + ) + SELECT + a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.account_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.diagnostic_settings IS NULL THEN a.name || ' logging disabled.' + WHEN l.account_id IS NOT NULL THEN a.name || ' logging enabled.' + ELSE a.name || ' logging disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_data_lake_store AS a + LEFT JOIN logging_details AS l ON a.account_id = l.account_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +65,4 @@ Tags: - "true" service: - Azure/DataLakeStorage -IntegrationType: - - azure_subscription +Title: Resource logs in Azure Data Lake Store should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_eventgrid_domain_identity_provider_enabled.yaml b/compliance/controls/azure/azure_eventgrid_domain_identity_provider_enabled.yaml old mode 100755 new mode 100644 index 0b4a1cfa8..2875ac3f5 --- a/compliance/controls/azure/azure_eventgrid_domain_identity_provider_enabled.yaml +++ b/compliance/controls/azure/azure_eventgrid_domain_identity_provider_enabled.yaml @@ -1,30 +1,30 @@ +Description: Ensure that managed identity provider is enabled for Event Grid Domain. This control is non-compliant if Event Grid domain identity provider is disabled. ID: azure_eventgrid_domain_identity_provider_enabled -Title: "Event Grid domains identity provider should be enabled" -Description: "Ensure that managed identity provider is enabled for Event Grid Domain. This control is non-compliant if Event Grid domain identity provider is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when identity_type = 'None' then 'alarm' - else 'ok' - end as status, - case - when identity_type = 'None' then a.name || ' identity provider disabled.' - else a.name || ' identity provider enabled.' - end as reason - from - azure_eventgrid_domain a, - azure_subscription sub; - PrimaryTable: azure_eventgrid_domain ListOfTables: - azure_eventgrid_domain - azure_subscription Parameters: [] + PrimaryTable: azure_eventgrid_domain + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN identity_type = 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity_type = 'None' THEN a.name || ' identity provider disabled.' + ELSE a.name || ' identity provider enabled.' + END AS reason + FROM + azure_eventgrid_domain a, + azure_subscription sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Event Grid domains identity provider should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_eventgrid_domain_private_link_used.yaml b/compliance/controls/azure/azure_eventgrid_domain_private_link_used.yaml old mode 100755 new mode 100644 index 687e14b56..02decd675 --- a/compliance/controls/azure/azure_eventgrid_domain_private_link_used.yaml +++ b/compliance/controls/azure/azure_eventgrid_domain_private_link_used.yaml @@ -1,19 +1,40 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Event Grid domain instead of the entire service, you'll also be protected against data leakage risks. ID: azure_eventgrid_domain_private_link_used -Title: "Azure Event Grid domains should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Event Grid domain instead of the entire service, you'll also be protected against data leakage risks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when public_network_access = 'Enabled' then 'alarm'\n when private_endpoint_connections is null then 'info'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then 'ok'\n else 'alarm'\n end as status,\n case\n when public_network_access = 'Enabled' then a.name || ' using public networks.'\n when private_endpoint_connections is null then a.name || ' no private link exists.'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb\n then a.name || ' using private link.'\n else a.name || ' not using private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_eventgrid_domain a,\n azure_subscription sub;\n" - PrimaryTable: azure_eventgrid_domain ListOfTables: - azure_eventgrid_domain - azure_subscription Parameters: [] + PrimaryTable: azure_eventgrid_domain + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + WHEN private_endpoint_connections IS NULL THEN 'info' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN a.name || ' using public networks.' + WHEN private_endpoint_connections IS NULL THEN a.name || ' no private link exists.' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN a.name || ' using private link.' + ELSE a.name || ' not using private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_eventgrid_domain a, + azure_subscription sub; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/EventGrid -IntegrationType: - - azure_subscription +Title: Azure Event Grid domains should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_eventgrid_domain_restrict_public_access.yaml b/compliance/controls/azure/azure_eventgrid_domain_restrict_public_access.yaml old mode 100755 new mode 100644 index 8aa277d08..a70431f01 --- a/compliance/controls/azure/azure_eventgrid_domain_restrict_public_access.yaml +++ b/compliance/controls/azure/azure_eventgrid_domain_restrict_public_access.yaml @@ -1,30 +1,30 @@ +Description: Ensure that Event Grid Domain public network access is disabled. This control is non-compliant if Event Grid domains have public network access enabled. ID: azure_eventgrid_domain_restrict_public_access -Title: "Event Grid domains should restrict public network access" -Description: "Ensure that Event Grid Domain public network access is disabled. This control is non-compliant if Event Grid domains have public network access enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when public_network_access = 'Enabled' then 'alarm' - else 'ok' - end as status, - case - when public_network_access = 'Enabled' then a.name || ' publicly accessible.' - else a.name || ' not publicly accessible.' - end as reason - from - azure_eventgrid_domain a, - azure_subscription sub; - PrimaryTable: azure_eventgrid_domain ListOfTables: - azure_eventgrid_domain - azure_subscription Parameters: [] + PrimaryTable: azure_eventgrid_domain + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN a.name || ' publicly accessible.' + ELSE a.name || ' not publicly accessible.' + END AS reason + FROM + azure_eventgrid_domain a, + azure_subscription sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Event Grid domains should restrict public network access \ No newline at end of file diff --git a/compliance/controls/azure/azure_eventgrid_topic_identity_provider_enabled.yaml b/compliance/controls/azure/azure_eventgrid_topic_identity_provider_enabled.yaml old mode 100755 new mode 100644 index c8b8b74b0..dcb1c82f3 --- a/compliance/controls/azure/azure_eventgrid_topic_identity_provider_enabled.yaml +++ b/compliance/controls/azure/azure_eventgrid_topic_identity_provider_enabled.yaml @@ -1,30 +1,30 @@ +Description: Ensure that managed identity provider is enabled for the Event Grid Topic. This control is non-compliant if Event Grid topic identity provider is disabled. ID: azure_eventgrid_topic_identity_provider_enabled -Title: "Event Grid topics identity provider should be enabled" -Description: "Ensure that managed identity provider is enabled for the Event Grid Topic. This control is non-compliant if Event Grid topic identity provider is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when identity ->> 'type' = 'None' then 'alarm' - else 'ok' - end as status, - case - when identity ->> 'type' = 'None' then a.name || ' identity provider disabled.' - else a.name || ' identity provider enabled.' - end as reason - from - azure_eventgrid_topic a, - azure_subscription sub; - PrimaryTable: azure_eventgrid_topic ListOfTables: - azure_eventgrid_topic - azure_subscription Parameters: [] + PrimaryTable: azure_eventgrid_topic + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN identity ->> 'type' = 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity ->> 'type' = 'None' THEN a.name || ' identity provider disabled.' + ELSE a.name || ' identity provider enabled.' + END AS reason + FROM + azure_eventgrid_topic a, + azure_subscription sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Event Grid topics identity provider should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_eventgrid_topic_local_auth_enabled.yaml b/compliance/controls/azure/azure_eventgrid_topic_local_auth_enabled.yaml old mode 100755 new mode 100644 index cf6ad6264..3568494fa --- a/compliance/controls/azure/azure_eventgrid_topic_local_auth_enabled.yaml +++ b/compliance/controls/azure/azure_eventgrid_topic_local_auth_enabled.yaml @@ -1,30 +1,30 @@ +Description: This control checks if Event Grid topics have local authentication enabled. ID: azure_eventgrid_topic_local_auth_enabled -Title: "Event Grid topics should have local authentication enabled" -Description: "This control checks if Event Grid topics have local authentication enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when disable_local_auth then 'alarm' - else 'ok' - end as status, - case - when disable_local_auth then a.name || ' local authentication disabled.' - else a.name || ' local authentication enabled.' - end as reason - from - azure_eventgrid_domain a, - azure_subscription sub; - PrimaryTable: azure_eventgrid_domain ListOfTables: - azure_eventgrid_domain - azure_subscription Parameters: [] + PrimaryTable: azure_eventgrid_domain + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN disable_local_auth THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN disable_local_auth THEN a.name || ' local authentication disabled.' + ELSE a.name || ' local authentication enabled.' + END AS reason + FROM + azure_eventgrid_domain a, + azure_subscription sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Event Grid topics should have local authentication enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_eventgrid_topic_private_link_used.yaml b/compliance/controls/azure/azure_eventgrid_topic_private_link_used.yaml old mode 100755 new mode 100644 index 7f3e6544d..9e410990e --- a/compliance/controls/azure/azure_eventgrid_topic_private_link_used.yaml +++ b/compliance/controls/azure/azure_eventgrid_topic_private_link_used.yaml @@ -1,19 +1,40 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Event Grid topic instead of the entire service, you'll also be protected against data leakage risks. ID: azure_eventgrid_topic_private_link_used -Title: "Azure Event Grid topics should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Event Grid topic instead of the entire service, you'll also be protected against data leakage risks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when public_network_access = 'Enabled' then 'alarm'\n when private_endpoint_connections is null then 'info'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then 'ok'\n else 'alarm'\n end as status,\n case\n when public_network_access = 'Enabled' then a.name || ' using public networks.'\n when private_endpoint_connections is null then a.name || ' no private link exists.'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb\n then a.name || ' using private link.'\n else a.name || ' not using private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_eventgrid_topic a,\n azure_subscription sub;\n" - PrimaryTable: azure_eventgrid_topic ListOfTables: - azure_eventgrid_topic - azure_subscription Parameters: [] + PrimaryTable: azure_eventgrid_topic + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + WHEN private_endpoint_connections IS NULL THEN 'info' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN a.name || ' using public networks.' + WHEN private_endpoint_connections IS NULL THEN a.name || ' no private link exists.' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN a.name || ' using private link.' + ELSE a.name || ' not using private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_eventgrid_topic a, + azure_subscription sub; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/EventGrid -IntegrationType: - - azure_subscription +Title: Azure Event Grid topics should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_eventhub_namespace_cmk_encryption_enabled.yaml b/compliance/controls/azure/azure_eventhub_namespace_cmk_encryption_enabled.yaml old mode 100755 new mode 100644 index 16de5c71a..c73299faa --- a/compliance/controls/azure/azure_eventhub_namespace_cmk_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_eventhub_namespace_cmk_encryption_enabled.yaml @@ -1,32 +1,32 @@ +Description: Azure Event Hubs supports the option of encrypting data at rest with either Microsoft-managed keys (default) or customer-managed keys. Choosing to encrypt data using customer-managed keys enables you to assign, rotate, disable, and revoke access to the keys that Event Hub will use to encrypt data in your namespace. Note that Event Hub only supports encryption with customer-managed keys for namespaces in dedicated clusters. ID: azure_eventhub_namespace_cmk_encryption_enabled -Title: "Event Hub namespaces should use a customer-managed key for encryption" -Description: "Azure Event Hubs supports the option of encrypting data at rest with either Microsoft-managed keys (default) or customer-managed keys. Choosing to encrypt data using customer-managed keys enables you to assign, rotate, disable, and revoke access to the keys that Event Hub will use to encrypt data in your namespace. Note that Event Hub only supports encryption with customer-managed keys for namespaces in dedicated clusters." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when encryption ->> 'keySource' = 'Microsoft.KeyVault' then 'ok' - else 'alarm' - end as status, - case - when encryption ->> 'keySource' = 'Microsoft.KeyVault' then a.name || ' CMK encryption enabled.' - else a.name || ' CMK encryption disabled.' - end as reason - from - azure_eventhub_namespace as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_eventhub_namespace ListOfTables: - azure_eventhub_namespace - azure_subscription Parameters: [] + PrimaryTable: azure_eventhub_namespace + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN encryption ->> 'keySource' = 'Microsoft.KeyVault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption ->> 'keySource' = 'Microsoft.KeyVault' THEN a.name || ' CMK encryption enabled.' + ELSE a.name || ' CMK encryption disabled.' + END AS reason + FROM + azure_eventhub_namespace AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Event Hub namespaces should use a customer-managed key for encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_eventhub_namespace_logging_enabled.yaml b/compliance/controls/azure/azure_eventhub_namespace_logging_enabled.yaml old mode 100755 new mode 100644 index f8b377100..2fe434163 --- a/compliance/controls/azure/azure_eventhub_namespace_logging_enabled.yaml +++ b/compliance/controls/azure/azure_eventhub_namespace_logging_enabled.yaml @@ -1,14 +1,63 @@ +Description: Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised. ID: azure_eventhub_namespace_logging_enabled -Title: "Resource logs in Event Hub should be enabled" -Description: "Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n distinct name as namespace_name\n from\n azure_eventhub_namespace,\n jsonb_array_elements(diagnostic_settings) setting,\n jsonb_array_elements(setting -> 'properties' -> 'logs') log\n where\n diagnostic_settings is not null\n and (\n (\n (log ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy' ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy') :: JSONB ? 'days'\n )\n or\n (\n (log ->> 'enabled') :: boolean\n and (\n log -> 'retentionPolicy' ->> 'enabled' <> 'true'\n or setting -> 'properties' ->> 'storageAccountId' = ''\n )\n )\n )\n)\nselect\n v.id as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when v.diagnostic_settings is null then 'alarm'\n when l.namespace_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when v.diagnostic_settings is null then v.name || ' logging not enabled.'\n when l.namespace_name is null then v.name || ' logging not enabled.'\n else v.name || ' logging enabled.'\n end as reason\n \n , v.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_eventhub_namespace as v\n left join logging_details as l on v.name = l.namespace_name,\n azure_subscription as sub\nwhere\n sub.subscription_id = v.subscription_id;\n" - PrimaryTable: azure_eventhub_namespace ListOfTables: - azure_eventhub_namespace - azure_subscription Parameters: [] + PrimaryTable: azure_eventhub_namespace + QueryToExecute: | + WITH logging_details AS ( + SELECT DISTINCT + name AS namespace_name + FROM + azure_eventhub_namespace, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND ( + ( + (log ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy' ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy')::JSONB ? 'days' + ) + OR + ( + (log ->> 'enabled')::BOOLEAN + AND ( + log -> 'retentionPolicy' ->> 'enabled' <> 'true' + OR setting -> 'properties' ->> 'storageAccountId' = '' + ) + ) + ) + ) + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.namespace_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.namespace_name IS NULL THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_eventhub_namespace AS v + LEFT JOIN + logging_details AS l ON v.name = l.namespace_name, + azure_subscription AS sub + WHERE + sub.subscription_id = v.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +66,4 @@ Tags: - "true" service: - Azure/EventHub -IntegrationType: - - azure_subscription +Title: Resource logs in Event Hub should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_eventhub_namespace_private_link_used.yaml b/compliance/controls/azure/azure_eventhub_namespace_private_link_used.yaml old mode 100755 new mode 100644 index 3985db5d7..d35a3c98e --- a/compliance/controls/azure/azure_eventhub_namespace_private_link_used.yaml +++ b/compliance/controls/azure/azure_eventhub_namespace_private_link_used.yaml @@ -1,19 +1,52 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. + The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. + By mapping private endpoints to Event Hub namespaces, data leakage risks are reduced. ID: azure_eventhub_namespace_private_link_used -Title: "Event Hub namespaces should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Event Hub namespaces, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with eventhub_service_connection as (\n select\n distinct a.id\n from\n azure_eventhub_namespace as a,\n jsonb_array_elements(private_endpoint_connections) as connection\n where\n connection -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when sku_tier = 'Basic' then 'skip'\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when sku_tier = 'Basic' then a.name || ' is of ' || sku_tier || ' tier.'\n when c.id is null then a.name || ' not uses private link.'\n else a.name || ' uses private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_eventhub_namespace as a\n left join eventhub_service_connection as c on c.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_eventhub_namespace ListOfTables: - azure_eventhub_namespace - azure_subscription Parameters: [] + PrimaryTable: azure_eventhub_namespace + QueryToExecute: | + WITH eventhub_service_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_eventhub_namespace AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_tier = 'Basic' THEN 'skip' + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sku_tier = 'Basic' THEN a.name || ' is of ' || sku_tier || ' tier.' + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_eventhub_namespace AS a + LEFT JOIN eventhub_service_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/EventHub -IntegrationType: - - azure_subscription +Title: Event Hub namespaces should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_eventhub_namespace_use_virtual_service_endpoint.yaml b/compliance/controls/azure/azure_eventhub_namespace_use_virtual_service_endpoint.yaml old mode 100755 new mode 100644 index 2812eb10b..6d41f02b0 --- a/compliance/controls/azure/azure_eventhub_namespace_use_virtual_service_endpoint.yaml +++ b/compliance/controls/azure/azure_eventhub_namespace_use_virtual_service_endpoint.yaml @@ -1,19 +1,48 @@ +Description: This policy audits any Event Hub not configured to use a virtual network service endpoint. ID: azure_eventhub_namespace_use_virtual_service_endpoint -Title: "Event Hub should use a virtual network service endpoint" -Description: "This policy audits any Event Hub not configured to use a virtual network service endpoint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with eventhub_namesapce_with_virtual_network as (\n select\n distinct a.id\n from\n azure_eventhub_namespace as a,\n jsonb_array_elements(network_rule_set -> 'properties' -> 'virtualNetworkRules') as rule\n where\n rule -> 'subnet' ->> 'id' is not null\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when c.id is null then a.name || ' not configured with virtual network service endpoint.'\n else a.name || ' configured with virtual network service endpoint.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_eventhub_namespace as a\n left join eventhub_namesapce_with_virtual_network as c on c.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_eventhub_namespace ListOfTables: - azure_eventhub_namespace - azure_subscription Parameters: [] + PrimaryTable: azure_eventhub_namespace + QueryToExecute: | + WITH eventhub_namespace_with_virtual_network AS ( + SELECT + DISTINCT a.id + FROM + azure_eventhub_namespace AS a, + jsonb_array_elements(network_rule_set -> 'properties' -> 'virtualNetworkRules') AS rule + WHERE + rule -> 'subnet' ->> 'id' IS NOT NULL + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.name || ' not configured with virtual network service endpoint.' + ELSE a.name || ' configured with virtual network service endpoint.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_eventhub_namespace AS a + LEFT JOIN eventhub_namespace_with_virtual_network AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/EventHub -IntegrationType: - - azure_subscription +Title: Event Hub should use a virtual network service endpoint \ No newline at end of file diff --git a/compliance/controls/azure/azure_frontdoor_waf_enabled.yaml b/compliance/controls/azure/azure_frontdoor_waf_enabled.yaml old mode 100755 new mode 100644 index 24607772f..e9867767f --- a/compliance/controls/azure/azure_frontdoor_waf_enabled.yaml +++ b/compliance/controls/azure/azure_frontdoor_waf_enabled.yaml @@ -1,19 +1,48 @@ +Description: Deploy Azure Web Application Firewall (WAF) in front of public facing web applications for additional inspection of incoming traffic. Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities such as SQL injections, Cross-Site Scripting, local and remote file executions. You can also restrict access to your web applications by countries, IP address ranges, and other http(s) parameters via custom rules. ID: azure_frontdoor_waf_enabled -Title: "Web Application Firewall (WAF) should be enabled for Azure Front Door Service" -Description: "Deploy Azure Web Application Firewall (WAF) in front of public facing web applications for additional inspection of incoming traffic. Web Application Firewall (WAF) provides centralized protection of your web applications from common exploits and vulnerabilities such as SQL injections, Cross-Site Scripting, local and remote file executions. You can also restrict access to your web applications by countries, IP address ranges, and other http(s) parameters via custom rules." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with frontdoor_with_waf as (\n select\n distinct a.front_door_id\n from\n azure_frontdoor as a,\n jsonb_array_elements(frontend_endpoints) as endpoint\n where\n endpoint -> 'properties' -> 'webApplicationFirewallPolicyLink' ->> 'id' is not null\n)\nselect\n a.front_door_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when c.front_door_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when c.front_door_id is not null then a.name || ' WAF enabled.'\n else a.name || ' WAF disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_frontdoor as a\n left join frontdoor_with_waf as c on c.front_door_id = a.front_door_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_frontdoor ListOfTables: - azure_frontdoor - azure_subscription Parameters: [] + PrimaryTable: azure_frontdoor + QueryToExecute: | + WITH frontdoor_with_waf AS ( + SELECT + DISTINCT a.front_door_id + FROM + azure_frontdoor AS a, + jsonb_array_elements(frontend_endpoints) AS endpoint + WHERE + endpoint -> 'properties' -> 'webApplicationFirewallPolicyLink' ->> 'id' IS NOT NULL + ) + SELECT + a.front_door_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.front_door_id IS NOT NULL THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN c.front_door_id IS NOT NULL THEN a.name || ' WAF enabled.' + ELSE a.name || ' WAF disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_frontdoor AS a + LEFT JOIN frontdoor_with_waf AS c ON c.front_door_id = a.front_door_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/FrontDoor -IntegrationType: - - azure_subscription +Title: Web Application Firewall (WAF) should be enabled for Azure Front Door Service \ No newline at end of file diff --git a/compliance/controls/azure/azure_hdinsight_cluster_encrypted_at_rest_with_cmk.yaml b/compliance/controls/azure/azure_hdinsight_cluster_encrypted_at_rest_with_cmk.yaml old mode 100755 new mode 100644 index a46f1a7dd..a9ff5b753 --- a/compliance/controls/azure/azure_hdinsight_cluster_encrypted_at_rest_with_cmk.yaml +++ b/compliance/controls/azure/azure_hdinsight_cluster_encrypted_at_rest_with_cmk.yaml @@ -1,19 +1,40 @@ +Description: Use customer-managed keys to manage the encryption at rest of your Azure HDInsight clusters. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_hdinsight_cluster_encrypted_at_rest_with_cmk -Title: "Azure HDInsight clusters should use customer-managed keys to encrypt data at rest" -Description: "Use customer-managed keys to manage the encryption at rest of your Azure HDInsight clusters. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when provisioning_state <> 'Succeeded' then 'skip'\n when disk_encryption_properties -> 'keyName' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when provisioning_state <> 'Succeeded' then a.name || ' is in ' || provisioning_state || ' state.'\n when disk_encryption_properties -> 'keyName' is not null then a.name || ' encrypted with CMK.'\n else a.name || ' not encrypted with CMK.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_hdinsight_cluster as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_hdinsight_cluster ListOfTables: - azure_hdinsight_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_hdinsight_cluster + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN provisioning_state <> 'Succeeded' THEN 'skip' + WHEN disk_encryption_properties -> 'keyName' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN provisioning_state <> 'Succeeded' THEN a.name || ' is in ' || provisioning_state || ' state.' + WHEN disk_encryption_properties -> 'keyName' IS NOT NULL THEN a.name || ' encrypted with CMK.' + ELSE a.name || ' not encrypted with CMK.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_hdinsight_cluster AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/HDInsight -IntegrationType: - - azure_subscription +Title: Azure HDInsight clusters should use customer-managed keys to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_hdinsight_cluster_encryption_at_host_enabled.yaml b/compliance/controls/azure/azure_hdinsight_cluster_encryption_at_host_enabled.yaml old mode 100755 new mode 100644 index 202d1867f..1d034fda1 --- a/compliance/controls/azure/azure_hdinsight_cluster_encryption_at_host_enabled.yaml +++ b/compliance/controls/azure/azure_hdinsight_cluster_encryption_at_host_enabled.yaml @@ -1,19 +1,40 @@ +Description: Enabling encryption at host helps protect and safeguard your data to meet your organizational security and compliance commitments. When you enable encryption at host, data stored on the VM host is encrypted at rest and flows encrypted to the Storage service. ID: azure_hdinsight_cluster_encryption_at_host_enabled -Title: "Azure HDInsight clusters should use encryption at host to encrypt data at rest" -Description: "Enabling encryption at host helps protect and safeguard your data to meet your organizational security and compliance commitments. When you enable encryption at host, data stored on the VM host is encrypted at rest and flows encrypted to the Storage service." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when provisioning_state <> 'Succeeded' then 'skip'\n when disk_encryption_properties -> 'encryptionAtHost' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when provisioning_state <> 'Succeeded' then a.name || ' is in ' || provisioning_state || ' state.'\n when disk_encryption_properties -> 'encryptionAtHost' = 'true' then a.name || ' uses encryption at host to encrypt data at rest.'\n else a.name || ' not uses encryption at host to encrypt data at rest.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_hdinsight_cluster as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_hdinsight_cluster ListOfTables: - azure_hdinsight_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_hdinsight_cluster + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN provisioning_state <> 'Succeeded' THEN 'skip' + WHEN disk_encryption_properties -> 'encryptionAtHost' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN provisioning_state <> 'Succeeded' THEN a.name || ' is in ' || provisioning_state || ' state.' + WHEN disk_encryption_properties -> 'encryptionAtHost' = 'true' THEN a.name || ' uses encryption at host to encrypt data at rest.' + ELSE a.name || ' not uses encryption at host to encrypt data at rest.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_hdinsight_cluster AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/HDInsight -IntegrationType: - - azure_subscription +Title: Azure HDInsight clusters should use encryption at host to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_hdinsight_cluster_encryption_in_transit_enabled.yaml b/compliance/controls/azure/azure_hdinsight_cluster_encryption_in_transit_enabled.yaml old mode 100755 new mode 100644 index 5fc2d2b8f..04192ea7b --- a/compliance/controls/azure/azure_hdinsight_cluster_encryption_in_transit_enabled.yaml +++ b/compliance/controls/azure/azure_hdinsight_cluster_encryption_in_transit_enabled.yaml @@ -1,19 +1,40 @@ +Description: Data can be tampered with during transmission between Azure HDInsight cluster nodes. Enabling encryption in transit addresses problems of misuse and tampering during this transmission. ID: azure_hdinsight_cluster_encryption_in_transit_enabled -Title: "Azure HDInsight clusters should use encryption in transit to encrypt communication between Azure HDInsight cluster nodes" -Description: "Data can be tampered with during transmission between Azure HDInsight cluster nodes. Enabling encryption in transit addresses problems of misuse and tampering during this transmission." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when provisioning_state <> 'Succeeded' then 'skip'\n when encryption_in_transit_properties -> 'isEncryptionInTransitEnabled' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when provisioning_state <> 'Succeeded' then a.name || ' is in ' || provisioning_state || ' state.'\n when encryption_in_transit_properties -> 'isEncryptionInTransitEnabled' = 'true' then a.name || ' encryption in transit enabled.'\n else a.name || ' encryption in transit disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_hdinsight_cluster as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_hdinsight_cluster ListOfTables: - azure_hdinsight_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_hdinsight_cluster + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN provisioning_state <> 'Succeeded' THEN 'skip' + WHEN encryption_in_transit_properties -> 'isEncryptionInTransitEnabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN provisioning_state <> 'Succeeded' THEN a.name || ' is in ' || provisioning_state || ' state.' + WHEN encryption_in_transit_properties -> 'isEncryptionInTransitEnabled' = 'true' THEN a.name || ' encryption in transit enabled.' + ELSE a.name || ' encryption in transit disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_hdinsight_cluster AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/HDInsight -IntegrationType: - - azure_subscription +Title: Azure HDInsight clusters should use encryption in transit to encrypt communication between Azure HDInsight cluster nodes \ No newline at end of file diff --git a/compliance/controls/azure/azure_healthcare_fhir_azure_api_encrypted_at_rest_with_cmk.yaml b/compliance/controls/azure/azure_healthcare_fhir_azure_api_encrypted_at_rest_with_cmk.yaml old mode 100755 new mode 100644 index dd114bf82..29e6e9661 --- a/compliance/controls/azure/azure_healthcare_fhir_azure_api_encrypted_at_rest_with_cmk.yaml +++ b/compliance/controls/azure/azure_healthcare_fhir_azure_api_encrypted_at_rest_with_cmk.yaml @@ -1,19 +1,42 @@ +Description: Use a customer-managed key to control the encryption at rest of the data stored + in Azure API for FHIR when this is a regulatory or compliance requirement. Customer-managed + keys also deliver double encryption by adding a second layer of encryption on top of the + default one done with service-managed keys. ID: azure_healthcare_fhir_azure_api_encrypted_at_rest_with_cmk -Title: "Azure API for FHIR should use a customer-managed key to encrypt data at rest" -Description: "Use a customer-managed key to control the encryption at rest of the data stored in Azure API for FHIR when this is a regulatory or compliance requirement. Customer-managed keys also deliver double encryption by adding a second layer of encryption on top of the default one done with service-managed keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when cosmos_db_configuration -> 'keyVaultKeyUri' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when cosmos_db_configuration -> 'keyVaultKeyUri' is not null then a.name || ' encrypted with CMK.'\n else a.name || ' not encrypted with CMK.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_healthcare_service as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_healthcare_service ListOfTables: - azure_healthcare_service - azure_subscription Parameters: [] + PrimaryTable: azure_healthcare_service + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN cosmos_db_configuration -> 'keyVaultKeyUri' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cosmos_db_configuration -> 'keyVaultKeyUri' IS NOT NULL + THEN a.name || ' encrypted with CMK.' + ELSE a.name || ' not encrypted with CMK.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_healthcare_service AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/HealthcareAPIs -IntegrationType: - - azure_subscription +Title: Azure API for FHIR should use a customer-managed key to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_healthcare_fhir_uses_private_link.yaml b/compliance/controls/azure/azure_healthcare_fhir_uses_private_link.yaml old mode 100755 new mode 100644 index fff06dd62..8ea948233 --- a/compliance/controls/azure/azure_healthcare_fhir_uses_private_link.yaml +++ b/compliance/controls/azure/azure_healthcare_fhir_uses_private_link.yaml @@ -1,19 +1,38 @@ +Description: Azure API for FHIR should have at least one approved private endpoint connection. Clients in a virtual network can securely access resources that have private endpoint connections through private links. ID: azure_healthcare_fhir_uses_private_link -Title: "Azure API for FHIR should use private link" -Description: "Azure API for FHIR should have at least one approved private endpoint connection. Clients in a virtual network can securely access resources that have private endpoint connections through private links." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when private_endpoint_connections is null then 'info'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionState\": \"Approved\"}]'::jsonb then 'ok'\n else 'alarm'\n end as status,\n case\n when private_endpoint_connections is null then a.name || ' no private link exists.'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionState\": \"Approved\"}]'::jsonb then a.name || ' using private link.'\n else a.name || ' not using private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_healthcare_service a,\n azure_subscription sub;\n" - PrimaryTable: azure_healthcare_service ListOfTables: - azure_healthcare_service - azure_subscription Parameters: [] + PrimaryTable: azure_healthcare_service + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN private_endpoint_connections IS NULL THEN 'info' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionState": "Approved"}]'::jsonb THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN private_endpoint_connections IS NULL THEN a.name || ' no private link exists.' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionState": "Approved"}]'::jsonb THEN a.name || ' using private link.' + ELSE a.name || ' not using private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_healthcare_service a, + azure_subscription sub; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/HealthcareAPIs -IntegrationType: - - azure_subscription +Title: Azure API for FHIR should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_hpc_cache_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_hpc_cache_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 967d431d2..42e9141e5 --- a/compliance/controls/azure/azure_hpc_cache_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_hpc_cache_encrypted_with_cmk.yaml @@ -1,19 +1,44 @@ +Description: Manage encryption at rest of Azure HPC Cache with customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_hpc_cache_encrypted_with_cmk -Title: "HPC Cache accounts should use customer-managed key for encryption" -Description: "Manage encryption at rest of Azure HPC Cache with customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when\n a.encryption_settings -> 'keyEncryptionKey' -> 'keyUrl' is not null\n and a.encryption_settings -> 'keyEncryptionKey' -> 'sourceVault' ->> 'id' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when\n a.encryption_settings -> 'keyEncryptionKey' -> 'keyUrl' is not null\n and a.encryption_settings -> 'keyEncryptionKey' -> 'sourceVault' ->> 'id' is not null then a.name || ' encrypted with CMK.'\n else a.name || ' not encrypted with CMK.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_hpc_cache as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_hpc_cache ListOfTables: - azure_hpc_cache - azure_subscription Parameters: [] + PrimaryTable: azure_hpc_cache + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN + a.encryption_settings -> 'keyEncryptionKey' -> 'keyUrl' IS NOT NULL + AND a.encryption_settings -> 'keyEncryptionKey' -> 'sourceVault' ->> 'id' IS NOT NULL + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN + a.encryption_settings -> 'keyEncryptionKey' -> 'keyUrl' IS NOT NULL + AND a.encryption_settings -> 'keyEncryptionKey' -> 'sourceVault' ->> 'id' IS NOT NULL + THEN a.name || ' encrypted with CMK.' + ELSE a.name || ' not encrypted with CMK.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_hpc_cache AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/HPCCache -IntegrationType: - - azure_subscription +Title: HPC Cache accounts should use customer-managed key for encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_conditional_access_mfa_enabled.yaml b/compliance/controls/azure/azure_iam_conditional_access_mfa_enabled.yaml old mode 100755 new mode 100644 index e79245288..394ddaac4 --- a/compliance/controls/azure/azure_iam_conditional_access_mfa_enabled.yaml +++ b/compliance/controls/azure/azure_iam_conditional_access_mfa_enabled.yaml @@ -1,14 +1,31 @@ +Description: For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins. ID: azure_iam_conditional_access_mfa_enabled -Title: "Ensure Multi-factor Authentication is required for Azure Management" -Description: "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n p.id as resource,\n p.og_account_id as og_account_id,\n p.og_resource_id as og_resource_id,\n case\n when p.built_in_controls @> '[\"mfa\"]' then 'ok'\n else 'alarm'\n end as status,\n case\n when p.built_in_controls @> '[\"mfa\"]' then p.display_name || ' MFA enabled.'\n else p.display_name || ' MFA disabled.'\n end as reason,\n t.tenant_id\n \nfrom\n azure_tenant as t,\n azuread_conditional_access_policy as p;\n" - PrimaryTable: azuread_conditional_access_policy ListOfTables: - azure_tenant - azuread_conditional_access_policy Parameters: [] + PrimaryTable: azuread_conditional_access_policy + QueryToExecute: | + SELECT + p.id AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.built_in_controls @> '["mfa"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.built_in_controls @> '["mfa"]' THEN p.display_name || ' MFA enabled.' + ELSE p.display_name || ' MFA disabled.' + END AS reason, + t.tenant_id + FROM + azure_tenant AS t, + azuread_conditional_access_policy AS p; Severity: medium Tags: category: @@ -29,5 +46,4 @@ Tags: - azure service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Ensure Multi-factor Authentication is required for Azure Management \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_deprecated_account.yaml b/compliance/controls/azure/azure_iam_deprecated_account.yaml old mode 100755 new mode 100644 index 927d8ef21..193554b7a --- a/compliance/controls/azure/azure_iam_deprecated_account.yaml +++ b/compliance/controls/azure/azure_iam_deprecated_account.yaml @@ -1,16 +1,49 @@ +Description: Deprecated accounts should be removed from your subscriptions. Deprecated accounts are accounts that have been blocked from signing in. ID: azure_iam_deprecated_account -Title: "Blocked accounts with read and write permissions on Azure resources should be removed" -Description: "Deprecated accounts should be removed from your subscriptions. Deprecated accounts are accounts that have been blocked from signing in." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with disabled_users as (\n select\n distinct\n u.display_name,\n u.account_enabled,\n u.user_principal_name,\n u.id,\n d.subscription_id\n from\n azuread_user as u\n left join azure_role_assignment as a on a.principal_id = u.id\n left join azure_role_definition as d on d.id = a.role_definition_id\n where not u.account_enabled\n)\nselect\n u.user_principal_name as resource,\n u.og_account_id as og_account_id,\n u.og_resource_id as og_resource_id,\n case\n when d.id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when d.id is null then u.display_name || ' sign-in enabled.'\n else u.display_name || ' sign-in disabled.'\n end as reason,\n t.tenant_id\n \nfrom\n azure_tenant as t,\n azuread_user as u\n left join disabled_users as d on d.id = u.id;\n" - PrimaryTable: azuread_user ListOfTables: - azure_role_assignment - azure_role_definition - azure_tenant - azuread_user Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + WITH disabled_users AS ( + SELECT + DISTINCT + u.display_name, + u.account_enabled, + u.user_principal_name, + u.id, + d.subscription_id + FROM + azuread_user AS u + LEFT JOIN azure_role_assignment AS a ON a.principal_id = u.id + LEFT JOIN azure_role_definition AS d ON d.id = a.role_definition_id + WHERE + NOT u.account_enabled + ) + SELECT + u.user_principal_name AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN d.id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.id IS NULL THEN u.display_name || ' sign-in enabled.' + ELSE u.display_name || ' sign-in disabled.' + END AS reason, + t.tenant_id + FROM + azure_tenant AS t, + azuread_user AS u + LEFT JOIN disabled_users AS d ON d.id = u.id; Severity: high Tags: hipaa_hitrust_v92: @@ -21,5 +54,4 @@ Tags: - "true" service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Blocked accounts with read and write permissions on Azure resources should be removed \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_deprecated_account_with_owner_roles.yaml b/compliance/controls/azure/azure_iam_deprecated_account_with_owner_roles.yaml old mode 100755 new mode 100644 index 7aa83fa77..93e48af9c --- a/compliance/controls/azure/azure_iam_deprecated_account_with_owner_roles.yaml +++ b/compliance/controls/azure/azure_iam_deprecated_account_with_owner_roles.yaml @@ -1,16 +1,37 @@ +Description: Deprecated accounts with owner permissions should be removed from your subscription. Deprecated accounts are accounts that have been blocked from signing in. ID: azure_iam_deprecated_account_with_owner_roles -Title: "Blocked accounts with owner permissions on Azure resources should be removed" -Description: "Deprecated accounts with owner permissions should be removed from your subscription. Deprecated accounts are accounts that have been blocked from signing in." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n distinct u.user_principal_name as resource,\n u.og_account_id as og_account_id,\n u.og_resource_id as og_resource_id,\n case\n when not u.account_enabled then 'alarm'\n else 'ok'\n end as status,\n case\n when not u.account_enabled then u.display_name || ' signing-in disabled state with ' || d.role_name || ' role.'\n else u.display_name || ' signing-in enabled.'\n end as reason,\n t.tenant_id\n \nfrom\n azure_tenant as t,\n azuread_user as u\n left join azure_role_assignment as a on a.principal_id = u.id\n left join azure_role_definition as d on d.id = a.role_definition_id\n -- Query checks the users with only Owner role\n where d.role_name = 'Owner';\n" - PrimaryTable: azuread_user ListOfTables: - azure_role_assignment - azure_role_definition - azure_tenant - azuread_user Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + SELECT DISTINCT + u.user_principal_name AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN NOT u.account_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT u.account_enabled THEN u.display_name || ' signing-in disabled state with ' || d.role_name || ' role.' + ELSE u.display_name || ' signing-in enabled.' + END AS reason, + t.tenant_id + FROM + azure_tenant AS t, + azuread_user AS u + LEFT JOIN azure_role_assignment AS a ON a.principal_id = u.id + LEFT JOIN azure_role_definition AS d ON d.id = a.role_definition_id + WHERE + d.role_name = 'Owner'; Severity: high Tags: hipaa_hitrust_v92: @@ -21,5 +42,4 @@ Tags: - "true" service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Blocked accounts with owner permissions on Azure resources should be removed \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_external_user_with_owner_role.yaml b/compliance/controls/azure/azure_iam_external_user_with_owner_role.yaml old mode 100755 new mode 100644 index b0d3a44e4..4b20ce901 --- a/compliance/controls/azure/azure_iam_external_user_with_owner_role.yaml +++ b/compliance/controls/azure/azure_iam_external_user_with_owner_role.yaml @@ -1,16 +1,49 @@ +Description: External accounts with owner permissions should be removed from your subscription in order to prevent unmonitored access. ID: azure_iam_external_user_with_owner_role -Title: "Guest accounts with owner permissions on Azure resources should be removed" -Description: "External accounts with owner permissions should be removed from your subscription in order to prevent unmonitored access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_owner_users as (\n select\n distinct\n u.display_name,\n d.role_name,\n u.account_enabled,\n u.user_principal_name,\n d.subscription_id,\n u.og_account_id as og_account_id,\n u.og_resource_id as og_resource_id\n from\n azuread_user as u\n left join azure_role_assignment as a on a.principal_id = u.id\n left join azure_role_definition as d on d.id = a.role_definition_id\n where d.role_name = 'Owner'\n)\nselect\n a.user_principal_name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.user_principal_name like '%EXT%' then 'alarm'\n else 'ok'\n end as status,\n case\n when a.user_principal_name like '%EXT%' then a.display_name || ' is external user with ' || a.role_name || ' role.'\n else a.display_name || ' is domain user with ' || a.role_name || ' role.'\n end as reason,\n t.tenant_id\n \nfrom\n azure_tenant as t,\n all_owner_users as a;\n" - PrimaryTable: azuread_user ListOfTables: - azure_role_assignment - azure_role_definition - azure_tenant - azuread_user Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + WITH all_owner_users AS ( + SELECT DISTINCT + u.display_name, + d.role_name, + u.account_enabled, + u.user_principal_name, + d.subscription_id, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id + FROM + azuread_user AS u + LEFT JOIN azure_role_assignment AS a ON a.principal_id = u.id + LEFT JOIN azure_role_definition AS d ON d.id = a.role_definition_id + WHERE + d.role_name = 'Owner' + ) + SELECT + a.user_principal_name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.user_principal_name LIKE '%EXT%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.user_principal_name LIKE '%EXT%' THEN a.display_name || ' is external user with ' || a.role_name || ' role.' + ELSE a.display_name || ' is domain user with ' || a.role_name || ' role.' + END AS reason, + t.tenant_id + FROM + azure_tenant AS t, + all_owner_users AS a; Severity: high Tags: hipaa_hitrust_v92: @@ -21,5 +54,4 @@ Tags: - "true" service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Guest accounts with owner permissions on Azure resources should be removed \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_external_user_with_read_permission.yaml b/compliance/controls/azure/azure_iam_external_user_with_read_permission.yaml old mode 100755 new mode 100644 index ca251eb7d..0dbbdd102 --- a/compliance/controls/azure/azure_iam_external_user_with_read_permission.yaml +++ b/compliance/controls/azure/azure_iam_external_user_with_read_permission.yaml @@ -1,16 +1,48 @@ +Description: External accounts with read privileges should be removed from your subscription in order to prevent unmonitored access. ID: azure_iam_external_user_with_read_permission -Title: "Guest accounts with read permissions on Azure resources should be removed" -Description: "External accounts with read privileges should be removed from your subscription in order to prevent unmonitored access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_write_permission_users as (\n select\n distinct\n u.display_name,\n d.role_name,\n u.account_enabled,\n u.user_principal_name,\n d.subscription_id,\n u.og_account_id as og_account_id,\n u.og_resource_id as og_resource_id\n from\n azuread_user as u\n left join azure_role_assignment as a on a.principal_id = u.id\n left join azure_role_definition as d on d.id = a.role_definition_id\n where d.role_name = 'Reader'\n)\nselect\n a.user_principal_name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.user_principal_name like '%EXT%' then 'alarm'\n else 'ok'\n end as status,\n case\n when a.user_principal_name like '%EXT%' then a.display_name || ' is external user with ' || a.role_name || ' role.'\n else a.display_name || ' is domain user with ' || a.role_name || ' role.'\n end as reason,\n t.tenant_id\n \nfrom\n azure_tenant as t,\n all_write_permission_users as a;\n" - PrimaryTable: azuread_user ListOfTables: - azure_role_assignment - azure_role_definition - azure_tenant - azuread_user Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + WITH all_write_permission_users AS ( + SELECT DISTINCT + u.display_name, + d.role_name, + u.account_enabled, + u.user_principal_name, + d.subscription_id, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id + FROM + azuread_user AS u + LEFT JOIN azure_role_assignment AS a ON a.principal_id = u.id + LEFT JOIN azure_role_definition AS d ON d.id = a.role_definition_id + WHERE d.role_name = 'Reader' + ) + SELECT + a.user_principal_name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.user_principal_name LIKE '%EXT%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.user_principal_name LIKE '%EXT%' THEN a.display_name || ' is external user with ' || a.role_name || ' role.' + ELSE a.display_name || ' is domain user with ' || a.role_name || ' role.' + END AS reason, + t.tenant_id + FROM + azure_tenant AS t, + all_write_permission_users AS a; Severity: high Tags: hipaa_hitrust_v92: @@ -21,5 +53,4 @@ Tags: - "true" service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Guest accounts with read permissions on Azure resources should be removed \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_external_user_with_write_permission.yaml b/compliance/controls/azure/azure_iam_external_user_with_write_permission.yaml old mode 100755 new mode 100644 index 4f45fc915..844629d75 --- a/compliance/controls/azure/azure_iam_external_user_with_write_permission.yaml +++ b/compliance/controls/azure/azure_iam_external_user_with_write_permission.yaml @@ -1,16 +1,50 @@ +Description: External accounts with write privileges should be removed from your subscription in order to prevent unmonitored access. ID: azure_iam_external_user_with_write_permission -Title: "Guest accounts with write permissions on Azure resources should be removed" -Description: "External accounts with write privileges should be removed from your subscription in order to prevent unmonitored access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with all_write_permission_users as (\n select\n distinct\n u.display_name,\n d.role_name,\n u.account_enabled,\n u.user_principal_name,\n d.subscription_id,\n u.og_account_id as og_account_id,\n u.og_resource_id as og_resource_id\n from\n azuread_user as u\n left join azure_role_assignment as a on a.principal_id = u.id\n left join azure_role_definition as d on d.id = a.role_definition_id\n where\n d.role_name = any(array['Owner', 'Contributor'])\n)\nselect\n a.user_principal_name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.user_principal_name like '%EXT%' then 'alarm'\n else 'ok'\n end as status,\n case\n when a.user_principal_name like '%EXT%' then a.display_name || ' is external user with ' || a.role_name || ' role.'\n else a.display_name || ' is domain user with ' || a.role_name || ' role.'\n end as reason,\n t.tenant_id\n \nfrom\n azure_tenant as t,\n all_write_permission_users as a;\n" - PrimaryTable: azuread_user ListOfTables: - azure_role_assignment - azure_role_definition - azure_tenant - azuread_user Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + WITH all_write_permission_users AS ( + SELECT + DISTINCT + u.display_name, + d.role_name, + u.account_enabled, + u.user_principal_name, + d.subscription_id, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id + FROM + azuread_user AS u + LEFT JOIN azure_role_assignment AS a ON a.principal_id = u.id + LEFT JOIN azure_role_definition AS d ON d.id = a.role_definition_id + WHERE + d.role_name = ANY(ARRAY['Owner', 'Contributor']) + ) + SELECT + a.user_principal_name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.user_principal_name LIKE '%EXT%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.user_principal_name LIKE '%EXT%' THEN a.display_name || ' is external user with ' || a.role_name || ' role.' + ELSE a.display_name || ' is domain user with ' || a.role_name || ' role.' + END AS reason, + t.tenant_id + FROM + azure_tenant AS t, + all_write_permission_users AS a; Severity: high Tags: hipaa_hitrust_v92: @@ -21,5 +55,4 @@ Tags: - "true" service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Guest accounts with write permissions on Azure resources should be removed \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_no_custom_role.yaml b/compliance/controls/azure/azure_iam_no_custom_role.yaml old mode 100755 new mode 100644 index bf4ab86be..c7f962278 --- a/compliance/controls/azure/azure_iam_no_custom_role.yaml +++ b/compliance/controls/azure/azure_iam_no_custom_role.yaml @@ -1,14 +1,49 @@ +Description: Audit built-in roles such as 'Owner, Contributor, Reader' instead of custom RBAC roles, which are error prone. Using custom roles is treated as an exception and requires a rigorous review and threat modeling. ID: azure_iam_no_custom_role -Title: "Audit usage of custom RBAC roles" -Description: "Audit built-in roles such as 'Owner, Contributor, Reader' instead of custom RBAC roles, which are error prone. Using custom roles is treated as an exception and requires a rigorous review and threat modeling." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with custom_roles as (\n select\n role_name,\n role_type,\n subscription_id,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n _ctx\n from\n azure_role_definition\n where\n role_type = 'CustomRole'\n)\nselect\n cr.subscription_id as resource,\n cr.og_account_id as og_account_id,\n cr.og_resource_id as og_resource_id,\n case\n when count(*) > 0 then 'alarm'\n else 'ok'\n end as status,\n 'There are ' || count(*) || ' custom roles.' as reason\n \n , sub.display_name as subscription\nfrom\n custom_roles as cr,\n azure_subscription as sub\nwhere\n sub.subscription_id = cr.subscription_id\ngroup by\n cr.subscription_id,\n cr._ctx,\n sub.display_name,\n cr.og_account_id,\n cr.og_resource_id " - PrimaryTable: azure_subscription ListOfTables: - azure_role_definition - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH custom_roles AS ( + SELECT + role_name, + role_type, + subscription_id, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + _ctx + FROM + azure_role_definition + WHERE + role_type = 'CustomRole' + ) + SELECT + cr.subscription_id AS resource, + cr.og_account_id AS og_account_id, + cr.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(*) > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + 'There are ' || COUNT(*) || ' custom roles.' AS reason, + sub.display_name AS subscription + FROM + custom_roles AS cr, + azure_subscription AS sub + WHERE + sub.subscription_id = cr.subscription_id + GROUP BY + cr.subscription_id, + cr._ctx, + sub.display_name, + cr.og_account_id, + cr.og_resource_id Severity: medium Tags: hipaa_hitrust_v92: @@ -19,5 +54,4 @@ Tags: - "true" service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Audit usage of custom RBAC roles \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_no_custom_subscription_owner_roles_created.yaml b/compliance/controls/azure/azure_iam_no_custom_subscription_owner_roles_created.yaml old mode 100755 new mode 100644 index 9892310df..636c9b649 --- a/compliance/controls/azure/azure_iam_no_custom_subscription_owner_roles_created.yaml +++ b/compliance/controls/azure/azure_iam_no_custom_subscription_owner_roles_created.yaml @@ -1,14 +1,58 @@ +Description: The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access. ID: azure_iam_no_custom_subscription_owner_roles_created -Title: "Ensure that no Custom Subscription Administrator roles exist" -Description: "The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with owner_custom_roles as (\n select\n role_name,\n role_type,\n title,\n action,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n _ctx,\n subscription_id\n from\n azure_role_definition,\n jsonb_array_elements(permissions) as s,\n jsonb_array_elements_text(s -> 'actions') as action\n where\n role_type = 'CustomRole'\n and action in ('*', '*:*')\n)\nselect\n cr.subscription_id as resource,\n cr.og_account_id as og_account_id,\n cr.og_resource_id as og_resource_id,\n case\n when count(*) > 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when count(*) = 1 then 'There is one custom owner role.'\n when count(*) > 1 then 'There are ' || count(*) || ' custom owner roles.'\n else 'There are no custom owner roles.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n owner_custom_roles cr,\n azure_subscription sub\nwhere\n sub.subscription_id = cr.subscription_id\ngroup by\n cr.subscription_id,\n cr.og_account_id,\n cr.og_resource_id,\n cr._ctx,\n sub.display_name;\n" - PrimaryTable: azure_subscription ListOfTables: - azure_role_definition - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH owner_custom_roles AS ( + SELECT + role_name, + role_type, + title, + action, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + _ctx, + subscription_id + FROM + azure_role_definition, + jsonb_array_elements(permissions) AS s, + jsonb_array_elements_text(s -> 'actions') AS action + WHERE + role_type = 'CustomRole' + AND action IN ('*', '*:*') + ) + SELECT + cr.subscription_id AS resource, + cr.og_account_id AS og_account_id, + cr.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(*) > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(*) = 1 THEN 'There is one custom owner role.' + WHEN COUNT(*) > 1 THEN 'There are ' || COUNT(*) || ' custom owner roles.' + ELSE 'There are no custom owner roles.' + END AS reason, + sub.display_name AS subscription + FROM + owner_custom_roles cr, + azure_subscription sub + WHERE + sub.subscription_id = cr.subscription_id + GROUP BY + cr.subscription_id, + cr.og_account_id, + cr.og_resource_id, + cr._ctx, + sub.display_name Severity: medium Tags: category: @@ -29,5 +73,4 @@ Tags: - azure service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Ensure that no Custom Subscription Administrator roles exist \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_subscription_owner_max_3.yaml b/compliance/controls/azure/azure_iam_subscription_owner_max_3.yaml old mode 100755 new mode 100644 index 7c822dd02..6f785f551 --- a/compliance/controls/azure/azure_iam_subscription_owner_max_3.yaml +++ b/compliance/controls/azure/azure_iam_subscription_owner_max_3.yaml @@ -1,15 +1,56 @@ +Description: It is recommended to designate up to 3 subscription owners in order to reduce the potential for breach by a compromised owner. ID: azure_iam_subscription_owner_max_3 -Title: "A maximum of 3 owners should be designated for your subscription" -Description: "It is recommended to designate up to 3 subscription owners in order to reduce the potential for breach by a compromised owner." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with owner_roles as (\n select\n d.role_name,\n d.role_type,\n d.name,\n d.title,\n d.og_account_id as og_account_id,\n d.og_resource_id as og_resource_id,\n d._ctx,\n d.subscription_id\n from\n azure_role_definition as d\n left join azure_role_assignment as a on d.id = a.role_definition_id\n where\n d.role_name = 'Owner'\n)\nselect\n owner.subscription_id as resource,\n owner.og_account_id as og_account_id,\n owner.og_resource_id as og_resource_id,\n case\n when count(*) <= 3 then 'ok'\n else 'alarm'\n end as status,\n count(*) || ' owner(s) associated.' as reason\n \n , sub.display_name as subscription\nfrom\n owner_roles as owner,\n azure_subscription as sub\nwhere\n sub.subscription_id =owner.subscription_id\ngroup by\n owner.subscription_id,\n owner.og_account_id,\n owner.og_resource_id,\n owner._ctx,\n sub.display_name;\n" - PrimaryTable: azure_subscription ListOfTables: - azure_role_assignment - azure_role_definition - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH owner_roles AS ( + SELECT + d.role_name, + d.role_type, + d.name, + d.title, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + d._ctx, + d.subscription_id + FROM + azure_role_definition AS d + LEFT JOIN + azure_role_assignment AS a + ON + d.id = a.role_definition_id + WHERE + d.role_name = 'Owner' + ) + SELECT + owner.subscription_id AS resource, + owner.og_account_id AS og_account_id, + owner.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(*) <= 3 THEN 'ok' + ELSE 'alarm' + END AS status, + COUNT(*) || ' owner(s) associated.' AS reason, + sub.display_name AS subscription + FROM + owner_roles AS owner, + azure_subscription AS sub + WHERE + sub.subscription_id = owner.subscription_id + GROUP BY + owner.subscription_id, + owner.og_account_id, + owner.og_resource_id, + owner._ctx, + sub.display_name Severity: medium Tags: hipaa_hitrust_v92: @@ -20,5 +61,4 @@ Tags: - "true" service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: A maximum of 3 owners should be designated for your subscription \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_subscription_owner_more_than_1.yaml b/compliance/controls/azure/azure_iam_subscription_owner_more_than_1.yaml old mode 100755 new mode 100644 index 975491f5c..16067b3bb --- a/compliance/controls/azure/azure_iam_subscription_owner_more_than_1.yaml +++ b/compliance/controls/azure/azure_iam_subscription_owner_more_than_1.yaml @@ -1,15 +1,53 @@ +Description: It is recommended to designate more than one subscription owner in order to have administrator access redundancy. ID: azure_iam_subscription_owner_more_than_1 -Title: "There should be more than one owner assigned to your subscription" -Description: "It is recommended to designate more than one subscription owner in order to have administrator access redundancy." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with owner_roles as (\n select\n d.role_name,\n d.role_type,\n d.name,\n d.title,\n d.og_account_id as og_account_id,\n d.og_resource_id as og_resource_id,\n d._ctx,\n d.subscription_id\n from\n azure_role_definition as d\n left join azure_role_assignment as a on d.id = a.role_definition_id\n where\n d.role_name = 'Owner'\n)\nselect\n owner.subscription_id as resource,\n owner.og_account_id as og_account_id,\n owner.og_resource_id as og_resource_id,\n case\n when count(*) > 1 then 'ok'\n else 'alarm'\n end as status,\n count(*) || ' owner(s) associated.' as reason\n \n , sub.display_name as subscription\nfrom\n owner_roles as owner,\n azure_subscription as sub\nwhere\n sub.subscription_id =owner.subscription_id\ngroup by\n owner.subscription_id,\n owner.og_account_id,\n owner.og_resource_id,\n owner._ctx,\n sub.display_name;\n" - PrimaryTable: azure_subscription ListOfTables: - azure_role_assignment - azure_role_definition - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH owner_roles AS ( + SELECT + d.role_name, + d.role_type, + d.name, + d.title, + d.og_account_id AS og_account_id, + d.og_resource_id AS og_resource_id, + d._ctx, + d.subscription_id + FROM + azure_role_definition AS d + LEFT JOIN azure_role_assignment AS a ON d.id = a.role_definition_id + WHERE + d.role_name = 'Owner' + ) + SELECT + owner.subscription_id AS resource, + owner.og_account_id AS og_account_id, + owner.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(*) > 1 THEN 'ok' + ELSE 'alarm' + END AS status, + COUNT(*) || ' owner(s) associated.' AS reason, + sub.display_name AS subscription + FROM + owner_roles AS owner, + azure_subscription AS sub + WHERE + sub.subscription_id = owner.subscription_id + GROUP BY + owner.subscription_id, + owner.og_account_id, + owner.og_resource_id, + owner._ctx, + sub.display_name Severity: medium Tags: hipaa_hitrust_v92: @@ -18,5 +56,4 @@ Tags: - "true" service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: There should be more than one owner assigned to your subscription \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_subscriptions_with_custom_roles_no_overly_permissive.yaml b/compliance/controls/azure/azure_iam_subscriptions_with_custom_roles_no_overly_permissive.yaml old mode 100755 new mode 100644 index 9387b6f3f..904cfe718 --- a/compliance/controls/azure/azure_iam_subscriptions_with_custom_roles_no_overly_permissive.yaml +++ b/compliance/controls/azure/azure_iam_subscriptions_with_custom_roles_no_overly_permissive.yaml @@ -1,56 +1,54 @@ +Description: This policy identifies azure subscriptions with custom roles that are overly permissive. Least privilege access rule should be followed and only necessary privileges should be assigned instead of allowing full administrative access. ID: azure_iam_subscriptions_with_custom_roles_no_overly_permissive -Title: "Subscriptions with custom roles should not be overly permissive" -Description: "This policy identifies azure subscriptions with custom roles are overly permissive. Least privilege access rule should be followed and only necessary privileges should be assigned instead of allowing full administrative access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with custom_roles as ( - select + ListOfTables: + - azure_role_definition + - azure_subscription + Parameters: [] + PrimaryTable: azure_role_definition + QueryToExecute: | + WITH custom_roles AS ( + SELECT role_name, role_type, title, action, _ctx, subscription_id - from + FROM azure_role_definition, - jsonb_array_elements(permissions) as s, - jsonb_array_elements_text(s -> 'actions') as action - where + jsonb_array_elements(permissions) AS s, + jsonb_array_elements_text(s -> 'actions') AS action + WHERE role_type = 'CustomRole' - and assignable_scopes @> '["/"]' - and action in ('*', '*:*') + AND assignable_scopes @> '["/"]' + AND action IN ('*', '*:*') ) - select - cr.subscription_id as resource, - cr.og_account_id as og_account_id, - cr.og_resource_id as og_resource_id, - case - when count(*) > 0 then 'alarm' - else 'ok' - end as status, - case - when count(*) = 1 then 'There is one subscription where custom roles are overly permissive.' - when count(*) > 1 then 'There are ' || count(*) || ' subscriptions where custom roles are overly permissive.' - else 'There is no subscription where custom roles are overly permissive.' - end as reason - from + SELECT + cr.subscription_id AS resource, + cr.og_account_id AS og_account_id, + cr.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(*) > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(*) = 1 THEN 'There is one subscription where custom roles are overly permissive.' + WHEN COUNT(*) > 1 THEN 'There are ' || COUNT(*) || ' subscriptions where custom roles are overly permissive.' + ELSE 'There is no subscription where custom roles are overly permissive.' + END AS reason + FROM custom_roles cr, azure_subscription sub - where + WHERE sub.subscription_id = cr.subscription_id - group by + GROUP BY cr.subscription_id, cr._ctx, sub.display_name; - ``` - PrimaryTable: azure_role_definition - ListOfTables: - - azure_role_definition - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Subscriptions with custom roles should not be overly permissive \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_user_no_built_in_contributor_role.yaml b/compliance/controls/azure/azure_iam_user_no_built_in_contributor_role.yaml old mode 100755 new mode 100644 index 2414636fa..f773eb054 --- a/compliance/controls/azure/azure_iam_user_no_built_in_contributor_role.yaml +++ b/compliance/controls/azure/azure_iam_user_no_built_in_contributor_role.yaml @@ -1,55 +1,56 @@ +Description: Ensure that IAM user does not have built in contributor role. This rule is non-compliant if IAM user have built in contributor role. ID: azure_iam_user_no_built_in_contributor_role -Title: "IAM users should not have built in contributor role" -Description: "Ensure that IAM user does not have built in contributor role. This rule is non-compliant if IAM user have built in contributor role." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with all_contributor_permission_users as ( - select - distinct + ListOfTables: + - azuread_user + - azure_role_assignment + - azure_role_definition + - azure_tenant + Parameters: [] + PrimaryTable: azuread_user + QueryToExecute: | + WITH all_contributor_permission_users AS ( + SELECT + DISTINCT u.display_name, d.role_name, u.account_enabled, u.user_principal_name, d.subscription_id - from - azuread_user as u - left join azure_role_assignment as a on a.principal_id = u.id - left join azure_role_definition as d on d.id = a.role_definition_id - where + FROM + azuread_user AS u + LEFT JOIN azure_role_assignment AS a ON a.principal_id = u.id + LEFT JOIN azure_role_definition AS d ON d.id = a.role_definition_id + WHERE d.role_name = 'Contributor' - ), distinct_tenant as ( - select - distinct tenant_id, + ), distinct_tenant AS ( + SELECT + DISTINCT tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - u.user_principal_name as resource, - u.og_account_id as og_account_id, - u.og_resource_id as og_resource_id, - case - when c.user_principal_name is not null then 'alarm' - else 'ok' - end as status, - case - when c.user_principal_name is not null then u.display_name || ' has contributor role assigned.' - else u.display_name || ' does not have contributor role assigned.' - end as reason, + SELECT + u.user_principal_name AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN c.user_principal_name IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.user_principal_name IS NOT NULL THEN u.display_name || ' has contributor role assigned.' + ELSE u.display_name || ' does not have contributor role assigned.' + END AS reason, t.tenant_id - from - distinct_tenant as t, - azuread_user as u left join all_contributor_permission_users as c on c.user_principal_name = u.user_principal_name; - PrimaryTable: azuread_user - ListOfTables: - - azuread_user - - azure_role_assignment - - azure_role_definition - - azure_tenant - Parameters: [] + FROM + distinct_tenant AS t, + azuread_user AS u + LEFT JOIN all_contributor_permission_users AS c ON c.user_principal_name = u.user_principal_name; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: IAM users should not have built in contributor role \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_user_not_allowed_to_create_security_group.yaml b/compliance/controls/azure/azure_iam_user_not_allowed_to_create_security_group.yaml old mode 100755 new mode 100644 index ed47785f4..13bfdc44b --- a/compliance/controls/azure/azure_iam_user_not_allowed_to_create_security_group.yaml +++ b/compliance/controls/azure/azure_iam_user_not_allowed_to_create_security_group.yaml @@ -1,14 +1,31 @@ +Description: Restrict security group creation to administrators only. ID: azure_iam_user_not_allowed_to_create_security_group -Title: "Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No'" -Description: "Restrict security group creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' then a.display_name || ' does not allow user to create security groups.'\n else a.display_name || ' allows user to create security groups.'\n end as reason,\n t.tenant_id\n \nfrom\n azure_tenant as t,\n azuread_authorization_policy as a;\n" - PrimaryTable: azuread_authorization_policy ListOfTables: - azure_tenant - azuread_authorization_policy Parameters: [] + PrimaryTable: azuread_authorization_policy + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateSecurityGroups' = 'false' THEN a.display_name || ' does not allow user to create security groups.' + ELSE a.display_name || ' allows user to create security groups.' + END AS reason, + t.tenant_id + FROM + azure_tenant AS t, + azuread_authorization_policy AS a; Severity: high Tags: category: @@ -29,5 +46,4 @@ Tags: - azure service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Ensure that 'Users can create security groups in Azure portals, API or PowerShell' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_user_not_allowed_to_create_tenants.yaml b/compliance/controls/azure/azure_iam_user_not_allowed_to_create_tenants.yaml old mode 100755 new mode 100644 index d62df627e..e6db54fa7 --- a/compliance/controls/azure/azure_iam_user_not_allowed_to_create_tenants.yaml +++ b/compliance/controls/azure/azure_iam_user_not_allowed_to_create_tenants.yaml @@ -1,39 +1,39 @@ +Description: Restrict tenant creation to administrators only. ID: azure_iam_user_not_allowed_to_create_tenants -Title: "Ensure that 'Users Can Create Tenants' is set to 'No'" -Description: "Restrict tenant creation to administrators only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with distinct_tenant as ( - select - distinct tenant_id, + ListOfTables: + - azure_tenant + - azuread_authorization_policy + Parameters: [] + PrimaryTable: azuread_authorization_policy + QueryToExecute: | + WITH distinct_tenant AS ( + SELECT + DISTINCT tenant_id, subscription_id, _ctx - from + FROM azure_tenant ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when a.default_user_role_permissions ->> 'allowedToCreateTenants' = 'true' then 'alarm' - else 'ok' - end as status, - case - when a.default_user_role_permissions ->> 'allowedToCreateTenants' = 'true' then a.display_name || ' allows user to create tenants.' - else a.display_name || ' restricts the user to create tenants.' - end as reason, + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateTenants' = 'true' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateTenants' = 'true' THEN a.display_name || ' allows user to create tenants.' + ELSE a.display_name || ' restricts the user to create tenants.' + END AS reason, t.tenant_id - from - distinct_tenant as t, - azuread_authorization_policy as a; - PrimaryTable: azuread_authorization_policy - ListOfTables: - - azure_tenant - - azuread_authorization_policy - Parameters: [] + FROM + distinct_tenant AS t, + azuread_authorization_policy AS a; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Ensure that 'Users Can Create Tenants' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_user_not_allowed_to_register_application.yaml b/compliance/controls/azure/azure_iam_user_not_allowed_to_register_application.yaml old mode 100755 new mode 100644 index 76fb8bc67..1544334d2 --- a/compliance/controls/azure/azure_iam_user_not_allowed_to_register_application.yaml +++ b/compliance/controls/azure/azure_iam_user_not_allowed_to_register_application.yaml @@ -1,14 +1,32 @@ +Description: Require administrators or appropriately delegated users to register third-party applications. ID: azure_iam_user_not_allowed_to_register_application -Title: "Ensure that 'Users Can Register Applications' is set to 'No'" -Description: "Require administrators or appropriately delegated users to register third-party applications." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' then a.display_name || ' does not allow user to register applications.'\n else a.display_name || ' allows user to register applications.'\n end as reason,\n t.tenant_id\n \nfrom\n azure_tenant as t,\n azuread_authorization_policy as a;\n" - PrimaryTable: azuread_authorization_policy ListOfTables: - azure_tenant - azuread_authorization_policy Parameters: [] + PrimaryTable: azuread_authorization_policy + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.default_user_role_permissions ->> 'allowedToCreateApps' = 'false' + THEN a.display_name || ' does not allow user to register applications.' + ELSE a.display_name || ' allows user to register applications.' + END AS reason, + t.tenant_id + FROM + azure_tenant AS t, + azuread_authorization_policy AS a; Severity: medium Tags: category: @@ -29,5 +47,4 @@ Tags: - azure service: - Azure/ActiveDirectory -IntegrationType: - - azure_subscription +Title: Ensure that 'Users Can Register Applications' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_user_with_owner_permission_on_subscription_mfa_enabled.yaml b/compliance/controls/azure/azure_iam_user_with_owner_permission_on_subscription_mfa_enabled.yaml old mode 100755 new mode 100644 index 8dba74343..ba1033f09 --- a/compliance/controls/azure/azure_iam_user_with_owner_permission_on_subscription_mfa_enabled.yaml +++ b/compliance/controls/azure/azure_iam_user_with_owner_permission_on_subscription_mfa_enabled.yaml @@ -1,24 +1,24 @@ +Description: Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with owner permissions to prevent a breach of accounts or resources. ID: azure_iam_user_with_owner_permission_on_subscription_mfa_enabled -Title: "Accounts with owner permissions on Azure resources should be MFA enabled" -Description: "Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with owner permissions to prevent a breach of accounts or resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Accounts with owner permissions on Azure resources should be MFA enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_user_with_read_permission_on_subscription_mfa_enabled.yaml b/compliance/controls/azure/azure_iam_user_with_read_permission_on_subscription_mfa_enabled.yaml old mode 100755 new mode 100644 index 77f364a45..3def49d4b --- a/compliance/controls/azure/azure_iam_user_with_read_permission_on_subscription_mfa_enabled.yaml +++ b/compliance/controls/azure/azure_iam_user_with_read_permission_on_subscription_mfa_enabled.yaml @@ -1,24 +1,24 @@ +Description: Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with read privileges to prevent a breach of accounts or resources. ID: azure_iam_user_with_read_permission_on_subscription_mfa_enabled -Title: "Accounts with read permissions on Azure resources should be MFA enabled" -Description: "Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with read privileges to prevent a breach of accounts or resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Accounts with read permissions on Azure resources should be MFA enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_iam_user_with_write_permission_on_subscription_mfa_enabled.yaml b/compliance/controls/azure/azure_iam_user_with_write_permission_on_subscription_mfa_enabled.yaml old mode 100755 new mode 100644 index e3c14f92b..0b675e640 --- a/compliance/controls/azure/azure_iam_user_with_write_permission_on_subscription_mfa_enabled.yaml +++ b/compliance/controls/azure/azure_iam_user_with_write_permission_on_subscription_mfa_enabled.yaml @@ -1,24 +1,24 @@ +Description: Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with write privileges to prevent a breach of accounts or resources. ID: azure_iam_user_with_write_permission_on_subscription_mfa_enabled -Title: "Accounts with write permissions on Azure resources should be MFA enabled" -Description: "Multi-Factor Authentication (MFA) should be enabled for all subscription accounts with write privileges to prevent a breach of accounts or resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Accounts with write permissions on Azure resources should be MFA enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_iot_hub_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_iot_hub_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index b01e1faf7..ac1be401f --- a/compliance/controls/azure/azure_iot_hub_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_iot_hub_encrypted_with_cmk.yaml @@ -1,24 +1,24 @@ +Description: Use customer-managed keys to manage the encryption at rest of your IoT Hub device provisioning service. The data is automatically encrypted at rest with service-managed keys, but customer-managed keys (CMK) are commonly required to meet regulatory compliance standards. CMKs enable the data to be encrypted with an Azure Key Vault key created and owned by you. Learn more about CMK encryption at https://aka.ms/dps/CMK. ID: azure_iot_hub_encrypted_with_cmk -Title: "IoT Hub device provisioning service data should be encrypted using customer-managed keys (CMK)" -Description: "Use customer-managed keys to manage the encryption at rest of your IoT Hub device provisioning service. The data is automatically encrypted at rest with service-managed keys, but customer-managed keys (CMK) are commonly required to meet regulatory compliance standards. CMKs enable the data to be encrypted with an Azure Key Vault key created and owned by you. Learn more about CMK encryption at https://aka.ms/dps/CMK." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: IoT Hub device provisioning service data should be encrypted using customer-managed keys (CMK) \ No newline at end of file diff --git a/compliance/controls/azure/azure_iot_hub_logging_enabled.yaml b/compliance/controls/azure/azure_iot_hub_logging_enabled.yaml old mode 100755 new mode 100644 index 65fb8c458..be90539be --- a/compliance/controls/azure/azure_iot_hub_logging_enabled.yaml +++ b/compliance/controls/azure/azure_iot_hub_logging_enabled.yaml @@ -1,14 +1,59 @@ +Description: Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised. ID: azure_iot_hub_logging_enabled -Title: "Resource logs in IoT Hub should be enabled" -Description: "Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n distinct id as id\n from\n azure_iothub,\n jsonb_array_elements(diagnostic_settings) setting,\n jsonb_array_elements(setting -> 'properties' -> 'logs') log\n where\n diagnostic_settings is not null\n and (\n (\n (log ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy' ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy') :: JSONB ? 'days'\n )\n or\n (\n (log ->> 'enabled') :: boolean\n and log -> 'retentionPolicy' ->> 'enabled' <> 'true'\n )\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.diagnostic_settings is null then 'alarm'\n when l.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.diagnostic_settings is null then a.name || ' logging disabled.'\n when l.id is not null then a.name || ' logging enabled.'\n else a.name || ' logging disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_iothub as a\n left join logging_details as l on a.id = l.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_iothub ListOfTables: - azure_iothub - azure_subscription Parameters: [] + PrimaryTable: azure_iothub + QueryToExecute: | + WITH logging_details AS ( + SELECT + DISTINCT id AS id + FROM + azure_iothub, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND ( + ( + (log ->> 'enabled')::boolean + AND (log -> 'retentionPolicy' ->> 'enabled')::boolean + AND (log -> 'retentionPolicy')::jsonb ? 'days' + ) + OR + ( + (log ->> 'enabled')::boolean + AND log -> 'retentionPolicy' ->> 'enabled' <> 'true' + ) + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.diagnostic_settings IS NULL THEN a.name || ' logging disabled.' + WHEN l.id IS NOT NULL THEN a.name || ' logging enabled.' + ELSE a.name || ' logging disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_iothub AS a + LEFT JOIN logging_details AS l ON a.id = l.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +62,4 @@ Tags: - "true" service: - Azure/IoTHub -IntegrationType: - - azure_subscription +Title: Resource logs in IoT Hub should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_certificate_validity_12_months.yaml b/compliance/controls/azure/azure_keyvault_certificate_validity_12_months.yaml old mode 100755 new mode 100644 index 4c2ee2074..5a832cc19 --- a/compliance/controls/azure/azure_keyvault_certificate_validity_12_months.yaml +++ b/compliance/controls/azure/azure_keyvault_certificate_validity_12_months.yaml @@ -1,24 +1,24 @@ +Description: Manage your organizational compliance requirements by specifying the maximum amount of time that a certificate can be valid within your key vault. ID: azure_keyvault_certificate_validity_12_months -Title: "Certificates should have the specified maximum validity period" -Description: "Manage your organizational compliance requirements by specifying the maximum amount of time that a certificate can be valid within your key vault." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Certificates should have the specified maximum validity period \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_firewall_enabled.yaml b/compliance/controls/azure/azure_keyvault_firewall_enabled.yaml old mode 100755 new mode 100644 index c1f89ca4d..d6093036a --- a/compliance/controls/azure/azure_keyvault_firewall_enabled.yaml +++ b/compliance/controls/azure/azure_keyvault_firewall_enabled.yaml @@ -1,32 +1,32 @@ +Description: Enable the key vault firewall so that the key vault is not accessible by default to any public IPs. Optionally, you can configure specific IP ranges to limit access to those networks. ID: azure_keyvault_firewall_enabled -Title: "Azure Key Vault should have firewall enabled" -Description: "Enable the key vault firewall so that the key vault is not accessible by default to any public IPs. Optionally, you can configure specific IP ranges to limit access to those networks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when jsonb_array_length(network_acls -> 'ipRules') > 0 then 'ok' - else 'alarm' - end as status, - case - when jsonb_array_length(network_acls -> 'ipRules') > 0 then name || ' firewall enabled.' - else name || ' firewall disabled.' - end as reason - from - azure_key_vault kv, - azure_subscription sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(network_acls -> 'ipRules') > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(network_acls -> 'ipRules') > 0 THEN name || ' firewall enabled.' + ELSE name || ' firewall disabled.' + END AS reason + FROM + azure_key_vault kv, + azure_subscription sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Azure Key Vault should have firewall enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_key_expiration_set.yaml b/compliance/controls/azure/azure_keyvault_key_expiration_set.yaml old mode 100755 new mode 100644 index 2bfb076f8..6a13f4000 --- a/compliance/controls/azure/azure_keyvault_key_expiration_set.yaml +++ b/compliance/controls/azure/azure_keyvault_key_expiration_set.yaml @@ -1,14 +1,36 @@ +Description: Cryptographic keys should have a defined expiration date and not be permanent. Keys that are valid forever provide a potential attacker with more time to compromise the key. It is a recommended security practice to set expiration dates on cryptographic keys. ID: azure_keyvault_key_expiration_set -Title: "Key Vault keys should have an expiration date" -Description: "Cryptographic keys should have a defined expiration date and not be permanent. Keys that are valid forever provide a potential attacker with more time to compromise the key. It is a recommended security practice to set expiration dates on cryptographic keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kvk.id as resource,\n kvk.og_account_id as og_account_id,\n kvk.og_resource_id as og_resource_id,\n case\n when enabled and expires_at is null then 'alarm'\n else 'ok'\n end as status,\n vault_name || ' key ' || name ||\n case\n when enabled and expires_at is null then ' expiration date not set.'\n when not enabled then ' disabled.'\n else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.'\n end as reason\n \n , kvk.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault_key kvk,\n azure_subscription sub\nwhere\n sub.subscription_id = kvk.subscription_id;\n" - PrimaryTable: azure_key_vault_key ListOfTables: - azure_key_vault_key - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + vault_name || ' key ' || name || + CASE + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason, + kvk.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_key kvk, + azure_subscription sub + WHERE + sub.subscription_id = kvk.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Key Vault keys should have an expiration date \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_logging_enabled.yaml b/compliance/controls/azure/azure_keyvault_logging_enabled.yaml old mode 100755 new mode 100644 index 7d8026818..0088cd1c4 --- a/compliance/controls/azure/azure_keyvault_logging_enabled.yaml +++ b/compliance/controls/azure/azure_keyvault_logging_enabled.yaml @@ -1,51 +1,51 @@ +Description: Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes when a security incident occurs or when your network is compromised. ID: azure_keyvault_logging_enabled -Title: "Resource logs in Key Vault should be enabled" -Description: "Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes when a security incident occurs or when your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_key_vault + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault QueryToExecute: | - with logging_details as ( - select - name as key_vault_name - from + WITH logging_details AS ( + SELECT + name AS key_vault_name + FROM azure_key_vault, jsonb_array_elements(diagnostic_settings) setting, jsonb_array_elements(setting -> 'properties' -> 'logs') log - where - diagnostic_settings is not null - and setting -> 'properties' ->> 'storageAccountId' <> '' - and (log ->> 'enabled') :: boolean - and log ->> 'category' = 'AuditEvent' - and (log -> 'retentionPolicy') :: JSONB ? 'days' + WHERE + diagnostic_settings IS NOT NULL + AND setting -> 'properties' ->> 'storageAccountId' <> '' + AND (log ->> 'enabled')::BOOLEAN + AND log ->> 'category' = 'AuditEvent' + AND (log -> 'retentionPolicy')::JSONB ? 'days' ) - select - v.id as resource, - v.og_account_id as og_account_id, - v.og_resource_id as og_resource_id, - case - when v.diagnostic_settings is null then 'alarm' - when l.key_vault_name not like concat('%', v.name, '%') then 'alarm' - else 'ok' - end as status, - case - when v.diagnostic_settings is null then v.name || ' logging not enabled.' - when l.key_vault_name not like concat('%', v.name, '%') then v.name || ' logging not enabled.' - else v.name || ' logging enabled.' - end as reason - - , v.resource_group as resource_group - , sub.display_name as subscription - from + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM azure_key_vault v - left join + LEFT JOIN logging_details l ON l.key_vault_name = v.name - join + JOIN azure_subscription sub ON sub.subscription_id = v.subscription_id; - PrimaryTable: azure_key_vault - ListOfTables: - - azure_key_vault - - azure_subscription - Parameters: [] Severity: high Tags: category: @@ -68,5 +68,4 @@ Tags: - Azure KeyVault score_tags: - Observability -IntegrationType: - - azure_subscription +Title: Resource logs in Key Vault should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_managed_hms_logging_enabled.yaml b/compliance/controls/azure/azure_keyvault_managed_hms_logging_enabled.yaml old mode 100755 new mode 100644 index 10a4bafd7..1edd190bf --- a/compliance/controls/azure/azure_keyvault_managed_hms_logging_enabled.yaml +++ b/compliance/controls/azure/azure_keyvault_managed_hms_logging_enabled.yaml @@ -1,19 +1,56 @@ +Description: To recreate activity trails for investigation purposes when a security incident occurs or when your network is compromised, you may want to audit by enabling resource logs on Managed HSMs. ID: azure_keyvault_managed_hms_logging_enabled -Title: "Resource logs in Azure Key Vault Managed HSM should be enabled" -Description: "To recreate activity trails for investigation purposes when a security incident occurs or when your network is compromised, you may want to audit by enabling resource logs on Managed HSMs." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n name as key_vault_name\n from\n azure_key_vault_managed_hardware_security_module,\n jsonb_array_elements(diagnostic_settings) setting,\n jsonb_array_elements(setting -> 'properties' -> 'logs') log\n where\n diagnostic_settings is not null\n and setting -> 'properties' ->> 'storageAccountId' <> ''\n and (log ->> 'enabled') :: boolean\n and log ->> 'category' = 'AuditEvent'\n and (log -> 'retentionPolicy') :: JSONB ? 'days'\n)\nselect\n v.id as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when v.diagnostic_settings is null then 'alarm'\n when l.key_vault_name not like concat('%', v.name, '%') then 'alarm'\n else 'ok'\n end as status,\n case\n when v.diagnostic_settings is null then v.name || ' logging not enabled.'\n when l.key_vault_name not like concat('%', v.name, '%')\n then v.name || ' logging not enabled.'\n else v.name || ' logging enabled.'\n end as reason\n \n , v.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault_managed_hardware_security_module as v,\n logging_details as l,\n azure_subscription as sub\nwhere\n sub.subscription_id = v.subscription_id;\n" - PrimaryTable: azure_key_vault_managed_hardware_security_module ListOfTables: - azure_key_vault_managed_hardware_security_module - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_managed_hardware_security_module + QueryToExecute: | + WITH logging_details AS ( + SELECT + name AS key_vault_name + FROM + azure_key_vault_managed_hardware_security_module, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND setting -> 'properties' ->> 'storageAccountId' <> '' + AND (log ->> 'enabled')::BOOLEAN + AND log ->> 'category' = 'AuditEvent' + AND (log -> 'retentionPolicy')::JSONB ? 'days' + ) + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.key_vault_name NOT LIKE CONCAT('%', v.name, '%') + THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_managed_hardware_security_module AS v, + logging_details AS l, + azure_subscription AS sub + WHERE + sub.subscription_id = v.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Resource logs in Azure Key Vault Managed HSM should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_managed_hms_purge_protection_enabled.yaml b/compliance/controls/azure/azure_keyvault_managed_hms_purge_protection_enabled.yaml old mode 100755 new mode 100644 index 087a0c08a..91151842e --- a/compliance/controls/azure/azure_keyvault_managed_hms_purge_protection_enabled.yaml +++ b/compliance/controls/azure/azure_keyvault_managed_hms_purge_protection_enabled.yaml @@ -1,19 +1,38 @@ +Description: Malicious deletion of an Azure Key Vault Managed HSM can lead to permanent data loss. A malicious insider in your organization can potentially delete and purge Azure Key Vault Managed HSM. Purge protection protects you from insider attacks by enforcing a mandatory retention period for soft deleted Azure Key Vault Managed HSM. No one inside your organization or Microsoft will be able to purge your Azure Key Vault Managed HSM during the soft delete retention period. ID: azure_keyvault_managed_hms_purge_protection_enabled -Title: "Azure Key Vault Managed HSM should have purge protection enabled" -Description: "Malicious deletion of an Azure Key Vault Managed HSM can lead to permanent data loss. A malicious insider in your organization can potentially delete and purge Azure Key Vault Managed HSM. Purge protection protects you from insider attacks by enforcing a mandatory retention period for soft deleted Azure Key Vault Managed HSM. No one inside your organization or Microsoft will be able to purge your Azure Key Vault Managed HSM during the soft delete retention period." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kv.id as resource,\n kv.og_account_id as og_account_id,\n kv.og_resource_id as og_resource_id,\n case\n when enable_purge_protection then 'ok'\n else 'alarm'\n end as status,\n case\n when enable_purge_protection then name || ' purge protection enabled.'\n else name || ' purge protection disabled.'\n end as reason\n \n , kv.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault_managed_hardware_security_module as kv,\n azure_subscription as sub\nwhere\n sub.subscription_id = kv.subscription_id;\n" - PrimaryTable: azure_key_vault_managed_hardware_security_module ListOfTables: - azure_key_vault_managed_hardware_security_module - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_managed_hardware_security_module + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN enable_purge_protection THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_purge_protection THEN name || ' purge protection enabled.' + ELSE name || ' purge protection disabled.' + END AS reason, + kv.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_managed_hardware_security_module AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: critical Tags: hipaa_hitrust_v92: - "true" service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Azure Key Vault Managed HSM should have purge protection enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_purge_protection_enabled.yaml b/compliance/controls/azure/azure_keyvault_purge_protection_enabled.yaml old mode 100755 new mode 100644 index d4b94a5aa..25e1dcab6 --- a/compliance/controls/azure/azure_keyvault_purge_protection_enabled.yaml +++ b/compliance/controls/azure/azure_keyvault_purge_protection_enabled.yaml @@ -1,14 +1,34 @@ +Description: Malicious deletion of a key vault can lead to permanent data loss. A malicious insider in your organization can potentially delete and purge key vaults. Purge protection protects you from insider attacks by enforcing a mandatory retention period for soft deleted key vaults. No one inside your organization or Microsoft will be able to purge your key vaults during the soft delete retention period. ID: azure_keyvault_purge_protection_enabled -Title: "Key vaults should have deletion protection enabled" -Description: "Malicious deletion of a key vault can lead to permanent data loss. A malicious insider in your organization can potentially delete and purge key vaults. Purge protection protects you from insider attacks by enforcing a mandatory retention period for soft deleted key vaults. No one inside your organization or Microsoft will be able to purge your key vaults during the soft delete retention period." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kv.id as resource,\n kv.og_account_id as og_account_id,\n kv.og_resource_id as og_resource_id,\n case\n when purge_protection_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when purge_protection_enabled then name || ' purge protection enabled.'\n else name || ' purge protection disabled.'\n end as reason\n \n , kv.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault as kv,\n azure_subscription as sub\nwhere\n sub.subscription_id = kv.subscription_id;\n" - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN purge_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN purge_protection_enabled THEN name || ' purge protection enabled.' + ELSE name || ' purge protection disabled.' + END AS reason, + kv.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: critical Tags: hipaa_hitrust_v92: @@ -17,5 +37,4 @@ Tags: - "true" service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Key vaults should have deletion protection enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_rbac_enabled.yaml b/compliance/controls/azure/azure_keyvault_rbac_enabled.yaml old mode 100755 new mode 100644 index 6779e3ab8..e6af6c7df --- a/compliance/controls/azure/azure_keyvault_rbac_enabled.yaml +++ b/compliance/controls/azure/azure_keyvault_rbac_enabled.yaml @@ -1,14 +1,34 @@ +Description: Role assignments disappear when a Key Vault has been deleted (soft- delete) and recovered. Afterwards it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services. ID: azure_keyvault_rbac_enabled -Title: "Enable Role Based Access Control for Azure Key Vault" -Description: "Role assignments disappear when a Key Vault has been deleted (soft- delete) and recovered. Afterwards it will be required to recreate all role assignments. This is a limitation of the soft-delete feature across all Azure services." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kv.id as resource,\n kv.og_account_id as og_account_id,\n kv.og_resource_id as og_resource_id,\n case\n when enable_rbac_authorization then 'ok'\n else 'alarm'\n end as status,\n case\n when enable_rbac_authorization then name || ' has RBAC enabled.'\n else name || ' have RBAC disabled.'\n end as reason\n \n , kv.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault as kv,\n azure_subscription as sub\nwhere\n sub.subscription_id = kv.subscription_id;\n" - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN enable_rbac_authorization THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_rbac_authorization THEN name || ' has RBAC enabled.' + ELSE name || ' have RBAC disabled.' + END AS reason, + kv.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Enable Role Based Access Control for Azure Key Vault \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_secret_expiration_set.yaml b/compliance/controls/azure/azure_keyvault_secret_expiration_set.yaml old mode 100755 new mode 100644 index 03eb8794f..94a65bb96 --- a/compliance/controls/azure/azure_keyvault_secret_expiration_set.yaml +++ b/compliance/controls/azure/azure_keyvault_secret_expiration_set.yaml @@ -1,14 +1,36 @@ +Description: Secrets should have a defined expiration date and not be permanent. Secrets that are valid forever provide a potential attacker with more time to compromise them. It is a recommended security practice to set expiration dates on secrets. ID: azure_keyvault_secret_expiration_set -Title: "Key Vault secrets should have an expiration date" -Description: "Secrets should have a defined expiration date and not be permanent. Secrets that are valid forever provide a potential attacker with more time to compromise them. It is a recommended security practice to set expiration dates on secrets." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kvs.id as resource,\n kvs.og_account_id as og_account_id,\n kvs.og_resource_id as og_resource_id,\n case\n when enabled and expires_at is null then 'alarm'\n else 'ok'\n end as status,\n vault_name || ' secret ' || name ||\n case\n when enabled and expires_at is null then ' expiration date not set.'\n when not enabled then ' disabled.'\n else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.'\n end as reason\n \n , kvs.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault_secret as kvs,\n azure_subscription as sub\nwhere\n sub.subscription_id = kvs.subscription_id;\n" - PrimaryTable: azure_key_vault_secret ListOfTables: - azure_key_vault_secret - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + vault_name || ' secret ' || name || + CASE + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason, + kvs.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_secret AS kvs, + azure_subscription AS sub + WHERE + sub.subscription_id = kvs.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Key Vault secrets should have an expiration date \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_soft_delete_enabled.yaml b/compliance/controls/azure/azure_keyvault_soft_delete_enabled.yaml old mode 100755 new mode 100644 index f0e0f37da..0f0dfc0f8 --- a/compliance/controls/azure/azure_keyvault_soft_delete_enabled.yaml +++ b/compliance/controls/azure/azure_keyvault_soft_delete_enabled.yaml @@ -1,19 +1,38 @@ +Description: Deleting a key vault without soft delete enabled permanently deletes all secrets, keys, and certificates stored in the key vault. Accidental deletion of a key vault can lead to permanent data loss. Soft delete allows you to recover an accidentally deleted key vault for a configurable retention period. ID: azure_keyvault_soft_delete_enabled -Title: "Key vaults should have soft delete enabled" -Description: "Deleting a key vault without soft delete enabled permanently deletes all secrets, keys, and certificates stored in the key vault. Accidental deletion of a key vault can lead to permanent data loss. Soft delete allows you to recover an accidentally deleted key vault for a configurable retention period." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kv.id as resource,\n kv.og_account_id as og_account_id,\n kv.og_resource_id as og_resource_id,\n case\n when soft_delete_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when soft_delete_enabled then name || ' soft delete enabled.'\n else name || ' soft delete disabled.'\n end as reason\n \n , kv.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault as kv,\n azure_subscription as sub\nwhere\n sub.subscription_id = kv.subscription_id;\n" - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN soft_delete_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN soft_delete_enabled THEN name || ' soft delete enabled.' + ELSE name || ' soft delete disabled.' + END AS reason, + kv.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: critical Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Key vaults should have soft delete enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_vault_private_link_used.yaml b/compliance/controls/azure/azure_keyvault_vault_private_link_used.yaml old mode 100755 new mode 100644 index 27ea49449..e9e41c9f7 --- a/compliance/controls/azure/azure_keyvault_vault_private_link_used.yaml +++ b/compliance/controls/azure/azure_keyvault_vault_private_link_used.yaml @@ -1,14 +1,36 @@ +Description: Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to key vault, you can reduce data leakage risks. ID: azure_keyvault_vault_private_link_used -Title: "Azure Key Vaults should use private link" -Description: "Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to key vault, you can reduce data leakage risks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n -- Having private_endpoint_connections will not permit vault to use the same.\n -- In case'defaultAction' = 'Allow', All Network including internet is allowed, which will not satisfy the private endpoint connection.\n -- Default All network will have not network_acls associated.\n when network_acls is null or network_acls ->> 'defaultAction' = 'Allow' then 'alarm'\n when private_endpoint_connections is null then 'info'\n when private_endpoint_connections @> '[{\"PrivateLinkServiceConnectionStateStatus\": \"Approved\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when network_acls is null or network_acls ->> 'defaultAction' = 'Allow' then a.name || ' using public networks.'\n when private_endpoint_connections is null then a.name || ' no private link exists.'\n when private_endpoint_connections @> '[{\"PrivateLinkServiceConnectionStateStatus\": \"Approved\"}]'\n then a.name || ' using private link.'\n else a.name || ' private link not enabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault a,\n azure_subscription sub;\n" - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' = 'Allow' THEN 'alarm' + WHEN private_endpoint_connections IS NULL THEN 'info' + WHEN private_endpoint_connections @> '[{"PrivateLinkServiceConnectionStateStatus": "Approved"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' = 'Allow' THEN a.name || ' using public networks.' + WHEN private_endpoint_connections IS NULL THEN a.name || ' no private link exists.' + WHEN private_endpoint_connections @> '[{"PrivateLinkServiceConnectionStateStatus": "Approved"}]' THEN a.name || ' using private link.' + ELSE a.name || ' private link not enabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault a, + azure_subscription sub; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Azure Key Vaults should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_vault_public_network_access_disabled.yaml b/compliance/controls/azure/azure_keyvault_vault_public_network_access_disabled.yaml old mode 100755 new mode 100644 index 5a0dfb635..13ac7d0a1 --- a/compliance/controls/azure/azure_keyvault_vault_public_network_access_disabled.yaml +++ b/compliance/controls/azure/azure_keyvault_vault_public_network_access_disabled.yaml @@ -1,19 +1,36 @@ +Description: Disable public network access for your key vault so that it's not accessible over the public internet. This can reduce data leakage risks. ID: azure_keyvault_vault_public_network_access_disabled -Title: "Azure Key Vault should disable public network access" -Description: "Disable public network access for your key vault so that it's not accessible over the public internet. This can reduce data leakage risks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n -- In case'defaultAction' = 'Allow', All Network including internet is allowed\n -- Default All network will have not network_acls associated\n when network_acls is null or network_acls ->> 'defaultAction' != 'Deny' then 'alarm'\n else 'ok'\n end as status,\n case\n when network_acls is null or network_acls ->> 'defaultAction' != 'Deny' then a.name || ' public network access enabled.'\n else a.name || ' public network access disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault a,\n azure_subscription sub;\n" - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' != 'Deny' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' != 'Deny' THEN a.name || ' public network access enabled.' + ELSE a.name || ' public network access disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault a, + azure_subscription sub; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Azure Key Vault should disable public network access \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_vault_recoverable.yaml b/compliance/controls/azure/azure_keyvault_vault_recoverable.yaml old mode 100755 new mode 100644 index 734a9a991..8289c0525 --- a/compliance/controls/azure/azure_keyvault_vault_recoverable.yaml +++ b/compliance/controls/azure/azure_keyvault_vault_recoverable.yaml @@ -1,14 +1,36 @@ +Description: The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the "Do Not Purge" and "Soft Delete" functions. ID: azure_keyvault_vault_recoverable -Title: "Ensure the key vault is recoverable" -Description: "The key vault contains object keys, secrets and certificates. Accidental unavailability of a key vault can cause immediate data loss or loss of security functions (authentication, validation, verification, non-repudiation, etc.) supported by the key vault objects. It is recommended the key vault be made recoverable by enabling the \\\"Do Not Purge\\\" and \\\"Soft Delete\\\" functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kv.id as resource,\n kv.og_account_id as og_account_id,\n kv.og_resource_id as og_resource_id,\n case\n when soft_delete_enabled and purge_protection_enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when not soft_delete_enabled and not purge_protection_enabled then name || ' \"soft delete\" and \"do not purge\" not enabled.'\n when not soft_delete_enabled then name || ' \"soft delete\" not enabled.'\n when not purge_protection_enabled then name || ' \"do not purge\" not enabled.'\n else name || ' \"soft delete\" and \"do not purge\" enabled.'\n end as reason\n \n , kv.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault kv,\n azure_subscription sub\nwhere\n sub.subscription_id = kv.subscription_id;\n" - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN soft_delete_enabled AND purge_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT soft_delete_enabled AND NOT purge_protection_enabled THEN name || ' "soft delete" and "do not purge" not enabled.' + WHEN NOT soft_delete_enabled THEN name || ' "soft delete" not enabled.' + WHEN NOT purge_protection_enabled THEN name || ' "do not purge" not enabled.' + ELSE name || ' "soft delete" and "do not purge" enabled.' + END AS reason, + kv.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault kv, + azure_subscription sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: critical Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Ensure the key vault is recoverable \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_vault_use_virtual_service_endpoint.yaml b/compliance/controls/azure/azure_keyvault_vault_use_virtual_service_endpoint.yaml old mode 100755 new mode 100644 index 35aa06bb5..860c95571 --- a/compliance/controls/azure/azure_keyvault_vault_use_virtual_service_endpoint.yaml +++ b/compliance/controls/azure/azure_keyvault_vault_use_virtual_service_endpoint.yaml @@ -1,19 +1,51 @@ +Description: This policy audits any Key Vault not configured to use a virtual network service endpoint. ID: azure_keyvault_vault_use_virtual_service_endpoint -Title: "Key Vault should use a virtual network service endpoint" -Description: "This policy audits any Key Vault not configured to use a virtual network service endpoint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with keyvault_vault_subnet as (\n select\n distinct a.name,\n rule ->> 'id' as id\n from\n azure_key_vault as a,\n jsonb_array_elements(network_acls -> 'virtualNetworkRules') as rule\n where\n rule ->> 'id' is not null\n)\nselect\n distinct a.name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when network_acls ->> 'defaultAction' <> 'Deny' then 'alarm'\n when s.name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when network_acls ->> 'defaultAction' <> 'Deny' then a.name || ' not configured with virtual service endpoint.'\n when s.name is null then a.name || ' not configured with virtual service endpoint.'\n else a.name || ' configured with virtual service endpoint.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault as a\n left join keyvault_vault_subnet as s on a.name = s.name,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + WITH keyvault_vault_subnet AS ( + SELECT + DISTINCT a.name, + rule ->> 'id' AS id + FROM + azure_key_vault AS a, + jsonb_array_elements(network_acls -> 'virtualNetworkRules') AS rule + WHERE + rule ->> 'id' IS NOT NULL + ) + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN network_acls ->> 'defaultAction' <> 'Deny' THEN 'alarm' + WHEN s.name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_acls ->> 'defaultAction' <> 'Deny' THEN a.name || ' not configured with virtual service endpoint.' + WHEN s.name IS NULL THEN a.name || ' not configured with virtual service endpoint.' + ELSE a.name || ' configured with virtual service endpoint.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault AS a + LEFT JOIN keyvault_vault_subnet AS s ON a.name = s.name, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Key Vault should use a virtual network service endpoint \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_with_non_rbac_key_expiration_set.yaml b/compliance/controls/azure/azure_keyvault_with_non_rbac_key_expiration_set.yaml old mode 100755 new mode 100644 index ecb306af2..83427023b --- a/compliance/controls/azure/azure_keyvault_with_non_rbac_key_expiration_set.yaml +++ b/compliance/controls/azure/azure_keyvault_with_non_rbac_key_expiration_set.yaml @@ -1,15 +1,49 @@ +Description: Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set. ID: azure_keyvault_with_non_rbac_key_expiration_set -Title: "Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults" -Description: "Ensure that all Keys in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with non_rbac_vault as (\n select\n name\n from\n azure_key_vault\n where not enable_rbac_authorization\n)\nselect\n kvk.id as resource,\n kvk.og_account_id as og_account_id,\n kvk.og_resource_id as og_resource_id,\n case\n when v.name is null then 'skip'\n when enabled and expires_at is null then 'alarm'\n else 'ok'\n end as status,\n vault_name || ' key ' || kvk.name ||\n case\n when v.name is null then ' RBAC enabled vault.'\n when enabled and expires_at is null then ' expiration date not set.'\n when not enabled then ' disabled.'\n else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.'\n end as reason\n \n , kvk.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault_key kvk\n left join non_rbac_vault as v on v.name = kvk.vault_name,\n azure_subscription sub\nwhere\n sub.subscription_id = kvk.subscription_id;\n" - PrimaryTable: azure_key_vault_key ListOfTables: - azure_key_vault - azure_key_vault_key - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + WITH non_rbac_vault AS ( + SELECT + name + FROM + azure_key_vault + WHERE + NOT enable_rbac_authorization + ) + + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + vault_name || ' key ' || kvk.name || + CASE + WHEN v.name IS NULL THEN ' RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason, + kvk.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_key kvk + LEFT JOIN non_rbac_vault AS v ON v.name = kvk.vault_name, + azure_subscription sub + WHERE + sub.subscription_id = kvk.subscription_id; Severity: medium Tags: category: @@ -30,5 +64,4 @@ Tags: - azure service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Ensure that the Expiration Date is set for all Keys in Non-RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_with_non_rbac_secret_expiration_set.yaml b/compliance/controls/azure/azure_keyvault_with_non_rbac_secret_expiration_set.yaml old mode 100755 new mode 100644 index aaeb9c756..182fb46dc --- a/compliance/controls/azure/azure_keyvault_with_non_rbac_secret_expiration_set.yaml +++ b/compliance/controls/azure/azure_keyvault_with_non_rbac_secret_expiration_set.yaml @@ -1,15 +1,49 @@ +Description: Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set. ID: azure_keyvault_with_non_rbac_secret_expiration_set -Title: "Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults" -Description: "Ensure that all Secrets in Non Role Based Access Control (RBAC) Azure Key Vaults have an expiration time set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with non_rbac_vault as (\n select\n name\n from\n azure_key_vault\n where not enable_rbac_authorization\n)\nselect\n kvs.id as resource,\n kvs.og_account_id as og_account_id,\n kvs.og_resource_id as og_resource_id,\n case\n when v.name is null then 'skip'\n when enabled and expires_at is null then 'alarm'\n else 'ok'\n end as status,\n vault_name || ' key ' || kvs.name ||\n case\n when v.name is null then ' RBAC enabled vault.'\n when enabled and expires_at is null then ' expiration date not set.'\n when not enabled then ' disabled.'\n else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.'\n end as reason\n \n , kvs.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault_secret kvs\n left join non_rbac_vault as v on v.name = kvs.vault_name,\n azure_subscription sub\nwhere\n sub.subscription_id = kvs.subscription_id;\n" - PrimaryTable: azure_key_vault_secret ListOfTables: - azure_key_vault - azure_key_vault_secret - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + WITH non_rbac_vault AS ( + SELECT + name + FROM + azure_key_vault + WHERE + NOT enable_rbac_authorization + ) + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + vault_name || ' key ' || kvs.name || + CASE + WHEN v.name IS NULL THEN ' RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason, + kvs.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_secret kvs + LEFT JOIN non_rbac_vault AS v + ON v.name = kvs.vault_name, + azure_subscription sub + WHERE + sub.subscription_id = kvs.subscription_id; Severity: high Tags: category: @@ -30,5 +64,4 @@ Tags: - azure service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Ensure that the Expiration Date is set for all Secrets in Non-RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_with_rbac_key_expiration_set.yaml b/compliance/controls/azure/azure_keyvault_with_rbac_key_expiration_set.yaml old mode 100755 new mode 100644 index e25d91a77..45cc69d74 --- a/compliance/controls/azure/azure_keyvault_with_rbac_key_expiration_set.yaml +++ b/compliance/controls/azure/azure_keyvault_with_rbac_key_expiration_set.yaml @@ -1,15 +1,47 @@ +Description: Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set. ID: azure_keyvault_with_rbac_key_expiration_set -Title: "Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults" -Description: "Ensure that all Keys in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with rbac_vault as (\n select\n name\n from\n azure_key_vault\n where enable_rbac_authorization\n)\nselect\n kvk.id as resource,\n kvk.og_account_id as og_account_id,\n kvk.og_resource_id as og_resource_id,\n case\n when v.name is null then 'skip'\n when enabled and expires_at is null then 'alarm'\n else 'ok'\n end as status,\n vault_name || ' key ' || kvk.name ||\n case\n when v.name is null then ' not RBAC enabled vault.'\n when enabled and expires_at is null then ' expiration date not set.'\n when not enabled then ' disabled.'\n else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.'\n end as reason\n \n , kvk.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault_key kvk\n left join rbac_vault as v on v.name = kvk.vault_name,\n azure_subscription sub\nwhere\n sub.subscription_id = kvk.subscription_id;\n" - PrimaryTable: azure_key_vault_key ListOfTables: - azure_key_vault - azure_key_vault_key - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + WITH rbac_vault AS ( + SELECT + name + FROM + azure_key_vault + WHERE enable_rbac_authorization + ) + SELECT + kvk.id AS resource, + kvk.og_account_id AS og_account_id, + kvk.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + vault_name || ' key ' || kvk.name || + CASE + WHEN v.name IS NULL THEN ' not RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason, + kvk.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_key kvk + LEFT JOIN rbac_vault AS v ON v.name = kvk.vault_name, + azure_subscription sub + WHERE + sub.subscription_id = kvk.subscription_id; Severity: high Tags: category: @@ -30,5 +62,4 @@ Tags: - azure service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_keyvault_with_rbac_secret_expiration_set.yaml b/compliance/controls/azure/azure_keyvault_with_rbac_secret_expiration_set.yaml old mode 100755 new mode 100644 index 38de81527..022bb5b41 --- a/compliance/controls/azure/azure_keyvault_with_rbac_secret_expiration_set.yaml +++ b/compliance/controls/azure/azure_keyvault_with_rbac_secret_expiration_set.yaml @@ -1,15 +1,48 @@ +Description: Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set. ID: azure_keyvault_with_rbac_secret_expiration_set -Title: "Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults" -Description: "Ensure that all Secrets in Role Based Access Control (RBAC) Azure Key Vaults have an expiration date set." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with rbac_vault as (\n select\n name\n from\n azure_key_vault\n where enable_rbac_authorization\n)\nselect\n kvs.id as resource,\n kvs.og_account_id as og_account_id,\n kvs.og_resource_id as og_resource_id,\n case\n when v.name is null then 'skip'\n when enabled and expires_at is null then 'alarm'\n else 'ok'\n end as status,\n vault_name || ' key ' || kvs.name ||\n case\n when v.name is null then ' not RBAC enabled vault.'\n when enabled and expires_at is null then ' expiration date not set.'\n when not enabled then ' disabled.'\n else ' expiration date set to ' || to_char(expires_at, 'DD-Mon-YYYY') || '.'\n end as reason\n \n , kvs.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_key_vault_secret kvs\n left join rbac_vault as v on v.name = kvs.vault_name,\n azure_subscription sub\nwhere\n sub.subscription_id = kvs.subscription_id;\n" - PrimaryTable: azure_key_vault_secret ListOfTables: - azure_key_vault - azure_key_vault_secret - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + WITH rbac_vault AS ( + SELECT + name + FROM + azure_key_vault + WHERE + enable_rbac_authorization + ) + SELECT + kvs.id AS resource, + kvs.og_account_id AS og_account_id, + kvs.og_resource_id AS og_resource_id, + CASE + WHEN v.name IS NULL THEN 'skip' + WHEN enabled AND expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + vault_name || ' key ' || kvs.name || + CASE + WHEN v.name IS NULL THEN ' not RBAC enabled vault.' + WHEN enabled AND expires_at IS NULL THEN ' expiration date not set.' + WHEN NOT enabled THEN ' disabled.' + ELSE ' expiration date set to ' || TO_CHAR(expires_at, 'DD-Mon-YYYY') || '.' + END AS reason, + kvs.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_secret kvs + LEFT JOIN rbac_vault AS v ON v.name = kvs.vault_name, + azure_subscription sub + WHERE + sub.subscription_id = kvs.subscription_id; Severity: high Tags: category: @@ -30,5 +63,4 @@ Tags: - azure service: - Azure/KeyVault -IntegrationType: - - azure_subscription +Title: Ensure that the Expiration Date is set for all Secrets in RBAC Key Vaults \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_add_on_azure_policy_enabled.yaml b/compliance/controls/azure/azure_kubernetes_cluster_add_on_azure_policy_enabled.yaml old mode 100755 new mode 100644 index f9bf9628c..ea6e12320 --- a/compliance/controls/azure/azure_kubernetes_cluster_add_on_azure_policy_enabled.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_add_on_azure_policy_enabled.yaml @@ -1,19 +1,38 @@ +Description: Azure Policy Add-on for Kubernetes service (AKS) extends Gatekeeper v3, an admission controller webhook for Open Policy Agent (OPA), to apply at-scale enforcements and safeguards on your clusters in a centralized, consistent manner. ID: azure_kubernetes_cluster_add_on_azure_policy_enabled -Title: "Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters" -Description: "Azure Policy Add-on for Kubernetes service (AKS) extends Gatekeeper v3, an admission controller webhook for Open Policy Agent (OPA), to apply at-scale enforcements and safeguards on your clusters in a centralized, consistent manner." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kc.id as resource,\n kc.og_account_id as og_account_id,\n kc.og_resource_id as og_resource_id,\n case\n when addon_profiles -> 'azurepolicy' ->> 'enabled' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when addon_profiles -> 'azurepolicy' ->> 'enabled' = 'true' then name || ' add on azure policy enabled.'\n else name || ' add on azure policy disabled.'\n end as reason\n \n , kc.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_kubernetes_cluster kc,\n azure_subscription sub\nwhere\n sub.subscription_id = kc.subscription_id;\n" - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + kc.id AS resource, + kc.og_account_id AS og_account_id, + kc.og_resource_id AS og_resource_id, + CASE + WHEN addon_profiles -> 'azurepolicy' ->> 'enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN addon_profiles -> 'azurepolicy' ->> 'enabled' = 'true' THEN name || ' add on azure policy enabled.' + ELSE name || ' add on azure policy disabled.' + END AS reason, + kc.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster kc, + azure_subscription sub + WHERE + sub.subscription_id = kc.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/KubernetesService -IntegrationType: - - azure_subscription +Title: Azure Policy Add-on for Kubernetes service (AKS) should be installed and enabled on your clusters \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_addon_azure_policy_enabled.yaml b/compliance/controls/azure/azure_kubernetes_cluster_addon_azure_policy_enabled.yaml old mode 100755 new mode 100644 index 7a7af7a0c..148ac3be7 --- a/compliance/controls/azure/azure_kubernetes_cluster_addon_azure_policy_enabled.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_addon_azure_policy_enabled.yaml @@ -1,32 +1,32 @@ +Description: Ensure that Kubernetes cluster uses Azure Policies Add-on. ID: azure_kubernetes_cluster_addon_azure_policy_enabled -Title: "Kubernetes cluster addon Azure policy should be enabled" -Description: "Ensure that Kubernetes cluster uses Azure Policies Add-on." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when addon_profiles -> 'azurepolicy' ->> 'enabled' = 'true' then 'ok' - else 'alarm' - end as status, - case - when addon_profiles -> 'azurepolicy' ->> 'enabled' = 'true' then c.name || ' addon azure policy enabled .' - else c.name || ' addon azure policy disabled .' - end as reason - from - azure_kubernetes_cluster c, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN addon_profiles -> 'azurepolicy' ->> 'enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN addon_profiles -> 'azurepolicy' ->> 'enabled' = 'true' THEN c.name || ' addon azure policy enabled.' + ELSE c.name || ' addon azure policy disabled.' + END AS reason + FROM + azure_kubernetes_cluster c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes cluster addon Azure policy should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_authorized_ip_range_defined.yaml b/compliance/controls/azure/azure_kubernetes_cluster_authorized_ip_range_defined.yaml old mode 100755 new mode 100644 index 75c9008ae..f6737a617 --- a/compliance/controls/azure/azure_kubernetes_cluster_authorized_ip_range_defined.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_authorized_ip_range_defined.yaml @@ -1,19 +1,40 @@ +Description: ARestrict access to the Kubernetes Service Management API by granting API access only + to IP addresses in specific ranges. It is recommended to limit access to authorized IP ranges to + ensure that only applications from allowed networks can access the cluster. ID: azure_kubernetes_cluster_authorized_ip_range_defined -Title: "Authorized IP ranges should be defined on Kubernetes Services" -Description: "ARestrict access to the Kubernetes Service Management API by granting API access only to IP addresses in specific ranges. It is recommended to limit access to authorized IP ranges to ensure that only applications from allowed networks can access the cluster." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n c.id as resource,\n c.og_account_id as og_account_id,\n c.og_resource_id as og_resource_id,\n case\n when api_server_access_profile -> 'AuthorizedIPRanges' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when api_server_access_profile -> 'AuthorizedIPRanges' is not null then c.title || ' authorized IP ranges defined.'\n else c.title || ' authorized IP ranges not defined.'\n end as reason\n \n , c.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_kubernetes_cluster as c,\n azure_subscription as sub\nwhere\n sub.subscription_id = c.subscription_id;\n" - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN api_server_access_profile -> 'AuthorizedIPRanges' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN api_server_access_profile -> 'AuthorizedIPRanges' IS NOT NULL THEN c.title || ' authorized IP ranges defined.' + ELSE c.title || ' authorized IP ranges not defined.' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS c, + azure_subscription AS sub + WHERE + sub.subscription_id = c.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/KubernetesService -IntegrationType: - - azure_subscription +Title: Authorized IP ranges should be defined on Kubernetes Services \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_container_cpu_and_memory_resource_limit.yaml b/compliance/controls/azure/azure_kubernetes_cluster_container_cpu_and_memory_resource_limit.yaml old mode 100755 new mode 100644 index ae69e113b..7ca88e3f1 --- a/compliance/controls/azure/azure_kubernetes_cluster_container_cpu_and_memory_resource_limit.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_container_cpu_and_memory_resource_limit.yaml @@ -1,24 +1,24 @@ +Description: Enforce container CPU and memory resource limits to prevent resource exhaustion attacks in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_container_cpu_and_memory_resource_limit -Title: "Kubernetes cluster containers CPU and memory resource limits should not exceed the specified limits" -Description: "Enforce container CPU and memory resource limits to prevent resource exhaustion attacks in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster containers CPU and memory resource limits should not exceed the specified limits \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_container_host_process_id_not_shared.yaml b/compliance/controls/azure/azure_kubernetes_cluster_container_host_process_id_not_shared.yaml old mode 100755 new mode 100644 index 3a0e3aaf5..1829d7201 --- a/compliance/controls/azure/azure_kubernetes_cluster_container_host_process_id_not_shared.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_container_host_process_id_not_shared.yaml @@ -1,24 +1,24 @@ +Description: Block pod containers from sharing the host process ID namespace and host IPC namespace in a Kubernetes cluster. This recommendation is part of CIS 5.2.2 and CIS 5.2.3 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_container_host_process_id_not_shared -Title: "Kubernetes cluster containers should not share host process ID or host IPC namespace" -Description: "Block pod containers from sharing the host process ID namespace and host IPC namespace in a Kubernetes cluster. This recommendation is part of CIS 5.2.2 and CIS 5.2.3 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster containers should not share host process ID or host IPC namespace \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_container_privilege_escalation_restricted.yaml b/compliance/controls/azure/azure_kubernetes_cluster_container_privilege_escalation_restricted.yaml old mode 100755 new mode 100644 index 40a6e27f6..5b77a4569 --- a/compliance/controls/azure/azure_kubernetes_cluster_container_privilege_escalation_restricted.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_container_privilege_escalation_restricted.yaml @@ -1,24 +1,24 @@ +Description: Do not allow containers to run with privilege escalation to root in a Kubernetes cluster. This recommendation is part of CIS 5.2.5 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_container_privilege_escalation_restricted -Title: "Kubernetes clusters should not allow container privilege escalation" -Description: "Do not allow containers to run with privilege escalation to root in a Kubernetes cluster. This recommendation is part of CIS 5.2.5 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes clusters should not allow container privilege escalation \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_apparmor_profile.yaml b/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_apparmor_profile.yaml old mode 100755 new mode 100644 index 9aa92260c..b8abc960e --- a/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_apparmor_profile.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_apparmor_profile.yaml @@ -1,24 +1,24 @@ +Description: Containers should only use allowed AppArmor profiles in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_container_use_allowed_apparmor_profile -Title: "Kubernetes cluster containers should only use allowed AppArmor profiles" -Description: "Containers should only use allowed AppArmor profiles in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster containers should only use allowed AppArmor profiles \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_capabilities.yaml b/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_capabilities.yaml old mode 100755 new mode 100644 index f8dd161b2..25bba711f --- a/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_capabilities.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_capabilities.yaml @@ -1,24 +1,24 @@ +Description: Restrict the capabilities to reduce the attack surface of containers in a Kubernetes cluster. This recommendation is part of CIS 5.2.8 and CIS 5.2.9 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_container_use_allowed_capabilities -Title: "Kubernetes cluster containers should only use allowed capabilities" -Description: "Restrict the capabilities to reduce the attack surface of containers in a Kubernetes cluster. This recommendation is part of CIS 5.2.8 and CIS 5.2.9 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster containers should only use allowed capabilities \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_images.yaml b/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_images.yaml old mode 100755 new mode 100644 index 0d7112786..009cb3dd4 --- a/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_images.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_container_use_allowed_images.yaml @@ -1,24 +1,24 @@ +Description: Use images from trusted registries to reduce the Kubernetes cluster's exposure risk to unknown vulnerabilities, security issues and malicious images. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_container_use_allowed_images -Title: "Kubernetes cluster containers should only use allowed images" -Description: "Use images from trusted registries to reduce the Kubernetes cluster's exposure risk to unknown vulnerabilities, security issues and malicious images. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster containers should only use allowed images \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_container_with_read_only_root_file_system.yaml b/compliance/controls/azure/azure_kubernetes_cluster_container_with_read_only_root_file_system.yaml old mode 100755 new mode 100644 index 2c7d15565..e5a09709a --- a/compliance/controls/azure/azure_kubernetes_cluster_container_with_read_only_root_file_system.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_container_with_read_only_root_file_system.yaml @@ -1,24 +1,24 @@ +Description: Run containers with a read only root file system to protect from changes at run-time with malicious binaries being added to PATH in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_container_with_read_only_root_file_system -Title: "Kubernetes cluster containers should run with a read only root file system" -Description: "Run containers with a read only root file system to protect from changes at run-time with malicious binaries being added to PATH in a Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster containers should run with a read only root file system \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_http_application_routing_disabled.yaml b/compliance/controls/azure/azure_kubernetes_cluster_http_application_routing_disabled.yaml old mode 100755 new mode 100644 index 3c0de1806..472e115ff --- a/compliance/controls/azure/azure_kubernetes_cluster_http_application_routing_disabled.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_http_application_routing_disabled.yaml @@ -1,32 +1,32 @@ +Description: This control checks if HTTP application routing is disabled for Kubernetes cluster. ID: azure_kubernetes_cluster_http_application_routing_disabled -Title: "Kubernetes clusters HTTP application routing should be disabled" -Description: "This control checks if HTTP application routing is disabled for Kubernetes cluster." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when addon_profiles -> 'httpApplicationRouting' ->> 'enabled' = 'true' then 'alarm' - else 'ok' - end as status, - case - when addon_profiles -> 'httpApplicationRouting' ->> 'enabled' = 'true' then c.name || ' HTTP application routing enabled.' - else c.name || ' HTTP application routing disabled.' - end as reason - from - azure_kubernetes_cluster c, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN addon_profiles -> 'httpApplicationRouting' ->> 'enabled' = 'true' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN addon_profiles -> 'httpApplicationRouting' ->> 'enabled' = 'true' THEN c.name || ' HTTP application routing enabled.' + ELSE c.name || ' HTTP application routing disabled.' + END AS reason + FROM + azure_kubernetes_cluster c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes clusters HTTP application routing should be disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_https_enabled.yaml b/compliance/controls/azure/azure_kubernetes_cluster_https_enabled.yaml old mode 100755 new mode 100644 index ca93d60f5..da816c595 --- a/compliance/controls/azure/azure_kubernetes_cluster_https_enabled.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_https_enabled.yaml @@ -1,24 +1,24 @@ +Description: Use of HTTPS ensures authentication and protects data in transit from network layer eavesdropping attacks. This capability is currently generally available for Kubernetes Service (AKS), and in preview for Azure Arc enabled Kubernetes. For more info, visit https://aka.ms/kubepolicydoc ID: azure_kubernetes_cluster_https_enabled -Title: "Kubernetes clusters should be accessible only over HTTPS" -Description: "Use of HTTPS ensures authentication and protects data in transit from network layer eavesdropping attacks. This capability is currently generally available for Kubernetes Service (AKS), and in preview for Azure Arc enabled Kubernetes. For more info, visit https://aka.ms/kubepolicydoc" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes clusters should be accessible only over HTTPS \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_key_vault_secret_rotation_enabled.yaml b/compliance/controls/azure/azure_kubernetes_cluster_key_vault_secret_rotation_enabled.yaml old mode 100755 new mode 100644 index a36cd0f4d..4d478b430 --- a/compliance/controls/azure/azure_kubernetes_cluster_key_vault_secret_rotation_enabled.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_key_vault_secret_rotation_enabled.yaml @@ -1,32 +1,34 @@ +Description: This control checks if key vault secret rotation is enabled for Kubernetes cluster. ID: azure_kubernetes_cluster_key_vault_secret_rotation_enabled -Title: "Kubernetes clusters key vault secret rotation should be enabled" -Description: "This control checks if key vault secret rotation should is enabled for Kubernetes cluster." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when addon_profiles -> 'azureKeyvaultSecretsProvider' -> 'config' ->> 'enableSecretRotation' = 'true' then 'ok' - else 'alarm' - end as status, - case - when addon_profiles -> 'azureKeyvaultSecretsProvider' -> 'config' ->> 'enableSecretRotation' = 'true' then c.name || ' key vault secret rotation enabled.' - else c.name || ' key vault secret rotation disabled.' - end as reason - from - azure_kubernetes_cluster c, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN addon_profiles -> 'azureKeyvaultSecretsProvider' -> 'config' ->> 'enableSecretRotation' = 'true' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN addon_profiles -> 'azureKeyvaultSecretsProvider' -> 'config' ->> 'enableSecretRotation' = 'true' + THEN c.name || ' key vault secret rotation enabled.' + ELSE c.name || ' key vault secret rotation disabled.' + END AS reason + FROM + azure_kubernetes_cluster c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes clusters key vault secret rotation should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_logging_enabled.yaml b/compliance/controls/azure/azure_kubernetes_cluster_logging_enabled.yaml old mode 100755 new mode 100644 index 31c901728..1b52e378b --- a/compliance/controls/azure/azure_kubernetes_cluster_logging_enabled.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_logging_enabled.yaml @@ -1,32 +1,36 @@ +Description: This control checks if OMS agent is enabled for Kubernetes cluster. ID: azure_kubernetes_cluster_logging_enabled -Title: "Kubernetes clusters should have logging enabled" -Description: "This control checks if OMS agent is enabled for Kubernetes cluster." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when addon_profiles -> 'omsAgent' ->> 'enabled' = 'true' and addon_profiles -> 'omsAgent' ->> 'config' is not null then 'ok' - else 'alarm' - end as status, - case - when addon_profiles -> 'omsAgent' ->> 'enabled' = 'true' and addon_profiles -> 'omsAgent' ->> 'config' is not null then c.name || ' logging enabled.' - else c.name || ' logging disabled.' - end as reason - from - azure_kubernetes_cluster c, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN addon_profiles -> 'omsAgent' ->> 'enabled' = 'true' + AND addon_profiles -> 'omsAgent' ->> 'config' IS NOT NULL + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN addon_profiles -> 'omsAgent' ->> 'enabled' = 'true' + AND addon_profiles -> 'omsAgent' ->> 'config' IS NOT NULL + THEN c.name || ' logging enabled.' + ELSE c.name || ' logging disabled.' + END AS reason + FROM + azure_kubernetes_cluster c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes clusters should have logging enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_max_pod_50.yaml b/compliance/controls/azure/azure_kubernetes_cluster_max_pod_50.yaml old mode 100755 new mode 100644 index ef36124c4..db2b420e2 --- a/compliance/controls/azure/azure_kubernetes_cluster_max_pod_50.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_max_pod_50.yaml @@ -1,42 +1,42 @@ +Description: This control checks if Kubernetes clusters is using a minimum number of 50 pods. ID: azure_kubernetes_cluster_max_pod_50 -Title: "Kubernetes clusters should use a minimum number of 50 pods" -Description: "This control checks if Kubernetes clusters is using a minimum number of 50 pods." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with max_node as ( - select - distinct id - from - azure_kubernetes_cluster, - jsonb_array_elements(agent_pool_profiles) as p - where - (p ->> 'maxPods')::int < 50 - ) - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when n.id is not null then 'alarm' - else 'ok' - end as status, - case - when n.id is not null then c.name || ' nodes have less than 50 pods.' - else c.name || ' nodes have greater than 50 pods.' - end as reason - from - azure_kubernetes_cluster c - left join max_node as n on n.id = c.id, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + WITH max_node AS ( + SELECT + DISTINCT id + FROM + azure_kubernetes_cluster, + jsonb_array_elements(agent_pool_profiles) AS p + WHERE + (p ->> 'maxPods')::INT < 50 + ) + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN n.id IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN n.id IS NOT NULL THEN c.name || ' nodes have less than 50 pods.' + ELSE c.name || ' nodes have greater than 50 pods.' + END AS reason + FROM + azure_kubernetes_cluster c + LEFT JOIN max_node AS n ON n.id = c.id, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes clusters should use a minimum number of 50 pods \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_network_plugin_azure.yaml b/compliance/controls/azure/azure_kubernetes_cluster_network_plugin_azure.yaml old mode 100755 new mode 100644 index aed9aca24..f54cb22f1 --- a/compliance/controls/azure/azure_kubernetes_cluster_network_plugin_azure.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_network_plugin_azure.yaml @@ -1,32 +1,32 @@ +Description: This control checks if Azure CNI networking is enabled for Kubernetes cluster. ID: azure_kubernetes_cluster_network_plugin_azure -Title: "Kubernetes clusters should have Azure network plugin" -Description: "This control checks if Azure CNI networking is enabled for Kubernetes cluster." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when network_profile ->> 'networkPlugin' = 'azure' then 'ok' - else 'alarm' - end as status, - case - when network_profile ->> 'networkPlugin' = 'azure' then c.name || ' Azure CNI networking enabled.' - else c.name || ' Azure CNI networking disabled.' - end as reason - from - azure_kubernetes_cluster c, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN network_profile ->> 'networkPlugin' = 'azure' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN network_profile ->> 'networkPlugin' = 'azure' THEN c.name || ' Azure CNI networking enabled.' + ELSE c.name || ' Azure CNI networking disabled.' + END AS reason + FROM + azure_kubernetes_cluster c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes clusters should have Azure network plugin \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_network_policy_enabled.yaml b/compliance/controls/azure/azure_kubernetes_cluster_network_policy_enabled.yaml old mode 100755 new mode 100644 index 50b7ff80b..474ce0171 --- a/compliance/controls/azure/azure_kubernetes_cluster_network_policy_enabled.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_network_policy_enabled.yaml @@ -1,32 +1,32 @@ +Description: This control checks if network policy is enabled for Kubernetes cluster. ID: azure_kubernetes_cluster_network_policy_enabled -Title: "Kubernetes clusters should have network policy enabled" -Description: "This control checks if network policy is enabled for Kubernetes cluster." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when network_profile ->> 'networkPolicy' is not null then 'ok' - else 'alarm' - end as status, - case - when network_profile ->> 'networkPolicy' is not null then c.name || ' network policy enabled.' - else c.name || ' network policy disabled.' - end as reason - from - azure_kubernetes_cluster c, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN network_profile ->> 'networkPolicy' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN network_profile ->> 'networkPolicy' IS NOT NULL THEN c.name || ' network policy enabled.' + ELSE c.name || ' network policy disabled.' + END AS reason + FROM + azure_kubernetes_cluster c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes clusters should have network policy enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_node_restrict_public_access.yaml b/compliance/controls/azure/azure_kubernetes_cluster_node_restrict_public_access.yaml old mode 100755 new mode 100644 index 0176c1d93..cef47965c --- a/compliance/controls/azure/azure_kubernetes_cluster_node_restrict_public_access.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_node_restrict_public_access.yaml @@ -1,44 +1,44 @@ +Description: Ensure Kubernetes cluster nodes do not have public IP addresses. This control is non-compliant if Kubernetes cluster nodes have a public IP address assigned. ID: azure_kubernetes_cluster_node_restrict_public_access -Title: "Kubernetes cluster nodes should prohibit public access" -Description: "Ensure Kubernetes cluster nodes do not have public IP addresses. This control is non-compliant if Kubernetes cluster nodes have a public IP address assigned." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with public_node as ( - select - distinct id - from + ListOfTables: + - azure_kubernetes_cluster + - azure_subscription + Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + WITH public_node AS ( + SELECT + DISTINCT id + FROM azure_kubernetes_cluster, - jsonb_array_elements(agent_pool_profiles) as p - where + jsonb_array_elements(agent_pool_profiles) AS p + WHERE p ->> 'enableNodePublicIP' = 'true' - group by + GROUP BY id ) - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when n.id is null then 'ok' - else 'alarm' - end as status, - case - when n.id is null then c.name || ' has no public node.' - else c.name || ' has public node.' - end as reason - from + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN n.id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN n.id IS NULL THEN c.name || ' has no public node.' + ELSE c.name || ' has public node.' + END AS reason + FROM azure_kubernetes_cluster c - left join public_node as n on n.id = c.id, + LEFT JOIN public_node AS n ON n.id = c.id, azure_subscription sub - where + WHERE sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster - ListOfTables: - - azure_kubernetes_cluster - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes cluster nodes should prohibit public access \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_os_and_data_disks_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_kubernetes_cluster_os_and_data_disks_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 52abea1b8..380959852 --- a/compliance/controls/azure/azure_kubernetes_cluster_os_and_data_disks_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_os_and_data_disks_encrypted_with_cmk.yaml @@ -1,19 +1,38 @@ +Description: Encrypting OS and data disks using customer-managed keys provides more control and greater flexibility in key management. This is a common requirement in many regulatory and industry compliance standards. ID: azure_kubernetes_cluster_os_and_data_disks_encrypted_with_cmk -Title: "Both operating systems and data disks in Azure Kubernetes Service clusters should be encrypted by customer-managed keys" -Description: "Encrypting OS and data disks using customer-managed keys provides more control and greater flexibility in key management. This is a common requirement in many regulatory and industry compliance standards." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n c.id as resource,\n c.og_account_id as og_account_id,\n c.og_resource_id as og_resource_id,\n case\n when disk_encryption_set_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when disk_encryption_set_id is not null then c.name || ' os and data diska encrypted with CMK.'\n else c.name || ' os and data diska not encrypted with CMK.'\n end as reason\n \n , c.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_kubernetes_cluster c,\n azure_subscription sub\nwhere\n sub.subscription_id = c.subscription_id;\n" - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN disk_encryption_set_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN disk_encryption_set_id IS NOT NULL THEN c.name || ' os and data disks encrypted with CMK.' + ELSE c.name || ' os and data disks not encrypted with CMK.' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/KubernetesService -IntegrationType: - - azure_subscription +Title: Both operating systems and data disks in Azure Kubernetes Service clusters should be encrypted by customer-managed keys \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_pod_host_path_volume_use_allowed_host_path.yaml b/compliance/controls/azure/azure_kubernetes_cluster_pod_host_path_volume_use_allowed_host_path.yaml old mode 100755 new mode 100644 index cd8166589..672eef7e0 --- a/compliance/controls/azure/azure_kubernetes_cluster_pod_host_path_volume_use_allowed_host_path.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_pod_host_path_volume_use_allowed_host_path.yaml @@ -1,24 +1,24 @@ +Description: Limit pod HostPath volume mounts to the allowed host paths in a Kubernetes Cluster. This policy is generally available for Kubernetes Service (AKS), and Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_pod_host_path_volume_use_allowed_host_path -Title: "Kubernetes cluster pod hostPath volumes should only use allowed host paths" -Description: "Limit pod HostPath volume mounts to the allowed host paths in a Kubernetes Cluster. This policy is generally available for Kubernetes Service (AKS), and Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster pod hostPath volumes should only use allowed host paths \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_pod_use_approved_host_network_and_port_range.yaml b/compliance/controls/azure/azure_kubernetes_cluster_pod_use_approved_host_network_and_port_range.yaml old mode 100755 new mode 100644 index 9b820bd64..f967ccab1 --- a/compliance/controls/azure/azure_kubernetes_cluster_pod_use_approved_host_network_and_port_range.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_pod_use_approved_host_network_and_port_range.yaml @@ -1,24 +1,24 @@ +Description: Restrict pod access to the host network and the allowable host port range in a Kubernetes cluster. This recommendation is part of CIS 5.2.4 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_pod_use_approved_host_network_and_port_range -Title: "Kubernetes cluster pods should only use approved host network and port range" -Description: "Restrict pod access to the host network and the allowable host port range in a Kubernetes cluster. This recommendation is part of CIS 5.2.4 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster pods should only use approved host network and port range \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_pods_and_containers_uses_approved_user_and_group_id.yaml b/compliance/controls/azure/azure_kubernetes_cluster_pods_and_containers_uses_approved_user_and_group_id.yaml old mode 100755 new mode 100644 index a00b58d8e..bee7e0e30 --- a/compliance/controls/azure/azure_kubernetes_cluster_pods_and_containers_uses_approved_user_and_group_id.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_pods_and_containers_uses_approved_user_and_group_id.yaml @@ -1,24 +1,24 @@ +Description: Control the user, primary group, supplemental group and file system group IDs that pods and containers can use to run in a Kubernetes Cluster. This recommendation is part of Pod Security Policies which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for AKS Engine and Azure Arc enabled Kubernetes. ID: azure_kubernetes_cluster_pods_and_containers_uses_approved_user_and_group_id -Title: "Kubernetes cluster pods and containers should only run with approved user and group IDs" -Description: "Control the user, primary group, supplemental group and file system group IDs that pods and containers can use to run in a Kubernetes Cluster. This recommendation is part of Pod Security Policies which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for AKS Engine and Azure Arc enabled Kubernetes." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster pods and containers should only run with approved user and group IDs \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_privilege_containers_restricted.yaml b/compliance/controls/azure/azure_kubernetes_cluster_privilege_containers_restricted.yaml old mode 100755 new mode 100644 index 6e6da3c6a..dd6dcd962 --- a/compliance/controls/azure/azure_kubernetes_cluster_privilege_containers_restricted.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_privilege_containers_restricted.yaml @@ -1,24 +1,24 @@ +Description: Do not allow privileged containers creation in a Kubernetes cluster. This recommendation is part of CIS 5.2.1 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_privilege_containers_restricted -Title: "Kubernetes cluster should not allow privileged containers" -Description: "Do not allow privileged containers creation in a Kubernetes cluster. This recommendation is part of CIS 5.2.1 which is intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster should not allow privileged containers \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_restrict_public_access.yaml b/compliance/controls/azure/azure_kubernetes_cluster_restrict_public_access.yaml old mode 100755 new mode 100644 index 22707b2ab..c1da6e850 --- a/compliance/controls/azure/azure_kubernetes_cluster_restrict_public_access.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_restrict_public_access.yaml @@ -1,32 +1,32 @@ +Description: Ensure that Kubernetes cluster enables private clusters to restrict public access. ID: azure_kubernetes_cluster_restrict_public_access -Title: "Kubernetes cluster should restrict public access" -Description: "Ensure that Kubernetes cluster enables private clusters to restrict public access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when api_server_access_profile ->> 'enablePrivateCluster' = 'true' then 'ok' - else 'alarm' - end as status, - case - when api_server_access_profile ->> 'enablePrivateCluster' = 'true' then c.name || ' not publicly accessible.' - else c.name || ' publicly accessibe.' - end as reason - from - azure_kubernetes_cluster c, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN api_server_access_profile ->> 'enablePrivateCluster' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN api_server_access_profile ->> 'enablePrivateCluster' = 'true' THEN c.name || ' not publicly accessible.' + ELSE c.name || ' publicly accessible.' + END AS reason + FROM + azure_kubernetes_cluster c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes cluster should restrict public access \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_service_listen_to_allowed_ports.yaml b/compliance/controls/azure/azure_kubernetes_cluster_service_listen_to_allowed_ports.yaml old mode 100755 new mode 100644 index 45ab862f9..ba9530143 --- a/compliance/controls/azure/azure_kubernetes_cluster_service_listen_to_allowed_ports.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_service_listen_to_allowed_ports.yaml @@ -1,24 +1,24 @@ +Description: Restrict services to listen only on allowed ports to secure access to the Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. ID: azure_kubernetes_cluster_service_listen_to_allowed_ports -Title: "Kubernetes cluster services should listen only on allowed ports" -Description: "Restrict services to listen only on allowed ports to secure access to the Kubernetes cluster. This policy is generally available for Kubernetes Service (AKS), and preview for Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Kubernetes cluster services should listen only on allowed ports \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_sku_standard.yaml b/compliance/controls/azure/azure_kubernetes_cluster_sku_standard.yaml old mode 100755 new mode 100644 index 59631620c..dd6ae2482 --- a/compliance/controls/azure/azure_kubernetes_cluster_sku_standard.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_sku_standard.yaml @@ -1,32 +1,32 @@ +Description: Ensure that Kubernetes clusters use standard SKU tier for production workloads. This control is non-compliant if App Configuration does not use standard SKU. ID: azure_kubernetes_cluster_sku_standard -Title: "Kubernetes clusters should use standard SKU" -Description: "Ensure that Kubernetes clusters uses standard SKU tier for production workloads. This control is non-compliant if App Configuration does not use standard SKU." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when sku ->> 'tier' = 'Paid' then 'ok' - else 'alarm' - end as status, - case - when sku ->> 'tier' = 'Paid' then c.name || ' uses standard SKU tier.' - else c.name || ' uses free SKU tier.' - end as reason - from - azure_kubernetes_cluster c, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN sku ->> 'tier' = 'Paid' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku ->> 'tier' = 'Paid' THEN c.name || ' uses standard SKU tier.' + ELSE c.name || ' uses free SKU tier.' + END AS reason + FROM + azure_kubernetes_cluster c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes clusters should use standard SKU \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_temp_disks_and_agent_node_pool_cache_encrypted_at_host.yaml b/compliance/controls/azure/azure_kubernetes_cluster_temp_disks_and_agent_node_pool_cache_encrypted_at_host.yaml old mode 100755 new mode 100644 index 451214eb2..b34179e81 --- a/compliance/controls/azure/azure_kubernetes_cluster_temp_disks_and_agent_node_pool_cache_encrypted_at_host.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_temp_disks_and_agent_node_pool_cache_encrypted_at_host.yaml @@ -1,19 +1,51 @@ +Description: To enhance data security, the data stored on the virtual machine (VM) host of your Azure Kubernetes Service nodes VMs should be encrypted at rest. This is a common requirement in many regulatory and industry compliance standards. ID: azure_kubernetes_cluster_temp_disks_and_agent_node_pool_cache_encrypted_at_host -Title: "Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host" -Description: "To enhance data security, the data stored on the virtual machine (VM) host of your Azure Kubernetes Service nodes VMs should be encrypted at rest. This is a common requirement in many regulatory and industry compliance standards." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with kubernetes_cluster as(\n select\n id,\n name,\n subscription_id,\n resource_group\n from\n azure_kubernetes_cluster,\n jsonb_array_elements(agent_pool_profiles) as p\n where\n p -> 'enableEncryptionAtHost' = 'true'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when s.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when s.id is not null then a.name || ' encrypted at host.'\n else a.name || ' not encrypted at host.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_kubernetes_cluster as a\n left join kubernetes_cluster as s on s.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + WITH kubernetes_cluster AS ( + SELECT + id, + name, + subscription_id, + resource_group + FROM + azure_kubernetes_cluster, + JSONB_ARRAY_ELEMENTS(agent_pool_profiles) AS p + WHERE + p -> 'enableEncryptionAtHost' = 'true' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN s.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.id IS NOT NULL THEN a.name || ' encrypted at host.' + ELSE a.name || ' not encrypted at host.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS a + LEFT JOIN kubernetes_cluster AS s ON s.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/KubernetesService -IntegrationType: - - azure_subscription +Title: Temp disks and cache for agent node pools in Azure Kubernetes Service clusters should be encrypted at host \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_upgrade_channel.yaml b/compliance/controls/azure/azure_kubernetes_cluster_upgrade_channel.yaml old mode 100755 new mode 100644 index f1bf95d1f..14df953f9 --- a/compliance/controls/azure/azure_kubernetes_cluster_upgrade_channel.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_upgrade_channel.yaml @@ -1,32 +1,32 @@ +Description: Ensure Kubernetes clusters upgrade channel is configured. This control is non-compliant if Kubernetes clusters upgrade channel is set to none. ID: azure_kubernetes_cluster_upgrade_channel -Title: "Kubernetes clusters upgrade channel should be configured" -Description: "Ensure Kubernetes clusters upgrade channel is configured. This control is non-compliant if Kubernetes clusters upgrade channel is set to none." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when auto_upgrade_profile ->> 'upgradeChannel' = 'none' then 'alarm' - else 'ok' - end as status, - case - when auto_upgrade_profile ->> 'upgradeChannel' = 'none' then c.name || ' upgrade channel not configured.' - else c.name || ' upgrade channel configured.' - end as reason - from - azure_kubernetes_cluster c, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN auto_upgrade_profile ->> 'upgradeChannel' = 'none' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN auto_upgrade_profile ->> 'upgradeChannel' = 'none' THEN c.name || ' upgrade channel not configured.' + ELSE c.name || ' upgrade channel configured.' + END AS reason + FROM + azure_kubernetes_cluster c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes clusters upgrade channel should be configured \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_cluster_upgraded_with_non_vulnerable_version.yaml b/compliance/controls/azure/azure_kubernetes_cluster_upgraded_with_non_vulnerable_version.yaml old mode 100755 new mode 100644 index accbae7eb..0609862ff --- a/compliance/controls/azure/azure_kubernetes_cluster_upgraded_with_non_vulnerable_version.yaml +++ b/compliance/controls/azure/azure_kubernetes_cluster_upgraded_with_non_vulnerable_version.yaml @@ -1,19 +1,46 @@ +Description: Upgrade your Kubernetes service cluster to a later Kubernetes version to protect against known vulnerabilities in your current Kubernetes version. Vulnerability CVE-2019-9946 has been patched in Kubernetes versions 1.11.9+, 1.12.7+, 1.13.5+, and 1.14.0+. ID: azure_kubernetes_cluster_upgraded_with_non_vulnerable_version -Title: "Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version" -Description: "Upgrade your Kubernetes service cluster to a later Kubernetes version to protect against known vulnerabilities in your current Kubernetes version. Vulnerability CVE-2019-9946 has been patched in Kubernetes versions 1.11.9+, 1.12.7+, 1.13.5+, and 1.14.0+." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when\n a.kubernetes_version ~ '1\\.13\\.[0-4]'\n or a.kubernetes_version ~ '1\\.12\\.[0-6]'\n or a.kubernetes_version ~ '1\\.11\\.[0-8]'\n or a.kubernetes_version ~ '1\\.\\d|10\\.*' then 'alarm'\n else 'ok'\n end as status,\n case\n when\n a.kubernetes_version ~ '1\\.13\\.[0-4]'\n or a.kubernetes_version ~ '1\\.12\\.[0-6]'\n or a.kubernetes_version ~ '1\\.11\\.[0-8]'\n or a.kubernetes_version ~ '1\\.\\d|10\\.*' then a.name || ' not upgraded to a non-vulnerable Kubernetes version.'\n else a.name || ' upgraded to a non-vulnerable Kubernetes version.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_kubernetes_cluster as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN + a.kubernetes_version ~ '1\.13\.[0-4]' + OR a.kubernetes_version ~ '1\.12\.[0-6]' + OR a.kubernetes_version ~ '1\.11\.[0-8]' + OR a.kubernetes_version ~ '1\.\d|10\.*' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + a.kubernetes_version ~ '1\.13\.[0-4]' + OR a.kubernetes_version ~ '1\.12\.[0-6]' + OR a.kubernetes_version ~ '1\.11\.[0-8]' + OR a.kubernetes_version ~ '1\.\d|10\.*' THEN a.name || ' not upgraded to a non-vulnerable Kubernetes version.' + ELSE a.name || ' upgraded to a non-vulnerable Kubernetes version.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/KubernetesService -IntegrationType: - - azure_subscription +Title: Kubernetes Services should be upgraded to a non-vulnerable Kubernetes version \ No newline at end of file diff --git a/compliance/controls/azure/azure_kubernetes_instance_rbac_enabled.yaml b/compliance/controls/azure/azure_kubernetes_instance_rbac_enabled.yaml old mode 100755 new mode 100644 index 93d343e8a..5c68e206a --- a/compliance/controls/azure/azure_kubernetes_instance_rbac_enabled.yaml +++ b/compliance/controls/azure/azure_kubernetes_instance_rbac_enabled.yaml @@ -1,14 +1,35 @@ +Description: To provide granular filtering on the actions that users can perform, use Role-Based Access Control (RBAC) to manage permissions in Kubernetes Service Clusters and configure relevant authorization policies. ID: azure_kubernetes_instance_rbac_enabled -Title: "Role-Based Access Control (RBAC) should be used on Kubernetes Services" -Description: "To provide granular filtering on the actions that users can perform, use Role-Based Access Control (RBAC) to manage permissions in Kubernetes Service Clusters and configure relevant authorization policies." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kc.id as resource,\n kc.og_account_id as og_account_id,\n kc.og_resource_id as og_resource_id,\n case\n when enable_rbac then 'ok'\n else 'alarm'\n end as status,\n case\n when enable_rbac then name || ' role based access control enabled.'\n else name || ' role based access control disabled.'\n end as reason,\n enable_rbac\n \n , kc.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_kubernetes_cluster kc,\n azure_subscription sub\nwhere\n sub.subscription_id = kc.subscription_id;\n" - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + kc.id AS resource, + kc.og_account_id AS og_account_id, + kc.og_resource_id AS og_resource_id, + CASE + WHEN enable_rbac THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_rbac THEN name || ' role based access control enabled.' + ELSE name || ' role based access control disabled.' + END AS reason, + enable_rbac, + kc.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster kc, + azure_subscription sub + WHERE + sub.subscription_id = kc.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +38,4 @@ Tags: - "true" service: - Azure/KubernetesService -IntegrationType: - - azure_subscription +Title: Role-Based Access Control (RBAC) should be used on Kubernetes Services \ No newline at end of file diff --git a/compliance/controls/azure/azure_kusto_cluster_disk_encryption_enabled.yaml b/compliance/controls/azure/azure_kusto_cluster_disk_encryption_enabled.yaml old mode 100755 new mode 100644 index 09e6b005a..d2e6f8a83 --- a/compliance/controls/azure/azure_kusto_cluster_disk_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_kusto_cluster_disk_encryption_enabled.yaml @@ -1,19 +1,38 @@ +Description: Enabling disk encryption helps protect and safeguard your data to meet your organizational security and compliance commitments. ID: azure_kusto_cluster_disk_encryption_enabled -Title: "Disk encryption should be enabled on Azure Data Explorer" -Description: "Enabling disk encryption helps protect and safeguard your data to meet your organizational security and compliance commitments." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kv.id as resource,\n kv.og_account_id as og_account_id,\n kv.og_resource_id as og_resource_id,\n case\n when enable_disk_encryption then 'ok'\n else 'alarm'\n end as status,\n case\n when enable_disk_encryption then name || ' disk encryption enabled.'\n else name || ' disk encryption disabled.'\n end as reason\n \n , kv.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_kusto_cluster as kv,\n azure_subscription as sub\nwhere\n sub.subscription_id = kv.subscription_id;\n" - PrimaryTable: azure_kusto_cluster ListOfTables: - azure_kusto_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kusto_cluster + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN enable_disk_encryption THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_disk_encryption THEN name || ' disk encryption enabled.' + ELSE name || ' disk encryption disabled.' + END AS reason, + kv.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kusto_cluster AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/DataExplorer -IntegrationType: - - azure_subscription +Title: Disk encryption should be enabled on Azure Data Explorer \ No newline at end of file diff --git a/compliance/controls/azure/azure_kusto_cluster_double_encryption_enabled.yaml b/compliance/controls/azure/azure_kusto_cluster_double_encryption_enabled.yaml old mode 100755 new mode 100644 index aef790b58..0f4891075 --- a/compliance/controls/azure/azure_kusto_cluster_double_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_kusto_cluster_double_encryption_enabled.yaml @@ -1,19 +1,38 @@ +Description: Enabling double encryption helps protect and safeguard your data to meet your organizational security and compliance commitments. When double encryption has been enabled, data in the storage account is encrypted twice, once at the service level and once at the infrastructure level, using two different encryption algorithms and two different keys. ID: azure_kusto_cluster_double_encryption_enabled -Title: "Double encryption should be enabled on Azure Data Explorer" -Description: "Enabling double encryption helps protect and safeguard your data to meet your organizational security and compliance commitments. When double encryption has been enabled, data in the storage account is encrypted twice, once at the service level and once at the infrastructure level, using two different encryption algorithms and two different keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kv.id as resource,\n kv.og_account_id as og_account_id,\n kv.og_resource_id as og_resource_id,\n case\n when enable_double_encryption then 'ok'\n else 'alarm'\n end as status,\n case\n when enable_double_encryption then name || ' double encryption enabled.'\n else name || ' double encryption disabled.'\n end as reason\n \n , kv.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_kusto_cluster as kv,\n azure_subscription as sub\nwhere\n sub.subscription_id = kv.subscription_id;\n" - PrimaryTable: azure_kusto_cluster ListOfTables: - azure_kusto_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kusto_cluster + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN enable_double_encryption THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_double_encryption THEN name || ' double encryption enabled.' + ELSE name || ' double encryption disabled.' + END AS reason, + kv.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kusto_cluster AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/DataExplorer -IntegrationType: - - azure_subscription +Title: Double encryption should be enabled on Azure Data Explorer \ No newline at end of file diff --git a/compliance/controls/azure/azure_kusto_cluster_encrypted_at_rest_with_cmk.yaml b/compliance/controls/azure/azure_kusto_cluster_encrypted_at_rest_with_cmk.yaml old mode 100755 new mode 100644 index b85a26a57..62184a525 --- a/compliance/controls/azure/azure_kusto_cluster_encrypted_at_rest_with_cmk.yaml +++ b/compliance/controls/azure/azure_kusto_cluster_encrypted_at_rest_with_cmk.yaml @@ -1,19 +1,46 @@ +Description: Enabling encryption at rest using a customer-managed key on your Azure Data Explorer cluster provides additional control over the key being used by the encryption at rest. This feature is oftentimes applicable to customers with special compliance requirements and requires a Key Vault to managing the keys. ID: azure_kusto_cluster_encrypted_at_rest_with_cmk -Title: "Azure Data Explorer encryption at rest should use a customer-managed key" -Description: "Enabling encryption at rest using a customer-managed key on your Azure Data Explorer cluster provides additional control over the key being used by the encryption at rest. This feature is oftentimes applicable to customers with special compliance requirements and requires a Key Vault to managing the keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n kv.id as resource,\n kv.og_account_id as og_account_id,\n kv.og_resource_id as og_resource_id,\n case\n when\n key_vault_properties -> 'keyName' is not null\n and key_vault_properties -> 'keyVaultUri' is not null\n and key_vault_properties -> 'keyVersion' is not null\n then 'ok'\n else 'alarm'\n end as status,\n case\n when\n key_vault_properties -> 'keyName' is not null\n and key_vault_properties -> 'keyVaultUri' is not null\n and key_vault_properties -> 'keyVersion' is not null\n then name || ' encrypted at rest with CMK.'\n else name || ' not encrypted at rest with CMK.'\n end as reason\n \n , kv.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_kusto_cluster as kv,\n azure_subscription as sub\nwhere\n sub.subscription_id = kv.subscription_id;\n" - PrimaryTable: azure_kusto_cluster ListOfTables: - azure_kusto_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kusto_cluster + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN + key_vault_properties -> 'keyName' IS NOT NULL + AND key_vault_properties -> 'keyVaultUri' IS NOT NULL + AND key_vault_properties -> 'keyVersion' IS NOT NULL + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN + key_vault_properties -> 'keyName' IS NOT NULL + AND key_vault_properties -> 'keyVaultUri' IS NOT NULL + AND key_vault_properties -> 'keyVersion' IS NOT NULL + THEN name || ' encrypted at rest with CMK.' + ELSE name || ' not encrypted at rest with CMK.' + END AS reason, + kv.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kusto_cluster AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/DataExplorer -IntegrationType: - - azure_subscription +Title: Azure Data Explorer encryption at rest should use a customer-managed key \ No newline at end of file diff --git a/compliance/controls/azure/azure_kusto_cluster_sku_with_sla.yaml b/compliance/controls/azure/azure_kusto_cluster_sku_with_sla.yaml old mode 100755 new mode 100644 index 40c96f29b..aa0ee2d83 --- a/compliance/controls/azure/azure_kusto_cluster_sku_with_sla.yaml +++ b/compliance/controls/azure/azure_kusto_cluster_sku_with_sla.yaml @@ -1,29 +1,29 @@ +Description: This control checks if Kusto clusters use SKU with an SLA. This control is considered non-compliant if Kusto clusters use SKUs without an SLA. ID: azure_kusto_cluster_sku_with_sla -Title: "Kusto clusters should use SKU with an SLA" -Description: "This control checks if Kusto clusters use SKU with an SLA. This control is considered non-compliant if Kusto clusters use SKUs without an SLA." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - kv.id as resource, - kv.og_account_id as og_account_id, - kv.og_resource_id as og_resource_id, - case - when sku_name in ('Dev(No SLA)_Standard_E2a_v4' , 'Dev(No SLA)_Standard_D11_v2') then 'alarm' - else 'ok' - end as status, - name || ' using ' || sku_name || ' SKU tier.' as reason - from - azure_kusto_cluster as kv, - azure_subscription as sub - where - sub.subscription_id = kv.subscription_id; - PrimaryTable: azure_kusto_cluster ListOfTables: - azure_kusto_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kusto_cluster + QueryToExecute: | + SELECT + kv.id AS resource, + kv.og_account_id AS og_account_id, + kv.og_resource_id AS og_resource_id, + CASE + WHEN sku_name IN ('Dev(No SLA)_Standard_E2a_v4', 'Dev(No SLA)_Standard_D11_v2') THEN 'alarm' + ELSE 'ok' + END AS status, + name || ' using ' || sku_name || ' SKU tier.' AS reason + FROM + azure_kusto_cluster AS kv, + azure_subscription AS sub + WHERE + sub.subscription_id = kv.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Kusto clusters should use SKU with an SLA \ No newline at end of file diff --git a/compliance/controls/azure/azure_log_analytics_workspace_block_log_ingestion_and_querying_from_public.yaml b/compliance/controls/azure/azure_log_analytics_workspace_block_log_ingestion_and_querying_from_public.yaml old mode 100755 new mode 100644 index e9b093ee4..15c664eb8 --- a/compliance/controls/azure/azure_log_analytics_workspace_block_log_ingestion_and_querying_from_public.yaml +++ b/compliance/controls/azure/azure_log_analytics_workspace_block_log_ingestion_and_querying_from_public.yaml @@ -1,30 +1,36 @@ +Description: Improve workspace security by blocking log ingestion and querying from public networks. Only private-link connected networks will be able to ingest and query logs on this workspace. Learn more at https://aka.ms/AzMonPrivateLink#configure-log-analytics. ID: azure_log_analytics_workspace_block_log_ingestion_and_querying_from_public -Title: "Log Analytics workspaces should block log ingestion and querying from public networks" -Description: "Improve workspace security by blocking log ingestion and querying from public networks. Only private-link connected networks will be able to ingest and query logs on this workspace. Learn more at https://aka.ms/AzMonPrivateLink#configure-log-analytics." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - w.id as resource, - w.og_account_id as og_account_id, - w.og_resource_id as og_resource_id, - case - when type = 'Microsoft.OperationalInsights/workspaces' and public_network_access_for_ingestion = 'Enabled' and public_network_access_for_query = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when type = 'Microsoft.OperationalInsights/workspaces' and public_network_access_for_ingestion = 'Enabled' and public_network_access_for_query = 'Enabled' then w.name || ' workspace allows log ingestion and querying from public network.' - else w.name || ' workspace does not allow log ingestion and querying from public network.' - end as reason - from - azure_log_analytics_workspace as w - left join azure_subscription sub on sub.subscription_id = w.subscription_id; - PrimaryTable: azure_log_analytics_workspace ListOfTables: - azure_log_analytics_workspace - azure_subscription Parameters: [] + PrimaryTable: azure_log_analytics_workspace + QueryToExecute: | + SELECT + w.id AS resource, + w.og_account_id AS og_account_id, + w.og_resource_id AS og_resource_id, + CASE + WHEN type = 'Microsoft.OperationalInsights/workspaces' + AND public_network_access_for_ingestion = 'Enabled' + AND public_network_access_for_query = 'Enabled' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN type = 'Microsoft.OperationalInsights/workspaces' + AND public_network_access_for_ingestion = 'Enabled' + AND public_network_access_for_query = 'Enabled' + THEN w.name || ' workspace allows log ingestion and querying from public network.' + ELSE w.name || ' workspace does not allow log ingestion and querying from public network.' + END AS reason + FROM + azure_log_analytics_workspace AS w + LEFT JOIN azure_subscription sub ON sub.subscription_id = w.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Log Analytics workspaces should block log ingestion and querying from public networks \ No newline at end of file diff --git a/compliance/controls/azure/azure_log_analytics_workspace_block_non_azure_ingestion.yaml b/compliance/controls/azure/azure_log_analytics_workspace_block_non_azure_ingestion.yaml old mode 100755 new mode 100644 index 55e254182..161bbd54d --- a/compliance/controls/azure/azure_log_analytics_workspace_block_non_azure_ingestion.yaml +++ b/compliance/controls/azure/azure_log_analytics_workspace_block_non_azure_ingestion.yaml @@ -1,30 +1,33 @@ +Description: Enforcing log ingestion to require Azure Active Directory authentication prevents unauthenticated logs from an attacker which could lead to incorrect status, false alerts, and incorrect logs stored in the system. ID: azure_log_analytics_workspace_block_non_azure_ingestion -Title: "Log Analytics Workspaces should block non-Azure Active Directory based ingestion" -Description: "Enforcing log ingestion to require Azure Active Directory authentication prevents unauthenticated logs from an attacker which could lead to incorrect status, false alerts, and incorrect logs stored in the system." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - w.id as resource, - w.og_account_id as og_account_id, - w.og_resource_id as og_resource_id, - case - when type = 'Microsoft.OperationalInsights/workspaces' and disable_local_auth = 'true' then 'alarm' - else 'ok' - end as status, - case - when type = 'Microsoft.OperationalInsights/workspaces' and disable_local_auth = 'true' then w.name || ' workspace allows non-Azure log ingestion.' - else w.name || ' workspace does not allow non-Azure log ingestion.' - end as reason - from - azure_log_analytics_workspace as w - left join azure_subscription sub on sub.subscription_id = w.subscription_id; - PrimaryTable: azure_log_analytics_workspace ListOfTables: - azure_log_analytics_workspace - azure_subscription Parameters: [] + PrimaryTable: azure_log_analytics_workspace + QueryToExecute: | + SELECT + w.id AS resource, + w.og_account_id AS og_account_id, + w.og_resource_id AS og_resource_id, + CASE + WHEN type = 'Microsoft.OperationalInsights/workspaces' AND disable_local_auth = 'true' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN type = 'Microsoft.OperationalInsights/workspaces' AND disable_local_auth = 'true' THEN w.name || ' workspace allows non-Azure log ingestion.' + ELSE w.name || ' workspace does not allow non-Azure log ingestion.' + END AS reason + FROM + azure_log_analytics_workspace AS w + LEFT JOIN + azure_subscription sub + ON + sub.subscription_id = w.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Log Analytics Workspaces should block non-Azure Active Directory based ingestion \ No newline at end of file diff --git a/compliance/controls/azure/azure_log_profile_enabled_for_all_subscription.yaml b/compliance/controls/azure/azure_log_profile_enabled_for_all_subscription.yaml old mode 100755 new mode 100644 index 963330563..4140d2851 --- a/compliance/controls/azure/azure_log_profile_enabled_for_all_subscription.yaml +++ b/compliance/controls/azure/azure_log_profile_enabled_for_all_subscription.yaml @@ -1,38 +1,38 @@ +Description: This policy ensures if a log profile is enabled for exporting activity logs. It audits if there is no log profile created to export the logs either to a storage account or to an event hub. ID: azure_log_profile_enabled_for_all_subscription -Title: "Azure subscriptions should have a log profile for Activity Log" -Description: "This policy ensures if a log profile is enabled for exporting activity logs. It audits if there is no log profile created to export the logs either to a storage account or to an event hub." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with log_profiles as ( - select - subscription_id - from - azure_log_profile - group by - subscription_id - ) - select - sub.id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when i.subscription_id is null then 'alarm' - else 'ok' - end as status, - case - when i.subscription_id is null then sub.display_name || ' does not collect activity logs.' - else sub.display_name || ' collects activity logs.' - end as reason - from - azure_subscription as sub - left join log_profiles as i on i.subscription_id = sub.subscription_id; - PrimaryTable: azure_subscription ListOfTables: - azure_log_profile - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH log_profiles AS ( + SELECT + subscription_id + FROM + azure_log_profile + GROUP BY + subscription_id + ) + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN i.subscription_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.subscription_id IS NULL THEN sub.display_name || ' does not collect activity logs.' + ELSE sub.display_name || ' collects activity logs.' + END AS reason + FROM + azure_subscription AS sub + LEFT JOIN log_profiles AS i ON i.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Azure subscriptions should have a log profile for Activity Log \ No newline at end of file diff --git a/compliance/controls/azure/azure_logic_app_integration_service_environment_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_logic_app_integration_service_environment_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index fb1fe6261..1d4eaf518 --- a/compliance/controls/azure/azure_logic_app_integration_service_environment_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_logic_app_integration_service_environment_encrypted_with_cmk.yaml @@ -1,24 +1,24 @@ +Description: Deploy into Integration Service Environment to manage encryption at rest of Logic Apps data using customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_logic_app_integration_service_environment_encrypted_with_cmk -Title: "Logic Apps Integration Service Environment should be encrypted with customer-managed keys" -Description: "Deploy into Integration Service Environment to manage encryption at rest of Logic Apps data using customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Logic Apps Integration Service Environment should be encrypted with customer-managed keys \ No newline at end of file diff --git a/compliance/controls/azure/azure_logic_app_workflow_logging_enabled.yaml b/compliance/controls/azure/azure_logic_app_workflow_logging_enabled.yaml old mode 100755 new mode 100644 index f225b1a0f..737e47126 --- a/compliance/controls/azure/azure_logic_app_workflow_logging_enabled.yaml +++ b/compliance/controls/azure/azure_logic_app_workflow_logging_enabled.yaml @@ -1,14 +1,62 @@ +Description: Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised. ID: azure_logic_app_workflow_logging_enabled -Title: "Resource logs in Logic Apps should be enabled" -Description: "Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n distinct id as workflow_id\n from\n azure_logic_app_workflow,\n jsonb_array_elements(diagnostic_settings) setting,\n jsonb_array_elements(setting -> 'properties' -> 'logs') log\n where\n diagnostic_settings is not null\n and (\n (\n (log ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy' ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy') :: JSONB ? 'days'\n )\n or\n (\n (log ->> 'enabled') :: boolean\n and (\n log -> 'retentionPolicy' ->> 'enabled' <> 'true'\n or setting -> 'properties' ->> 'storageAccountId' = ''\n )\n )\n )\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.diagnostic_settings is null then 'alarm'\n when l.workflow_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.diagnostic_settings is null then a.name || ' logging disabled.'\n when l.workflow_id is not null then a.name || ' logging enabled.'\n else a.name || ' logging disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_logic_app_workflow as a\n left join logging_details as l on a.id = l.workflow_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_logic_app_workflow ListOfTables: - azure_logic_app_workflow - azure_subscription Parameters: [] + PrimaryTable: azure_logic_app_workflow + QueryToExecute: | + WITH logging_details AS ( + SELECT + DISTINCT id AS workflow_id + FROM + azure_logic_app_workflow, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND ( + ( + (log ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy' ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy')::JSONB ? 'days' + ) + OR + ( + (log ->> 'enabled')::BOOLEAN + AND ( + log -> 'retentionPolicy' ->> 'enabled' <> 'true' + OR setting -> 'properties' ->> 'storageAccountId' = '' + ) + ) + ) + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.workflow_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.diagnostic_settings IS NULL THEN a.name || ' logging disabled.' + WHEN l.workflow_id IS NOT NULL THEN a.name || ' logging enabled.' + ELSE a.name || ' logging disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_logic_app_workflow AS a + LEFT JOIN logging_details AS l ON a.id = l.workflow_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +65,4 @@ Tags: - "true" service: - Azure/Logic -IntegrationType: - - azure_subscription +Title: Resource logs in Logic Apps should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_machine_learning_workspace_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_machine_learning_workspace_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 5edde2218..5e82684d1 --- a/compliance/controls/azure/azure_machine_learning_workspace_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_machine_learning_workspace_encrypted_with_cmk.yaml @@ -1,19 +1,38 @@ +Description: Manage encryption at rest of Azure Machine Learning workspace data with customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_machine_learning_workspace_encrypted_with_cmk -Title: "Azure Machine Learning workspaces should be encrypted with a customer-managed key" -Description: "Manage encryption at rest of Azure Machine Learning workspace data with customer-managed keys. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n c.id as resource,\n c.og_account_id as og_account_id,\n c.og_resource_id as og_resource_id,\n case\n when encryption ->> 'status' = 'Enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption ->> 'status' = 'Enabled' then c.name || ' encrypted with CMK.'\n else c.name || ' not encrypted with CMK.'\n end as reason\n \n , c.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_machine_learning_workspace c,\n azure_subscription sub\nwhere\n sub.subscription_id = c.subscription_id;\n" - PrimaryTable: azure_machine_learning_workspace ListOfTables: - azure_machine_learning_workspace - azure_subscription Parameters: [] + PrimaryTable: azure_machine_learning_workspace + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN encryption ->> 'status' = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption ->> 'status' = 'Enabled' THEN c.name || ' encrypted with CMK.' + ELSE c.name || ' not encrypted with CMK.' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_machine_learning_workspace c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/MachineLearning -IntegrationType: - - azure_subscription +Title: Azure Machine Learning workspaces should be encrypted with a customer-managed key \ No newline at end of file diff --git a/compliance/controls/azure/azure_machine_learning_workspace_private_link_used.yaml b/compliance/controls/azure/azure_machine_learning_workspace_private_link_used.yaml old mode 100755 new mode 100644 index 03a3a67f8..aae55acbe --- a/compliance/controls/azure/azure_machine_learning_workspace_private_link_used.yaml +++ b/compliance/controls/azure/azure_machine_learning_workspace_private_link_used.yaml @@ -1,24 +1,24 @@ +Description: 'Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Machine Learning workspaces, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/machine-learning/how-to-configure-private-link.' ID: azure_machine_learning_workspace_private_link_used -Title: "Azure Machine Learning workspaces should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Machine Learning workspaces, data leakage risks are reduced. Learn more about private links at: https://docs.microsoft.com/azure/machine-learning/how-to-configure-private-link." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Azure Machine Learning workspaces should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_api_management_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_api_management_mandatory.yaml old mode 100755 new mode 100644 index 13070e0a1..846849bdb --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_api_management_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_api_management_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if API Management services have mandatory tags. ID: azure_mandatory_sql_resource_group_api_management_mandatory -Title: "API Management services should have mandatory tags" -Description: "Check if API Management services have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_api_management + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_api_management QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_api_management ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_api_management - ListOfTables: - - azure_api_management - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: API Management services should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_environment_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_environment_mandatory.yaml old mode 100755 new mode 100644 index 7c93b81d9..9fb5e0e91 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_environment_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_environment_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if App Service environments have mandatory tags. ID: azure_mandatory_sql_resource_group_app_service_environment_mandatory -Title: "App Service environments should have mandatory tags" -Description: "Check if App Service environments have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_app_service_environment + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_app_service_environment QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_app_service_environment ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_app_service_environment - ListOfTables: - - azure_app_service_environment - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: App Service environments should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_function_app_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_function_app_mandatory.yaml old mode 100755 new mode 100644 index 7b056b64c..b53a7ea1e --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_function_app_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_function_app_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if App Service function apps have mandatory tags. ID: azure_mandatory_sql_resource_group_app_service_function_app_mandatory -Title: "App Service function apps should have mandatory tags" -Description: "Check if App Service function apps have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_app_service_function_app + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_app_service_function_app QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_app_service_function_app ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_app_service_function_app - ListOfTables: - - azure_app_service_function_app - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: App Service function apps should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_plan_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_plan_mandatory.yaml old mode 100755 new mode 100644 index d99ad22b7..4f85ad794 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_plan_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_plan_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if App Service plans have mandatory tags. ID: azure_mandatory_sql_resource_group_app_service_plan_mandatory -Title: "App Service plans should have mandatory tags" -Description: "Check if App Service plans have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_app_service_plan + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_app_service_plan QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_app_service_plan ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_app_service_plan - ListOfTables: - - azure_app_service_plan - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: App Service plans should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_web_app_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_web_app_mandatory.yaml old mode 100755 new mode 100644 index d6fa56c82..e907c24ff --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_web_app_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_app_service_web_app_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if App Service web apps have mandatory tags. ID: azure_mandatory_sql_resource_group_app_service_web_app_mandatory -Title: "App Service web apps should have mandatory tags" -Description: "Check if App Service web apps have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_app_service_web_app + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_app_service_web_app QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_app_service_web_app ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_app_service_web_app - ListOfTables: - - azure_app_service_web_app - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: App Service web apps should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_application_security_group_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_application_security_group_mandatory.yaml old mode 100755 new mode 100644 index 8118d76d2..21b315ca1 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_application_security_group_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_application_security_group_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Application security groups have mandatory tags. ID: azure_mandatory_sql_resource_group_application_security_group_mandatory -Title: "Application security groups should have mandatory tags" -Description: "Check if Application security groups have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_application_security_group + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_application_security_group QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_application_security_group ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_application_security_group - ListOfTables: - - azure_application_security_group - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Application security groups should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_batch_account_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_batch_account_mandatory.yaml old mode 100755 new mode 100644 index dddef3aee..f65168fa5 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_batch_account_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_batch_account_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Batch accounts have mandatory tags. ID: azure_mandatory_sql_resource_group_batch_account_mandatory -Title: "Batch accounts should have mandatory tags" -Description: "Check if Batch accounts have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_batch_account + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_batch_account QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_batch_account ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_batch_account - ListOfTables: - - azure_batch_account - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Batch accounts should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_availability_set_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_availability_set_mandatory.yaml old mode 100755 new mode 100644 index 28b90bffc..a6a9d19c2 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_availability_set_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_availability_set_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Compute availability sets have mandatory tags. ID: azure_mandatory_sql_resource_group_compute_availability_set_mandatory -Title: "Compute availability sets should have mandatory tags" -Description: "Check if Compute availability sets have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_compute_availability_set + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_compute_availability_set QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_compute_availability_set ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_compute_availability_set - ListOfTables: - - azure_compute_availability_set - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Compute availability sets should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_disk_encryption_set_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_disk_encryption_set_mandatory.yaml old mode 100755 new mode 100644 index 1dc6182a6..58fb663cb --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_disk_encryption_set_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_disk_encryption_set_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Compute disk encryption sets have mandatory tags. ID: azure_mandatory_sql_resource_group_compute_disk_encryption_set_mandatory -Title: "Compute disk encryption sets should have mandatory tags" -Description: "Check if Compute disk encryption sets have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_compute_disk_encryption_set + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_compute_disk_encryption_set QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT JSONB_OBJECT_KEYS(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_compute_disk_encryption_set ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT JSONB_ARRAY_ELEMENTS_TEXT(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_compute_disk_encryption_set - ListOfTables: - - azure_compute_disk_encryption_set - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Compute disk encryption sets should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_disk_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_disk_mandatory.yaml old mode 100755 new mode 100644 index 39e768c15..5485b947d --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_disk_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_disk_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Compute disks have mandatory tags. ID: azure_mandatory_sql_resource_group_compute_disk_mandatory -Title: "Compute disks should have mandatory tags" -Description: "Check if Compute disks have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_compute_disk + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_compute_disk QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_compute_disk ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_compute_disk - ListOfTables: - - azure_compute_disk - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Compute disks should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_image_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_image_mandatory.yaml old mode 100755 new mode 100644 index 49d936469..9789d1d73 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_image_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_image_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Compute images have mandatory tags. ID: azure_mandatory_sql_resource_group_compute_image_mandatory -Title: "Compute images should have mandatory tags" -Description: "Check if Compute images have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_compute_image + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_compute_image QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_compute_image ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_compute_image - ListOfTables: - - azure_compute_image - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Compute images should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_snapshot_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_snapshot_mandatory.yaml old mode 100755 new mode 100644 index 145e12d27..8524a7255 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_snapshot_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_snapshot_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Compute snapshots have mandatory tags. ID: azure_mandatory_sql_resource_group_compute_snapshot_mandatory -Title: "Compute snapshots should have mandatory tags" -Description: "Check if Compute snapshots have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_compute_snapshot + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_compute_snapshot QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_compute_snapshot ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_compute_snapshot - ListOfTables: - - azure_compute_snapshot - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Compute snapshots should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_virtual_machine_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_virtual_machine_mandatory.yaml old mode 100755 new mode 100644 index a56c5257d..e49f6fe89 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_virtual_machine_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_virtual_machine_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Compute virtual machines have mandatory tags. ID: azure_mandatory_sql_resource_group_compute_virtual_machine_mandatory -Title: "Compute virtual machines should have mandatory tags" -Description: "Check if Compute virtual machines have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_compute_virtual_machine + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_compute_virtual_machine QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_compute_virtual_machine ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_compute_virtual_machine - ListOfTables: - - azure_compute_virtual_machine - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Compute virtual machines should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_virtual_machine_scale_set_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_virtual_machine_scale_set_mandatory.yaml old mode 100755 new mode 100644 index 3a67a5ae9..62ce8b9cb --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_virtual_machine_scale_set_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_compute_virtual_machine_scale_set_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Compute virtual machine scale sets have mandatory tags. ID: azure_mandatory_sql_resource_group_compute_virtual_machine_scale_set_mandatory -Title: "Compute virtual machine scale sets should have mandatory tags" -Description: "Check if Compute virtual machine scale sets have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_compute_virtual_machine_scale_set + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_compute_virtual_machine_scale_set QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_compute_virtual_machine_scale_set ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_compute_virtual_machine_scale_set - ListOfTables: - - azure_compute_virtual_machine_scale_set - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Compute virtual machine scale sets should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_container_registry_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_container_registry_mandatory.yaml old mode 100755 new mode 100644 index 62232e762..5a29a5abb --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_container_registry_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_container_registry_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Container registries have mandatory tags. ID: azure_mandatory_sql_resource_group_container_registry_mandatory -Title: "Container registries should have mandatory tags" -Description: "Check if Container registries have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_container_registry + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_container_registry QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_container_registry ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_container_registry - ListOfTables: - - azure_container_registry - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Container registries should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_account_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_account_mandatory.yaml old mode 100755 new mode 100644 index 0510fa471..f94e85f9e --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_account_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_account_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if CosmosDB accounts have mandatory tags. ID: azure_mandatory_sql_resource_group_cosmosdb_account_mandatory -Title: "CosmosDB accounts should have mandatory tags" -Description: "Check if CosmosDB accounts have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_cosmosdb_account + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_cosmosdb_account QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_cosmosdb_account ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_cosmosdb_account - ListOfTables: - - azure_cosmosdb_account - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: CosmosDB accounts should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_mongo_database_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_mongo_database_mandatory.yaml old mode 100755 new mode 100644 index 3eb82fc9a..6650c90ab --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_mongo_database_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_mongo_database_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if CosmosDB mongo databases have mandatory tags. ID: azure_mandatory_sql_resource_group_cosmosdb_mongo_database_mandatory -Title: "CosmosDB mongo databases should have mandatory tags" -Description: "Check if CosmosDB mongo databases have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_cosmosdb_mongo_database + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_cosmosdb_mongo_database QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_cosmosdb_mongo_database ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_cosmosdb_mongo_database - ListOfTables: - - azure_cosmosdb_mongo_database - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: CosmosDB mongo databases should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_sql_database_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_sql_database_mandatory.yaml old mode 100755 new mode 100644 index 1e5149225..6962bb11f --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_sql_database_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_cosmosdb_sql_database_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if CosmosDB sql databases have mandatory tags. ID: azure_mandatory_sql_resource_group_cosmosdb_sql_database_mandatory -Title: "CosmosDB sql databases should have mandatory tags" -Description: "Check if CosmosDB sql databases have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_cosmosdb_sql_database + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_cosmosdb_sql_database QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_cosmosdb_sql_database ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_cosmosdb_sql_database - ListOfTables: - - azure_cosmosdb_sql_database - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: CosmosDB sql databases should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_data_factory_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_data_factory_mandatory.yaml old mode 100755 new mode 100644 index 58cf2d9a7..10c7389ef --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_data_factory_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_data_factory_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Data factories have mandatory tags. ID: azure_mandatory_sql_resource_group_data_factory_mandatory -Title: "Data factories should have mandatory tags" -Description: "Check if Data factories have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_data_factory + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_data_factory QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_data_factory ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_data_factory - ListOfTables: - - azure_data_factory - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Data factories should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_data_lake_analytics_account_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_data_lake_analytics_account_mandatory.yaml old mode 100755 new mode 100644 index d83e02ec1..5c6db02f4 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_data_lake_analytics_account_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_data_lake_analytics_account_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Data lake analytics accounts have mandatory tags. ID: azure_mandatory_sql_resource_group_data_lake_analytics_account_mandatory -Title: "Data lake analytics accounts should have mandatory tags" -Description: "Check if Data lake analytics accounts have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_data_lake_analytics_account + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_data_lake_analytics_account QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_data_lake_analytics_account ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_data_lake_analytics_account - ListOfTables: - - azure_data_lake_analytics_account - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Data lake analytics accounts should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_data_lake_store_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_data_lake_store_mandatory.yaml old mode 100755 new mode 100644 index d5dbd0255..75a504538 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_data_lake_store_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_data_lake_store_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Data lake stores have mandatory tags. ID: azure_mandatory_sql_resource_group_data_lake_store_mandatory -Title: "Data lake stores should have mandatory tags" -Description: "Check if Data lake stores have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_data_lake_store + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_data_lake_store QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_data_lake_store ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_data_lake_store - ListOfTables: - - azure_data_lake_store - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Data lake stores should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_eventhub_namespace_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_eventhub_namespace_mandatory.yaml old mode 100755 new mode 100644 index 61c6a84d5..55d7d4202 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_eventhub_namespace_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_eventhub_namespace_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Event Hub namespaces have mandatory tags. ID: azure_mandatory_sql_resource_group_eventhub_namespace_mandatory -Title: "Event Hub namespaces should have mandatory tags" -Description: "Check if Event Hub namespaces have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_eventhub_namespace + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_eventhub_namespace QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_eventhub_namespace ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_eventhub_namespace - ListOfTables: - - azure_eventhub_namespace - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Event Hub namespaces should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_express_route_circuit_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_express_route_circuit_mandatory.yaml old mode 100755 new mode 100644 index c1d8fc717..da7a28586 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_express_route_circuit_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_express_route_circuit_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if ExpressRoute circuits have mandatory tags. ID: azure_mandatory_sql_resource_group_express_route_circuit_mandatory -Title: "ExpressRoute circuits should have mandatory tags" -Description: "Check if ExpressRoute circuits have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_express_route_circuit + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_express_route_circuit QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_express_route_circuit ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_express_route_circuit - ListOfTables: - - azure_express_route_circuit - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: ExpressRoute circuits should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_firewall_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_firewall_mandatory.yaml old mode 100755 new mode 100644 index e421ddfb5..b26b6b28d --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_firewall_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_firewall_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Firewalls have mandatory tags. ID: azure_mandatory_sql_resource_group_firewall_mandatory -Title: "Firewalls should have mandatory tags" -Description: "Check if Firewalls have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_firewall + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_firewall QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_firewall ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_firewall - ListOfTables: - - azure_firewall - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Firewalls should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_iothub_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_iothub_mandatory.yaml old mode 100755 new mode 100644 index 8026f06d1..78d2ce80a --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_iothub_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_iothub_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if IoT Hubs have mandatory tags. ID: azure_mandatory_sql_resource_group_iothub_mandatory -Title: "IoT Hubs should have mandatory tags" -Description: "Check if IoT Hubs have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_iothub + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_iothub QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_iothub ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_iothub - ListOfTables: - - azure_iothub - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: IoT Hubs should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_deleted_vault_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_deleted_vault_mandatory.yaml old mode 100755 new mode 100644 index 8f799a919..c843be694 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_deleted_vault_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_deleted_vault_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Key vault deleted vaults have mandatory tags. ID: azure_mandatory_sql_resource_group_key_vault_deleted_vault_mandatory -Title: "Key vault deleted vaults should have mandatory tags" -Description: "Check if Key vault deleted vaults have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_key_vault_deleted_vault + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_key_vault_deleted_vault QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_key_vault_deleted_vault ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_key_vault_deleted_vault - ListOfTables: - - azure_key_vault_deleted_vault - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Key vault deleted vaults should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_key_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_key_mandatory.yaml old mode 100755 new mode 100644 index e52fbebbd..9dae23fc8 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_key_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_key_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Key vault keys have mandatory tags. ID: azure_mandatory_sql_resource_group_key_vault_key_mandatory -Title: "Key vault keys should have mandatory tags" -Description: "Check if Key vault keys have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_key_vault_key + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_key_vault_key QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_key_vault_key ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_key_vault_key - ListOfTables: - - azure_key_vault_key - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Key vault keys should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_managed_hardware_security_module_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_managed_hardware_security_module_mandatory.yaml old mode 100755 new mode 100644 index 1532f592b..c7bd93365 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_managed_hardware_security_module_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_managed_hardware_security_module_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Key vault managed hardware security modules have mandatory tags. ID: azure_mandatory_sql_resource_group_key_vault_managed_hardware_security_module_mandatory -Title: "Key vault managed hardware security modules should have mandatory tags" -Description: "Check if Key vault managed hardware security modules have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_key_vault_managed_hardware_security_module + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_key_vault_managed_hardware_security_module QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_key_vault_managed_hardware_security_module ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_key_vault_managed_hardware_security_module - ListOfTables: - - azure_key_vault_managed_hardware_security_module - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Key vault managed hardware security modules should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_mandatory.yaml old mode 100755 new mode 100644 index 9e5b239d7..81d0f7fd8 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Key vaults have mandatory tags. ID: azure_mandatory_sql_resource_group_key_vault_mandatory -Title: "Key vaults should have mandatory tags" -Description: "Check if Key vaults have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_key_vault + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_key_vault QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_key_vault ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_key_vault - ListOfTables: - - azure_key_vault - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Key vaults should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_secret_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_secret_mandatory.yaml old mode 100755 new mode 100644 index 8011bf6a9..81458a9ef --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_secret_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_key_vault_secret_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Key vault secrets have mandatory tags. ID: azure_mandatory_sql_resource_group_key_vault_secret_mandatory -Title: "Key vault secrets should have mandatory tags" -Description: "Check if Key vault secrets have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_key_vault_secret + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_key_vault_secret QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_key_vault_secret ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_key_vault_secret - ListOfTables: - - azure_key_vault_secret - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Key vault secrets should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_kubernetes_cluster_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_kubernetes_cluster_mandatory.yaml old mode 100755 new mode 100644 index e5ed95da5..47346466c --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_kubernetes_cluster_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_kubernetes_cluster_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Kubernetes clusters have mandatory tags. ID: azure_mandatory_sql_resource_group_kubernetes_cluster_mandatory -Title: "Kubernetes clusters should have mandatory tags" -Description: "Check if Kubernetes clusters have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_kubernetes_cluster + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_kubernetes_cluster QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_kubernetes_cluster ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_kubernetes_cluster - ListOfTables: - - azure_kubernetes_cluster - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Kubernetes clusters should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_lb_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_lb_mandatory.yaml old mode 100755 new mode 100644 index 5dd66c01d..241d0043a --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_lb_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_lb_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Load balancers have mandatory tags. ID: azure_mandatory_sql_resource_group_lb_mandatory -Title: "Load balancers should have mandatory tags" -Description: "Check if Load balancers have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_lb + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_lb QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_lb ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_lb - ListOfTables: - - azure_lb - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Load balancers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_log_alert_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_log_alert_mandatory.yaml old mode 100755 new mode 100644 index ee747a197..ee26040bc --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_log_alert_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_log_alert_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Log alerts have mandatory tags. ID: azure_mandatory_sql_resource_group_log_alert_mandatory -Title: "Log alerts should have mandatory tags" -Description: "Check if Log alerts have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_log_alert + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_log_alert QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_log_alert ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Log alerts should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_log_profile_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_log_profile_mandatory.yaml old mode 100755 new mode 100644 index 8ca632ca8..1183794c5 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_log_profile_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_log_profile_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Log profiles have mandatory tags. ID: azure_mandatory_sql_resource_group_log_profile_mandatory -Title: "Log profiles should have mandatory tags" -Description: "Check if Log profiles have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_log_profile + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_log_profile QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_log_profile ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_log_profile - ListOfTables: - - azure_log_profile - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Log profiles should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_logic_app_workflow_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_logic_app_workflow_mandatory.yaml old mode 100755 new mode 100644 index f9cafa21d..3265e6c14 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_logic_app_workflow_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_logic_app_workflow_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Logic app workflows have mandatory tags. ID: azure_mandatory_sql_resource_group_logic_app_workflow_mandatory -Title: "Logic app workflows should have mandatory tags" -Description: "Check if Logic app workflows have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_logic_app_workflow + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_logic_app_workflow QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_logic_app_workflow ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_logic_app_workflow - ListOfTables: - - azure_logic_app_workflow - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Logic app workflows should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_mariadb_server_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_mariadb_server_mandatory.yaml old mode 100755 new mode 100644 index 3fc72285d..3d986b1b5 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_mariadb_server_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_mariadb_server_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if MariaDB servers have mandatory tags. ID: azure_mandatory_sql_resource_group_mariadb_server_mandatory -Title: "MariaDB servers should have mandatory tags" -Description: "Check if MariaDB servers have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_mariadb_server + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_mariadb_server QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT JSONB_OBJECT_KEYS(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_mariadb_server ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT JSONB_ARRAY_ELEMENTS_TEXT(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_mariadb_server - ListOfTables: - - azure_mariadb_server - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: MariaDB servers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_mssql_elasticpool_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_mssql_elasticpool_mandatory.yaml old mode 100755 new mode 100644 index 3a02e2b99..5eb6bea51 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_mssql_elasticpool_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_mssql_elasticpool_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Microsoft SQL elasticpools have mandatory tags. ID: azure_mandatory_sql_resource_group_mssql_elasticpool_mandatory -Title: "Microsoft SQL elasticpools should have mandatory tags" -Description: "Check if Microsoft SQL elasticpools have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_mssql_elasticpool + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_mssql_elasticpool QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_mssql_elasticpool ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_mssql_elasticpool - ListOfTables: - - azure_mssql_elasticpool - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Microsoft SQL elasticpools should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_mssql_managed_instance_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_mssql_managed_instance_mandatory.yaml old mode 100755 new mode 100644 index 3481fcdc9..93f7a25c2 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_mssql_managed_instance_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_mssql_managed_instance_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Microsoft SQL managed instances have mandatory tags. ID: azure_mandatory_sql_resource_group_mssql_managed_instance_mandatory -Title: "Microsoft SQL managed instances should have mandatory tags" -Description: "Check if Microsoft SQL managed instances have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_mssql_managed_instance + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_mssql_managed_instance QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_mssql_managed_instance ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_mssql_managed_instance - ListOfTables: - - azure_mssql_managed_instance - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Microsoft SQL managed instances should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_mysql_server_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_mysql_server_mandatory.yaml old mode 100755 new mode 100644 index a1dea1777..fabcc9774 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_mysql_server_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_mysql_server_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if MySQL servers have mandatory tags. ID: azure_mandatory_sql_resource_group_mysql_server_mandatory -Title: "MySQL servers should have mandatory tags" -Description: "Check if MySQL servers have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_mysql_server + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_mysql_server QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_mysql_server ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_mysql_server - ListOfTables: - - azure_mysql_server - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: MySQL servers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_network_interface_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_network_interface_mandatory.yaml old mode 100755 new mode 100644 index 40ce2e2fa..1c70d6c0b --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_network_interface_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_network_interface_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Network interfaces have mandatory tags. ID: azure_mandatory_sql_resource_group_network_interface_mandatory -Title: "Network interfaces should have mandatory tags" -Description: "Check if Network interfaces have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_network_interface + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_network_interface QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_network_interface ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_network_interface - ListOfTables: - - azure_network_interface - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Network interfaces should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_network_security_group_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_network_security_group_mandatory.yaml old mode 100755 new mode 100644 index 5ce33742e..d291b5799 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_network_security_group_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_network_security_group_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Network security groups have mandatory tags. ID: azure_mandatory_sql_resource_group_network_security_group_mandatory -Title: "Network security groups should have mandatory tags" -Description: "Check if Network security groups have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_network_security_group + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_network_security_group QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_network_security_group ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_network_watcher_flow_log_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_network_watcher_flow_log_mandatory.yaml old mode 100755 new mode 100644 index 031ce7e6a..76e14bf97 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_network_watcher_flow_log_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_network_watcher_flow_log_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Network watcher flow logs have mandatory tags. ID: azure_mandatory_sql_resource_group_network_watcher_flow_log_mandatory -Title: "Network watcher flow logs should have mandatory tags" -Description: "Check if Network watcher flow logs have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_network_watcher_flow_log + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_network_watcher_flow_log QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_network_watcher_flow_log ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_network_watcher_flow_log - ListOfTables: - - azure_network_watcher_flow_log - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Network watcher flow logs should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_network_watcher_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_network_watcher_mandatory.yaml old mode 100755 new mode 100644 index 8719155c7..268e52bf4 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_network_watcher_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_network_watcher_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Network watchers have mandatory tags. ID: azure_mandatory_sql_resource_group_network_watcher_mandatory -Title: "Network watchers should have mandatory tags" -Description: "Check if Network watchers have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_network_watcher + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_network_watcher QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_network_watcher ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_network_watcher - ListOfTables: - - azure_network_watcher - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Network watchers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_postgresql_server_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_postgresql_server_mandatory.yaml old mode 100755 new mode 100644 index 666414d25..7d8d42c83 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_postgresql_server_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_postgresql_server_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if PostgreSQL servers have mandatory tags. ID: azure_mandatory_sql_resource_group_postgresql_server_mandatory -Title: "PostgreSQL servers should have mandatory tags" -Description: "Check if PostgreSQL servers have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_postgresql_server + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_postgresql_server QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_postgresql_server ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_postgresql_server - ListOfTables: - - azure_postgresql_server - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: PostgreSQL servers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_public_ip_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_public_ip_mandatory.yaml old mode 100755 new mode 100644 index f12d01ac3..65c6ec0b0 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_public_ip_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_public_ip_mandatory.yaml @@ -4,32 +4,34 @@ Description: "Check if Public ips have mandatory tags." Query: Engine: steampipe-v0.5 QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_public_ip ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; PrimaryTable: azure_public_ip ListOfTables: @@ -40,4 +42,4 @@ Query: Severity: high Tags: {} IntegrationType: - - azure_subscription + - azure_subscription \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_recovery_services_vault_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_recovery_services_vault_mandatory.yaml old mode 100755 new mode 100644 index fcbaeec6b..bfb34a9be --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_recovery_services_vault_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_recovery_services_vault_mandatory.yaml @@ -1,43 +1,51 @@ +Description: Check if Recovery services vaults have mandatory tags. ID: azure_mandatory_sql_resource_group_recovery_services_vault_mandatory -Title: "Recovery services vaults should have mandatory tags" -Description: "Check if Recovery services vaults have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_recovery_services_vault + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_recovery_services_vault QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY( + SELECT jsonb_object_keys(tags) + ) AS missing_tags, + resource_group, + subscription_id + FROM azure_recovery_services_vault ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string( + ARRAY( + SELECT jsonb_array_elements_text(missing_tags) + ), ', ' + ) || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_recovery_services_vault - ListOfTables: - - azure_recovery_services_vault - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Recovery services vaults should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_redis_cache_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_redis_cache_mandatory.yaml old mode 100755 new mode 100644 index 15399a12e..0de3ead4d --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_redis_cache_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_redis_cache_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Redis caches have mandatory tags. ID: azure_mandatory_sql_resource_group_redis_cache_mandatory -Title: "Redis caches should have mandatory tags" -Description: "Check if Redis caches have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_redis_cache + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_redis_cache QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_redis_cache ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_redis_cache - ListOfTables: - - azure_redis_cache - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Redis caches should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_route_table_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_route_table_mandatory.yaml old mode 100755 new mode 100644 index 96dee758f..4c37e964a --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_route_table_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_route_table_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Route tables have mandatory tags. ID: azure_mandatory_sql_resource_group_route_table_mandatory -Title: "Route tables should have mandatory tags" -Description: "Check if Route tables have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_route_table + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_route_table QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_route_table ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_route_table - ListOfTables: - - azure_route_table - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Route tables should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_search_service_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_search_service_mandatory.yaml old mode 100755 new mode 100644 index 1f364100b..7a65b81ac --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_search_service_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_search_service_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Search services have mandatory tags. ID: azure_mandatory_sql_resource_group_search_service_mandatory -Title: "Search services should have mandatory tags" -Description: "Check if Search services have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_search_service + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_search_service QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_search_service ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_search_service - ListOfTables: - - azure_search_service - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Search services should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_servicebus_namespace_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_servicebus_namespace_mandatory.yaml old mode 100755 new mode 100644 index 10af05d52..50f3ed151 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_servicebus_namespace_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_servicebus_namespace_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Service Bus namespaces have mandatory tags. ID: azure_mandatory_sql_resource_group_servicebus_namespace_mandatory -Title: "Service Bus namespaces should have mandatory tags" -Description: "Check if Service Bus namespaces have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_servicebus_namespace + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_servicebus_namespace QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_servicebus_namespace ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_servicebus_namespace - ListOfTables: - - azure_servicebus_namespace - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Service Bus namespaces should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_sql_database_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_sql_database_mandatory.yaml old mode 100755 new mode 100644 index 50ba7432c..5eebc85e4 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_sql_database_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_sql_database_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if SQL databases have mandatory tags. ID: azure_mandatory_sql_resource_group_sql_database_mandatory -Title: "SQL databases should have mandatory tags" -Description: "Check if SQL databases have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_sql_database + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_sql_database QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_sql_database ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_sql_database - ListOfTables: - - azure_sql_database - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: SQL databases should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_sql_server_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_sql_server_mandatory.yaml old mode 100755 new mode 100644 index 27ee0254d..2c08dba3b --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_sql_server_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_sql_server_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if SQL servers have mandatory tags. ID: azure_mandatory_sql_resource_group_sql_server_mandatory -Title: "SQL servers should have mandatory tags" -Description: "Check if SQL servers have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_sql_server + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_sql_server QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_sql_server ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_sql_server - ListOfTables: - - azure_sql_server - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: SQL servers should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_storage_account_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_storage_account_mandatory.yaml old mode 100755 new mode 100644 index 12ecaa02d..e695b2986 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_storage_account_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_storage_account_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Storage accounts have mandatory tags. ID: azure_mandatory_sql_resource_group_storage_account_mandatory -Title: "Storage accounts should have mandatory tags" -Description: "Check if Storage accounts have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_storage_account + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_storage_account QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + to_jsonb('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_storage_account ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Storage accounts should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_stream_analytics_job_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_stream_analytics_job_mandatory.yaml old mode 100755 new mode 100644 index ad7d39728..d8f980c36 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_stream_analytics_job_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_stream_analytics_job_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Stream Analytics jobs have mandatory tags. ID: azure_mandatory_sql_resource_group_stream_analytics_job_mandatory -Title: "Stream Analytics jobs should have mandatory tags" -Description: "Check if Stream Analytics jobs have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_stream_analytics_job + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_stream_analytics_job QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_stream_analytics_job ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_stream_analytics_job - ListOfTables: - - azure_stream_analytics_job - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Stream Analytics jobs should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_virtual_network_gateway_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_virtual_network_gateway_mandatory.yaml old mode 100755 new mode 100644 index 934ea2279..39e58c3c9 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_virtual_network_gateway_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_virtual_network_gateway_mandatory.yaml @@ -1,43 +1,45 @@ +Description: Check if Virtual network gateways have mandatory tags. ID: azure_mandatory_sql_resource_group_virtual_network_gateway_mandatory -Title: "Virtual network gateways should have mandatory tags" -Description: "Check if Virtual network gateways have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_virtual_network_gateway + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_virtual_network_gateway QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT jsonb_object_keys(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_virtual_network_gateway ) - select + SELECT og_account_id, og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT jsonb_array_elements_text(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_virtual_network_gateway - ListOfTables: - - azure_virtual_network_gateway - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Virtual network gateways should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_resource_group_virtual_network_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_resource_group_virtual_network_mandatory.yaml old mode 100755 new mode 100644 index 14c61b301..7df47b439 --- a/compliance/controls/azure/azure_mandatory_sql_resource_group_virtual_network_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_resource_group_virtual_network_mandatory.yaml @@ -1,43 +1,46 @@ +Description: Check if Virtual networks have mandatory tags. ID: azure_mandatory_sql_resource_group_virtual_network_mandatory -Title: "Virtual networks should have mandatory tags" -Description: "Check if Virtual networks have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_virtual_network + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_virtual_network QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, - resource_group, subscription_id - from + tags ?& '{{.azureMandatoryTags}}'::TEXT[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::TEXT[]) - ARRAY(SELECT JSONB_OBJECT_KEYS(tags)) AS missing_tags, + resource_group, + subscription_id + FROM azure_virtual_network ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, - resource_group, subscription_id - from + + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || ARRAY_TO_STRING(ARRAY(SELECT JSONB_ARRAY_ELEMENTS_TEXT(missing_tags)), ', ') || '.' + END AS reason, + resource_group, + subscription_id + FROM analysis; - PrimaryTable: azure_virtual_network - ListOfTables: - - azure_virtual_network - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Virtual networks should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mandatory_sql_subscription_resource_group_mandatory.yaml b/compliance/controls/azure/azure_mandatory_sql_subscription_resource_group_mandatory.yaml old mode 100755 new mode 100644 index e4ec06adc..bea366533 --- a/compliance/controls/azure/azure_mandatory_sql_subscription_resource_group_mandatory.yaml +++ b/compliance/controls/azure/azure_mandatory_sql_subscription_resource_group_mandatory.yaml @@ -1,43 +1,48 @@ +Description: Check if Resource groups have mandatory tags. ID: azure_mandatory_sql_subscription_resource_group_mandatory -Title: "Resource groups should have mandatory tags" -Description: "Check if Resource groups have mandatory tags." +IntegrationType: + - azure_subscription Query: Engine: steampipe-v0.5 + ListOfTables: + - azure_resource_group + Parameters: + - key: azureMandatoryTags + required: true + PrimaryTable: azure_resource_group QueryToExecute: | - with analysis as ( - select + WITH analysis AS ( + SELECT og_account_id, og_resource_id, id, title, - tags ?& '{{.azureMandatoryTags}}'::text[] as has_mandatory_tags, - to_jsonb('{{.azureMandatoryTags}}'::text[]) - array(select jsonb_object_keys(tags)) as missing_tags, + tags ?& '{{.azureMandatoryTags}}'::text[] AS has_mandatory_tags, + TO_JSONB('{{.azureMandatoryTags}}'::text[]) - ARRAY( + SELECT jsonb_object_keys(tags) + ) AS missing_tags, subscription_id - from + FROM azure_resource_group ) - select - og_account_id, - og_resource_id, - id as resource, - case - when has_mandatory_tags then 'ok' - else 'alarm' - end as status, - case - when has_mandatory_tags then title || ' has all mandatory tags.' - else title || ' is missing tags: ' || array_to_string(array(select jsonb_array_elements_text(missing_tags)), ', ') || '.' - end as reason, + SELECT + og_account_id, + og_resource_id, + id AS resource, + CASE + WHEN has_mandatory_tags THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN has_mandatory_tags THEN title || ' has all mandatory tags.' + ELSE title || ' is missing tags: ' || array_to_string( + ARRAY( + SELECT jsonb_array_elements_text(missing_tags) + ), ', ') || '.' + END AS reason, subscription_id - from + FROM analysis; - PrimaryTable: azure_resource_group - ListOfTables: - - azure_resource_group - Parameters: - - key: azureMandatoryTags - required: true Severity: high Tags: {} -IntegrationType: - - azure_subscription +Title: Resource groups should have mandatory tags \ No newline at end of file diff --git a/compliance/controls/azure/azure_mariadb_server_geo_redundant_backup_enabled.yaml b/compliance/controls/azure/azure_mariadb_server_geo_redundant_backup_enabled.yaml old mode 100755 new mode 100644 index 25069f57c..ace28e860 --- a/compliance/controls/azure/azure_mariadb_server_geo_redundant_backup_enabled.yaml +++ b/compliance/controls/azure/azure_mariadb_server_geo_redundant_backup_enabled.yaml @@ -1,14 +1,35 @@ +Description: Azure Database for MariaDB allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create. ID: azure_mariadb_server_geo_redundant_backup_enabled -Title: "Geo-redundant backup should be enabled for Azure Database for MariaDB" -Description: "Azure Database for MariaDB allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when s.geo_redundant_backup_enabled = 'Enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when s.geo_redundant_backup_enabled = 'Enabled' then s.title || ' geo-redundant backup enabled.'\n else s.title || ' geo-redundant backup disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mariadb_server as s\n join azure_subscription as sub on sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mariadb_server ListOfTables: - azure_mariadb_server - azure_subscription Parameters: [] + PrimaryTable: azure_mariadb_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN s.geo_redundant_backup_enabled = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.geo_redundant_backup_enabled = 'Enabled' THEN s.title || ' geo-redundant backup enabled.' + ELSE s.title || ' geo-redundant backup disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mariadb_server AS s + JOIN + azure_subscription AS sub + ON + sub.subscription_id = s.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +38,4 @@ Tags: - "true" service: - Azure/MariaDB -IntegrationType: - - azure_subscription +Title: Geo-redundant backup should be enabled for Azure Database for MariaDB \ No newline at end of file diff --git a/compliance/controls/azure/azure_mariadb_server_public_network_access_disabled.yaml b/compliance/controls/azure/azure_mariadb_server_public_network_access_disabled.yaml old mode 100755 new mode 100644 index 85d20a9e1..32748e510 --- a/compliance/controls/azure/azure_mariadb_server_public_network_access_disabled.yaml +++ b/compliance/controls/azure/azure_mariadb_server_public_network_access_disabled.yaml @@ -1,19 +1,38 @@ +Description: Disable the public network access property to improve security and ensure your Azure Database for MariaDB can only be accessed from a private endpoint. This configuration strictly disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules. ID: azure_mariadb_server_public_network_access_disabled -Title: "Public network access should be disabled for MariaDB servers" -Description: "Disable the public network access property to improve security and ensure your Azure Database for MariaDB can only be accessed from a private endpoint. This configuration strictly disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when public_network_access = 'Enabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when public_network_access = 'Enabled' then name || ' public network access enabled.'\n else name || ' public network access disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mariadb_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mariadb_server ListOfTables: - azure_mariadb_server - azure_subscription Parameters: [] + PrimaryTable: azure_mariadb_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN name || ' public network access enabled.' + ELSE name || ' public network access disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mariadb_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/MariaDB -IntegrationType: - - azure_subscription +Title: Public network access should be disabled for MariaDB servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_mariadb_server_ssl_enabled.yaml b/compliance/controls/azure/azure_mariadb_server_ssl_enabled.yaml old mode 100755 new mode 100644 index 63520d3b4..cdd764078 --- a/compliance/controls/azure/azure_mariadb_server_ssl_enabled.yaml +++ b/compliance/controls/azure/azure_mariadb_server_ssl_enabled.yaml @@ -1,32 +1,32 @@ +Description: This control checks whether MariaDB servers SSL enforcement is enabled. This control is non-compliant if SSL enforcement is disabled. ID: azure_mariadb_server_ssl_enabled -Title: "MariaDB servers should have 'Enforce SSL connection' set to 'ENABLED'" -Description: "This control checks whether MariaDB servers SSL enforcement is enabled. This control is non-compliant if SSL enforcement is disabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when ssl_enforcement = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when ssl_enforcement = 'Enabled' then name || ' SSL connection enabled.' - else name || ' SSL connection disabled.' - end as reason - from - azure_mariadb_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_mariadb_server ListOfTables: - azure_mariadb_server - azure_subscription Parameters: [] + PrimaryTable: azure_mariadb_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ssl_enforcement = 'Enabled' THEN name || ' SSL connection enabled.' + ELSE name || ' SSL connection disabled.' + END AS reason + FROM + azure_mariadb_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: MariaDB servers should have 'Enforce SSL connection' set to 'ENABLED' \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_application_insights_configured.yaml b/compliance/controls/azure/azure_monitor_application_insights_configured.yaml old mode 100755 new mode 100644 index 8ca37097d..a7146bad6 --- a/compliance/controls/azure/azure_monitor_application_insights_configured.yaml +++ b/compliance/controls/azure/azure_monitor_application_insights_configured.yaml @@ -1,14 +1,40 @@ +Description: Application Insights within Azure act as an Application Performance Monitoring solution providing valuable data into how well an application performs and additional information when performing incident response. The types of log data collected include application metrics, telemetry data, and application trace logging data providing organizations with detailed information about application activity and application transactions. ID: azure_monitor_application_insights_configured -Title: "Ensure Application Insights are Configured" -Description: "Application Insights within Azure act as an Application Performance Monitoring solution providing valuable data into how well an application performs and additional information when performing incident response. The types of log data collected include application metrics, telemetry data, and application trace logging data providing organizations with detailed information about application activity and application transactions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with application_insights as (\n select\n subscription_id,\n count(*) as no_application_insight\n from\n azure_application_insight\n group by\n subscription_id\n)\nselect\n sub.id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when i.subscription_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when i.subscription_id is null then sub.display_name || ' does not have application insights configured.'\n else sub.display_name || ' has ' || no_application_insight || ' application insights configured.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription as sub\n left join application_insights as i on i.subscription_id = sub.subscription_id;\n" - PrimaryTable: azure_application_insight ListOfTables: - azure_application_insight - azure_subscription Parameters: [] + PrimaryTable: azure_application_insight + QueryToExecute: | + WITH application_insights AS ( + SELECT + subscription_id, + COUNT(*) AS no_application_insight + FROM + azure_application_insight + GROUP BY + subscription_id + ) + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN i.subscription_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.subscription_id IS NULL THEN sub.display_name || ' does not have application insights configured.' + ELSE sub.display_name || ' has ' || no_application_insight || ' application insights configured.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription AS sub + LEFT JOIN application_insights AS i ON i.subscription_id = sub.subscription_id; Severity: medium Tags: category: @@ -29,5 +55,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure Application Insights are Configured \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_diagnostic_settings_captures_proper_categories.yaml b/compliance/controls/azure/azure_monitor_diagnostic_settings_captures_proper_categories.yaml old mode 100755 new mode 100644 index c0c83e503..99ce3d59e --- a/compliance/controls/azure/azure_monitor_diagnostic_settings_captures_proper_categories.yaml +++ b/compliance/controls/azure/azure_monitor_diagnostic_settings_captures_proper_categories.yaml @@ -1,28 +1,34 @@ +Description: 'A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: ''Ensure that a ''Diagnostic Setting'' exists.'' The diagnostic setting should be configured to log the appropriate activities from the control/management plane.' ID: azure_monitor_diagnostic_settings_captures_proper_categories -Title: "Ensure Diagnostic Setting captures appropriate categories" -Description: "A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: 'Ensure that a 'Diagnostic Setting' exists.' The diagnostic setting should be configured to log the appropriate activities from the control/management plane." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_diagnostic_setting + - azure_subscription + Parameters: [] + PrimaryTable: azure_diagnostic_setting QueryToExecute: | - with enabled_settings as ( - select + WITH enabled_settings AS ( + SELECT name, id, - og_account_id as og_account_id, - og_resource_id as og_resource_id, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, _ctx, resource_group, subscription_id, - count(*) filter (where l ->> 'enabled' = 'true' - and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy') - ) as valid_category_count, - string_agg(l ->> 'category', ', ') filter (where l ->> 'enabled' = 'true' - and l ->> 'category' in ('Administrative', 'Security', 'Alert', 'Policy') - ) as valid_categories - from + COUNT(*) FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy') + ) AS valid_category_count, + STRING_AGG(l ->> 'category', ', ') FILTER (WHERE l ->> 'enabled' = 'true' + AND l ->> 'category' IN ('Administrative', 'Security', 'Alert', 'Policy') + ) AS valid_categories + FROM azure_diagnostic_setting, - jsonb_array_elements(logs) as l - group by + jsonb_array_elements(logs) AS l + GROUP BY name, id, og_account_id, @@ -31,33 +37,28 @@ Query: resource_group, subscription_id ) - select - sett.id as resource, - sett.og_account_id as og_account_id, - sett.og_resource_id as og_resource_id, - case - when valid_category_count = 4 then 'ok' - else 'alarm' - end as status, - case - when valid_category_count = 4 - then name || ' logs enabled for required categories administrative, security, alert and policy.' - when valid_category_count > 0 - then sett.name || ' logs enabled for ' || valid_categories || ' categories.' - else sett.name || ' logs not enabled for categories administrative, security, alert and policy.' - end as reason - , sett.resource_group as resource_group - , sub.display_name as subscription - from + SELECT + sett.id AS resource, + sett.og_account_id AS og_account_id, + sett.og_resource_id AS og_resource_id, + CASE + WHEN valid_category_count = 4 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN valid_category_count = 4 + THEN name || ' logs enabled for required categories administrative, security, alert and policy.' + WHEN valid_category_count > 0 + THEN sett.name || ' logs enabled for ' || valid_categories || ' categories.' + ELSE sett.name || ' logs not enabled for categories administrative, security, alert and policy.' + END AS reason, + sett.resource_group AS resource_group, + sub.display_name AS subscription + FROM enabled_settings sett, azure_subscription sub - where + WHERE sub.subscription_id = sett.subscription_id; - PrimaryTable: azure_diagnostic_setting - ListOfTables: - - azure_diagnostic_setting - - azure_subscription - Parameters: [] Severity: medium Tags: category: @@ -78,5 +79,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure Diagnostic Setting captures appropriate categories \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_create_policy_assignment.yaml b/compliance/controls/azure/azure_monitor_log_alert_create_policy_assignment.yaml old mode 100755 new mode 100644 index fe8a9f93e..781483b16 --- a/compliance/controls/azure/azure_monitor_log_alert_create_policy_assignment.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_create_policy_assignment.yaml @@ -1,14 +1,58 @@ +Description: Create an activity log alert for the Create Policy Assignment event. ID: azure_monitor_log_alert_create_policy_assignment -Title: "Ensure that Activity Log Alert exists for Create Policy Assignment" -Description: "Create an activity log alert for the Create Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.og_account_id as og_account_id,\n alert.og_resource_id as og_resource_id,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.authorization/policyassignments\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Authorization/policyAssignments/write\"}]'\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for create policy assignment event.'\n else 'Activity log alert does not exists for create policy assignment event.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub.subscription_id,\n sub.og_account_id,\n sub.og_resource_id,\n sub._ctx,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.og_account_id AS og_account_id, + alert.og_resource_id AS og_resource_id, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.authorization/policyassignments"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/write"}]' + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create policy assignment event.' + ELSE 'Activity log alert does not exist for create policy assignment event.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub.subscription_id, + sub.og_account_id, + sub.og_resource_id, + sub._ctx, + sub.display_name Severity: medium Tags: category: @@ -29,5 +73,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Create Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_create_update_nsg.yaml b/compliance/controls/azure/azure_monitor_log_alert_create_update_nsg.yaml old mode 100755 new mode 100644 index 29d45b954..fa44430f6 --- a/compliance/controls/azure/azure_monitor_log_alert_create_update_nsg.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_create_update_nsg.yaml @@ -1,14 +1,66 @@ +Description: Create an Activity Log Alert for the Create or Update Network Security Group event. ID: azure_monitor_log_alert_create_update_nsg -Title: "Ensure that Activity Log Alert exists for Create or Update Network Security Group" -Description: "Create an Activity Log Alert for the Create or Update Network Security Group event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and (\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/networksecuritygroups\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/networkSecurityGroups/write\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/networksecuritygroups\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Network Security Group event.'\n else 'Activity log alert does not exists for create or update Network Security Group event.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub._ctx,\n sub.subscription_id,\n sub.og_account_id,\n sub.og_resource_id,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' + ) + OR + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Network Security Group event.' + ELSE 'Activity log alert does not exist for create or update Network Security Group event.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.subscription_id, + sub.og_account_id, + sub.og_resource_id, + sub.display_name Severity: medium Tags: category: @@ -29,5 +81,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Create or Update Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_create_update_nsg_rule.yaml b/compliance/controls/azure/azure_monitor_log_alert_create_update_nsg_rule.yaml old mode 100755 new mode 100644 index b043fb5e9..5d2b801fa --- a/compliance/controls/azure/azure_monitor_log_alert_create_update_nsg_rule.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_create_update_nsg_rule.yaml @@ -1,14 +1,66 @@ +Description: Create an activity log alert for the Create or Update Network Security Group Rule event. ID: azure_monitor_log_alert_create_update_nsg_rule -Title: "Ensure that Activity Log Alert exists for Create or Update Network Security Group Rule" -Description: "Create an activity log alert for the Create or Update Network Security Group Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and (\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/networksecuritygroups/securityrules\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/networksecuritygroups/securityrules/write\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/networksecuritygroups/securityrules\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Network Security Group Rule event.'\n else 'Activity log alert does not exists for create or update Network Security Group Rule event.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub._ctx,\n sub.og_account_id,\n sub.og_resource_id,\n sub.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups/securityrules"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networksecuritygroups/securityrules/write"}]' + ) + OR + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups/securityrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Network Security Group Rule event.' + ELSE 'Activity log alert does not exist for create or update Network Security Group Rule event.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub._ctx, + sub.og_account_id, + sub.og_resource_id, + sub.subscription_id, + sub.display_name Severity: medium Tags: category: @@ -29,5 +81,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Create or Update Network Security Group Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_create_update_public_ip_address.yaml b/compliance/controls/azure/azure_monitor_log_alert_create_update_public_ip_address.yaml old mode 100755 new mode 100644 index d35099820..158d92374 --- a/compliance/controls/azure/azure_monitor_log_alert_create_update_public_ip_address.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_create_update_public_ip_address.yaml @@ -1,67 +1,64 @@ +Description: Create an activity log alert for the Create or Update Public IP Addresses rule. ID: azure_monitor_log_alert_create_update_public_ip_address -Title: "Ensure that Activity Log Alert exists for Create or Update Public IP Address rule" -Description: "Create an activity log alert for the Create or Update Public IP Addresses rule." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert QueryToExecute: | - with alert_rule as - ( - select - alert.id as alert_id, - alert.name as alert_name, + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location ILIKE 'Global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/write"}]' - ) - or + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' - and jsonb_array_length(alert.condition -> 'allOf') = 2 + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/write"}]' + ) OR ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Create or Update Public IP Address rule.' - else 'Activity Log Alert does not exists for Create or Update Public IP Address rule.' - end as reason - - , sub.display_name as subscription - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Create or Update Public IP Address rule.' + ELSE 'Activity Log Alert does not exist for Create or Update Public IP Address rule.' + END AS reason, + sub.display_name AS subscription + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub.og_account_id, sub.og_resource_id, sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: high Tags: category: @@ -82,5 +79,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Create or Update Public IP Address rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_create_update_security_solution.yaml b/compliance/controls/azure/azure_monitor_log_alert_create_update_security_solution.yaml old mode 100755 new mode 100644 index 7470234e4..e62bd3d7c --- a/compliance/controls/azure/azure_monitor_log_alert_create_update_security_solution.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_create_update_security_solution.yaml @@ -1,14 +1,66 @@ +Description: Create an activity log alert for the Create or Update Security Solution event. ID: azure_monitor_log_alert_create_update_security_solution -Title: "Ensure that Activity Log Alert exists for Create or Update Security Solution" -Description: "Create an activity log alert for the Create or Update Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and (\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Security\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.security/securitysolutions\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Security/securitySolutions/write\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Security\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.security/securitysolutions\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for create or update Security Solution event.'\n else 'Activity log alert does not exists for create or update Security Solution event.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub.og_account_id,\n sub.og_resource_id,\n sub._ctx,\n sub.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/write"}]' + ) + OR + ( + alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.security/securitysolutions"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create or update Security Solution event.' + ELSE 'Activity log alert does not exists for create or update Security Solution event.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub.og_account_id, + sub.og_resource_id, + sub._ctx, + sub.subscription_id, + sub.display_name; Severity: medium Tags: category: @@ -29,5 +81,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Create or Update Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_create_update_sql_servers_firewall_rule.yaml b/compliance/controls/azure/azure_monitor_log_alert_create_update_sql_servers_firewall_rule.yaml old mode 100755 new mode 100644 index de3f3dfc7..b5bab85d4 --- a/compliance/controls/azure/azure_monitor_log_alert_create_update_sql_servers_firewall_rule.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_create_update_sql_servers_firewall_rule.yaml @@ -1,14 +1,66 @@ +Description: Create an activity log alert for the Create or Update SQL Server Firewall Rule event. ID: azure_monitor_log_alert_create_update_sql_servers_firewall_rule -Title: "Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule" -Description: "Create an activity log alert for the Create or Update SQL Server Firewall Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as\n(\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and\n (\n ( alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.sql/servers/firewallrules\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Sql/servers/firewallRules/write\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.sql/servers/firewallrules\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Create or Update SQL Server Firewall Rule.'\n else 'Activity Log Alert does not exists for Create or Update SQL Server Firewall Rule.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub.og_account_id,\n sub.og_resource_id,\n sub._ctx,\n sub.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/write"}]' + ) + OR ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers/firewallrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN count(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN count(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Create or Update SQL Server Firewall Rule.' + ELSE 'Activity Log Alert does not exist for Create or Update SQL Server Firewall Rule.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub.og_account_id, + sub.og_resource_id, + sub._ctx, + sub.subscription_id, + sub.display_name Severity: medium Tags: category: @@ -29,5 +81,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Create or Update SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_delete_nsg.yaml b/compliance/controls/azure/azure_monitor_log_alert_delete_nsg.yaml old mode 100755 new mode 100644 index ef54e6447..516c6f9c7 --- a/compliance/controls/azure/azure_monitor_log_alert_delete_nsg.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_delete_nsg.yaml @@ -1,14 +1,67 @@ +Description: Create an activity log alert for the Delete Network Security Group event. ID: azure_monitor_log_alert_delete_nsg -Title: "Ensure that Activity Log Alert exists for Delete Network Security Group" -Description: "Create an activity log alert for the Delete Network Security Group event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id,\n jsonb_array_length(alert.condition -> 'allOf')\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and (\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/networksecuritygroups\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/networkSecurityGroups/delete\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/networksecuritygroups\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\n select\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Network Security Group event.'\n else 'Activity log alert does not exists for delete Network Security Group event.'\n end as reason\n \n , sub.display_name as subscription\n from\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\n group by\n og_account_id,\n og_resource_id,\n sub._ctx,\n sub.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id, + jsonb_array_length(alert.condition -> 'allOf') + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' + ) + OR + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/networksecuritygroups"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Network Security Group event.' + ELSE 'Activity log alert does not exist for delete Network Security Group event.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + og_account_id, + og_resource_id, + sub._ctx, + sub.subscription_id, + sub.display_name Severity: medium Tags: category: @@ -29,5 +82,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Delete Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_delete_nsg_rule.yaml b/compliance/controls/azure/azure_monitor_log_alert_delete_nsg_rule.yaml old mode 100755 new mode 100644 index bbb93c5c5..1d5b06407 --- a/compliance/controls/azure/azure_monitor_log_alert_delete_nsg_rule.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_delete_nsg_rule.yaml @@ -1,14 +1,66 @@ +Description: Create an activity log alert for the Delete Network Security Group Rule event. ID: azure_monitor_log_alert_delete_nsg_rule -Title: "Ensure that Activity Log Alert exists for Delete Network Security Group Rule" -Description: "Create an activity log alert for the Delete Network Security Group Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and (\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/networksecuritygroups/securityrules\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/networksecuritygroups/securityrules/delete\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/networksecuritygroups/securityrules\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Network Security Group Rule event.'\n else 'Activity log alert does not exists for delete Network Security Group Rule event.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub.og_account_id,\n sub.og_resource_id,\n sub._ctx,\n sub.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field":"resourceType","equals":"microsoft.network/networksecuritygroups/securityrules"}]' + AND alert.condition -> 'allOf' @> '[{"field":"operationName","equals":"Microsoft.Network/networksecuritygroups/securityrules/delete"}]' + ) + OR + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field":"resourceType","equals":"microsoft.network/networksecuritygroups/securityrules"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN count(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN count(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Network Security Group Rule event.' + ELSE 'Activity log alert does not exist for delete Network Security Group Rule event.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub.og_account_id, + sub.og_resource_id, + sub._ctx, + sub.subscription_id, + sub.display_name Severity: medium Tags: category: @@ -29,5 +81,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Delete Network Security Group Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_delete_policy_assignment.yaml b/compliance/controls/azure/azure_monitor_log_alert_delete_policy_assignment.yaml old mode 100755 new mode 100644 index d15baee2d..bb1f6a788 --- a/compliance/controls/azure/azure_monitor_log_alert_delete_policy_assignment.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_delete_policy_assignment.yaml @@ -1,14 +1,56 @@ +Description: Create an activity log alert for the Delete Policy Assignment event. ID: azure_monitor_log_alert_delete_policy_assignment -Title: "Ensure that Activity Log Alert exists for Delete Policy Assignment" -Description: "Create an activity log alert for the Delete Policy Assignment event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.authorization/policyassignments\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Authorization/policyAssignments/delete\"}]'\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for delete policy assignment event.'\n else 'Activity log alert does not exists for delete policy assignment event.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub.og_account_id,\n sub.og_resource_id,\n sub._ctx,\n sub.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.authorization/policyassignments"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Authorization/policyAssignments/delete"}]' + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete policy assignment event.' + ELSE 'Activity log alert does not exist for delete policy assignment event.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub.og_account_id, + sub.og_resource_id, + sub._ctx, + sub.subscription_id, + sub.display_name Severity: medium Tags: category: @@ -29,5 +71,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Delete Policy Assignment \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_delete_public_ip_address.yaml b/compliance/controls/azure/azure_monitor_log_alert_delete_public_ip_address.yaml old mode 100755 new mode 100644 index 3d07a9b6e..42e718a63 --- a/compliance/controls/azure/azure_monitor_log_alert_delete_public_ip_address.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_delete_public_ip_address.yaml @@ -1,14 +1,65 @@ +Description: Create an activity log alert for the Delete Public IP Address rule. ID: azure_monitor_log_alert_delete_public_ip_address -Title: "Ensure that Activity Log Alert exists for Delete Public IP Address rule" -Description: "Create an activity log alert for the Delete Public IP Address rule." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as(\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and\n (\n ( alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/publicipaddresses\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/publicIPAddresses/delete\"}]'\n )\n or\n (\n alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.network/publicipaddresses\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n )\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Delete Public IP Address rule.'\n else 'Activity Log Alert does not exists for Delete Public IP Address rule.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub.og_account_id,\n sub.og_resource_id,\n sub._ctx,\n sub.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/publicIPAddresses/delete"}]' + ) + OR ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.network/publicipaddresses"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + ) + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Delete Public IP Address rule.' + ELSE 'Activity Log Alert does not exist for Delete Public IP Address rule.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub.og_account_id, + sub.og_resource_id, + sub._ctx, + sub.subscription_id, + sub.display_name Severity: medium Tags: category: @@ -29,5 +80,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Delete Public IP Address rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_delete_security_solution.yaml b/compliance/controls/azure/azure_monitor_log_alert_delete_security_solution.yaml old mode 100755 new mode 100644 index 05c2ee62a..abe4437b0 --- a/compliance/controls/azure/azure_monitor_log_alert_delete_security_solution.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_delete_security_solution.yaml @@ -1,59 +1,59 @@ +Description: Create an activity log alert for the Delete Security Solution event. ID: azure_monitor_log_alert_delete_security_solution -Title: "Ensure that Activity Log Alert exists for Delete Security Solution" -Description: "Create an activity log alert for the Delete Security Solution event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert QueryToExecute: | - with alert_rule as ( - select - alert.id as alert_id, - alert.name as alert_name, + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location ILIKE 'Global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and ( + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( ( alert.condition -> 'allOf' @> '[{"equals":"Security","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/delete"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Security/securitySolutions/delete"}]' ) ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity log alert exists for delete Security Solution event.' - else 'Activity log alert does not exists for delete Security Solution event.' - end as reason - - , sub.display_name as subscription - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for delete Security Solution event.' + ELSE 'Activity log alert does not exist for delete Security Solution event.' + END AS reason, + sub.display_name AS subscription + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub.og_account_id, sub.og_resource_id, sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: high Tags: category: @@ -74,5 +74,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Delete Security Solution \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_delete_sql_servers_firewall_rule.yaml b/compliance/controls/azure/azure_monitor_log_alert_delete_sql_servers_firewall_rule.yaml old mode 100755 new mode 100644 index e67dd3c6a..959b76ccc --- a/compliance/controls/azure/azure_monitor_log_alert_delete_sql_servers_firewall_rule.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_delete_sql_servers_firewall_rule.yaml @@ -1,58 +1,57 @@ +Description: Create an activity log alert for the 'Delete SQL Server Firewall Rule.' ID: azure_monitor_log_alert_delete_sql_servers_firewall_rule -Title: "Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule" -Description: "Create an activity log alert for the 'Delete SQL Server Firewall Rule.'" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_log_alert + - azure_subscription + Parameters: [] + PrimaryTable: azure_log_alert QueryToExecute: | - with alert_rule as( - select - alert.id as alert_id, - alert.name as alert_name, + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, alert.enabled, alert.location, alert.subscription_id - from - azure_log_alert as alert, - jsonb_array_elements_text(scopes) as sc - where + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE alert.location ILIKE 'Global' - and alert.enabled - and sc = '/subscriptions/' || alert.subscription_id - and - ( - ( alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' - and alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/delete"}]' ) + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND ( + alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/delete"}]' ) - limit 1 + LIMIT 1 ) - select - sub.subscription_id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when count(a.subscription_id) > 0 then 'ok' - else 'alarm' - end as status, - case - when count(a.subscription_id) > 0 then 'Activity Log Alert exists for Delete SQL Server Firewall Rule.' - else 'Activity Log Alert does not exists for Delete SQL Server Firewall Rule.' - end as reason - - , sub.display_name as subscription - from + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity Log Alert exists for Delete SQL Server Firewall Rule.' + ELSE 'Activity Log Alert does not exist for Delete SQL Server Firewall Rule.' + END AS reason, + sub.display_name AS subscription + FROM azure_subscription sub - left join alert_rule a on sub.subscription_id = a.subscription_id - group by + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY sub.og_account_id, sub.og_resource_id, sub._ctx, sub.subscription_id, sub.display_name; - PrimaryTable: azure_log_alert - ListOfTables: - - azure_log_alert - - azure_subscription - Parameters: [] Severity: high Tags: category: @@ -73,5 +72,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Delete SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_for_administrative_operations.yaml b/compliance/controls/azure/azure_monitor_log_alert_for_administrative_operations.yaml old mode 100755 new mode 100644 index 09a1fc038..4e84efae9 --- a/compliance/controls/azure/azure_monitor_log_alert_for_administrative_operations.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_for_administrative_operations.yaml @@ -1,19 +1,70 @@ +Description: This policy audits specific Administrative operations with no activity log alerts configured. ID: azure_monitor_log_alert_for_administrative_operations -Title: "An activity log alert should exist for specific Administrative operations" -Description: "This policy audits specific Administrative operations with no activity log alerts configured." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and (\n alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Sql/servers/firewallRules/write\"}]'\n or alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Sql/servers/firewallRules/delete\"}]'\n or alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/networkSecurityGroups/write\"}]'\n or alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/networkSecurityGroups/delete\"}]'\n or alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.ClassicNetwork/networkSecurityGroups/write\"}]'\n or alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.ClassicNetwork/networkSecurityGroups/delete\"}]'\n or alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/networkSecurityGroups/securityRules/write\"}]'\n or alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.Network/networkSecurityGroups/securityRules/delete\"}]'\n or alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.ClassicNetwork/networkSecurityGroups/securityRules/write\"}]'\n or alert.condition -> 'allOf' @> '[{\"field\": \"operationName\", \"equals\": \"Microsoft.ClassicNetwork/networkSecurityGroups/securityRules/delete\"}]'\n )\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for administrative operations.'\n else 'Activity log alert does not exists for administrative operations.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub.og_account_id,\n sub.og_resource_id,\n sub._ctx,\n sub.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND ( + alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/write"}]' + OR alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Sql/servers/firewallRules/delete"}]' + OR alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/write"}]' + OR alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/delete"}]' + OR alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.ClassicNetwork/networkSecurityGroups/write"}]' + OR alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.ClassicNetwork/networkSecurityGroups/delete"}]' + OR alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/securityRules/write"}]' + OR alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.Network/networkSecurityGroups/securityRules/delete"}]' + OR alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.ClassicNetwork/networkSecurityGroups/securityRules/write"}]' + OR alert.condition -> 'allOf' @> '[{"field": "operationName", "equals": "Microsoft.ClassicNetwork/networkSecurityGroups/securityRules/delete"}]' + ) + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for administrative operations.' + ELSE 'Activity log alert does not exists for administrative operations.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub.og_account_id, + sub.og_resource_id, + sub._ctx, + sub.subscription_id, + sub.display_name Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: An activity log alert should exist for specific Administrative operations \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_alert_sql_firewall_rule.yaml b/compliance/controls/azure/azure_monitor_log_alert_sql_firewall_rule.yaml old mode 100755 new mode 100644 index 72de67b7e..eeaf1a6ff --- a/compliance/controls/azure/azure_monitor_log_alert_sql_firewall_rule.yaml +++ b/compliance/controls/azure/azure_monitor_log_alert_sql_firewall_rule.yaml @@ -1,14 +1,56 @@ +Description: Create an activity log alert for the Create or Update or Delete SQL Server Firewall Rule event. ID: azure_monitor_log_alert_sql_firewall_rule -Title: "Ensure that Activity Log Alert exists for Create or Update or Delete SQL Server Firewall Rule" -Description: "Create an activity log alert for the Create or Update or Delete SQL Server Firewall Rule event." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with alert_rule as (\n select\n alert.id as alert_id,\n alert.name as alert_name,\n alert.enabled,\n alert.location,\n alert.subscription_id\n from\n azure_log_alert as alert,\n jsonb_array_elements_text(scopes) as sc\n where\n alert.location = 'Global'\n and alert.enabled\n and sc = '/subscriptions/' || alert.subscription_id\n and alert.condition -> 'allOf' @> '[{\"equals\":\"Administrative\",\"field\":\"category\"}]'\n and alert.condition -> 'allOf' @> '[{\"field\": \"resourceType\", \"equals\": \"microsoft.sql/servers\"}]'\n and jsonb_array_length(alert.condition -> 'allOf') = 2\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(a.subscription_id) > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when count(a.subscription_id) > 0 then 'Activity log alert exists for create, update and delete SQL Server Firewall Rule event.'\n else 'Activity log alert does not exists for create, update and delete SQL Server Firewall Rule event.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join alert_rule a on sub.subscription_id = a.subscription_id\ngroup by\n sub.og_account_id,\n sub.og_resource_id,\n sub._ctx,\n sub.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_log_alert ListOfTables: - azure_log_alert - azure_subscription Parameters: [] + PrimaryTable: azure_log_alert + QueryToExecute: | + WITH alert_rule AS ( + SELECT + alert.id AS alert_id, + alert.name AS alert_name, + alert.enabled, + alert.location, + alert.subscription_id + FROM + azure_log_alert AS alert, + jsonb_array_elements_text(scopes) AS sc + WHERE + alert.location = 'Global' + AND alert.enabled + AND sc = '/subscriptions/' || alert.subscription_id + AND alert.condition -> 'allOf' @> '[{"equals":"Administrative","field":"category"}]' + AND alert.condition -> 'allOf' @> '[{"field": "resourceType", "equals": "microsoft.sql/servers"}]' + AND jsonb_array_length(alert.condition -> 'allOf') = 2 + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN COUNT(a.subscription_id) > 0 THEN 'Activity log alert exists for create, update and delete SQL Server Firewall Rule event.' + ELSE 'Activity log alert does not exist for create, update and delete SQL Server Firewall Rule event.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN alert_rule a ON sub.subscription_id = a.subscription_id + GROUP BY + sub.og_account_id, + sub.og_resource_id, + sub._ctx, + sub.subscription_id, + sub.display_name Severity: medium Tags: category: @@ -29,5 +71,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure that Activity Log Alert exists for Create or Update or Delete SQL Server Firewall Rule \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_analytics_workspace_integrated_with_encrypted_storage_account.yaml b/compliance/controls/azure/azure_monitor_log_analytics_workspace_integrated_with_encrypted_storage_account.yaml old mode 100755 new mode 100644 index c7709dad4..61e72f1f0 --- a/compliance/controls/azure/azure_monitor_log_analytics_workspace_integrated_with_encrypted_storage_account.yaml +++ b/compliance/controls/azure/azure_monitor_log_analytics_workspace_integrated_with_encrypted_storage_account.yaml @@ -1,24 +1,24 @@ +Description: Link storage account to Log Analytics workspace to protect saved-queries with storage account encryption. Customer-managed keys are commonly required to meet regulatory compliance and for more control over the access to your saved-queries in Azure Monitor. For more details on the above, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys?tabs ID: azure_monitor_log_analytics_workspace_integrated_with_encrypted_storage_account -Title: "Saved-queries in Azure Monitor should be saved in customer storage account for logs encryption" -Description: "Link storage account to Log Analytics workspace to protect saved-queries with storage account encryption. Customer-managed keys are commonly required to meet regulatory compliance and for more control over the access to your saved-queries in Azure Monitor. For more details on the above, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys?tabs" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Saved-queries in Azure Monitor should be saved in customer storage account for logs encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_cluster_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_monitor_log_cluster_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 7013a8dc9..364a5be86 --- a/compliance/controls/azure/azure_monitor_log_cluster_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_monitor_log_cluster_encrypted_with_cmk.yaml @@ -1,24 +1,24 @@ +Description: Create Azure Monitor logs cluster with customer-managed keys encryption. By default, the log data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance. Customer-managed key in Azure Monitor gives you more control over the access to you data, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys. ID: azure_monitor_log_cluster_encrypted_with_cmk -Title: "Azure Monitor Logs clusters should be encrypted with customer-managed key" -Description: "Create Azure Monitor logs cluster with customer-managed keys encryption. By default, the log data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance. Customer-managed key in Azure Monitor gives you more control over the access to you data, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Azure Monitor Logs clusters should be encrypted with customer-managed key \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_cluster_infrastructure_encryption_enabled.yaml b/compliance/controls/azure/azure_monitor_log_cluster_infrastructure_encryption_enabled.yaml old mode 100755 new mode 100644 index 30281f9bd..1da0eae95 --- a/compliance/controls/azure/azure_monitor_log_cluster_infrastructure_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_monitor_log_cluster_infrastructure_encryption_enabled.yaml @@ -1,24 +1,24 @@ +Description: To ensure secure data encryption is enabled at the service level and the infrastructure level with two different encryption algorithms and two different keys, use an Azure Monitor dedicated cluster. This option is enabled by default when supported at the region, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys#customer-managed-key-overview. ID: azure_monitor_log_cluster_infrastructure_encryption_enabled -Title: "Azure Monitor Logs clusters should be created with infrastructure-encryption enabled (double encryption)" -Description: "To ensure secure data encryption is enabled at the service level and the infrastructure level with two different encryption algorithms and two different keys, use an Azure Monitor dedicated cluster. This option is enabled by default when supported at the region, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys#customer-managed-key-overview." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Azure Monitor Logs clusters should be created with infrastructure-encryption enabled (double encryption) \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_profile_enabled_for_all_categories.yaml b/compliance/controls/azure/azure_monitor_log_profile_enabled_for_all_categories.yaml old mode 100755 new mode 100644 index 797e64500..411baf040 --- a/compliance/controls/azure/azure_monitor_log_profile_enabled_for_all_categories.yaml +++ b/compliance/controls/azure/azure_monitor_log_profile_enabled_for_all_categories.yaml @@ -1,19 +1,37 @@ +Description: This policy ensures that a log profile collects logs for categories 'write,' 'delete,' and 'action'. ID: azure_monitor_log_profile_enabled_for_all_categories -Title: "Azure Monitor log profile should collect logs for categories 'write,' 'delete,' and 'action'" -Description: "This policy ensures that a log profile collects logs for categories 'write,' 'delete,' and 'action'." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n p.id as resource,\n p.og_account_id as og_account_id,\n p.og_resource_id as og_resource_id,\n case\n when p.categories @> '[\"Write\", \"Action\", \"Delete\"]' then 'ok'\n else 'alarm'\n end as status,\n case\n when p.categories @> '[\"Write\", \"Action\", \"Delete\"]' then p.name || ' collects logs for categories write, delete and action'\n else p.name || ' does not collects logs for all categories.'\n end as reason\n \n , p.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_log_profile as p\n left join azure_subscription sub on sub.subscription_id = p.subscription_id;\n" - PrimaryTable: azure_log_profile ListOfTables: - azure_log_profile - azure_subscription Parameters: [] + PrimaryTable: azure_log_profile + QueryToExecute: | + SELECT + p.id AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.categories @> '["Write", "Action", "Delete"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.categories @> '["Write", "Action", "Delete"]' + THEN p.name || ' collects logs for categories write, delete and action' + ELSE p.name || ' does not collects logs for all categories.' + END AS reason, + p.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_log_profile AS p + LEFT JOIN azure_subscription sub ON sub.subscription_id = p.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Azure Monitor log profile should collect logs for categories 'write,' 'delete,' and 'action' \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_profile_enabled_for_all_regions.yaml b/compliance/controls/azure/azure_monitor_log_profile_enabled_for_all_regions.yaml old mode 100755 new mode 100644 index eb9ee55d8..d5b178cc6 --- a/compliance/controls/azure/azure_monitor_log_profile_enabled_for_all_regions.yaml +++ b/compliance/controls/azure/azure_monitor_log_profile_enabled_for_all_regions.yaml @@ -1,19 +1,36 @@ +Description: This policy audits the Azure Monitor log profile which does not export activities from all Azure supported regions including global. ID: azure_monitor_log_profile_enabled_for_all_regions -Title: "Azure Monitor should collect activity logs from all regions" -Description: "This policy audits the Azure Monitor log profile which does not export activities from all Azure supported regions including global." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n p.id as resource,\n p.og_account_id as og_account_id,\n p.og_resource_id as og_resource_id,\n case\n when p.log_event_location @> '[\"global\", \"australiacentral\", \"australiacentral2\", \"australiaeast\", \"australiasoutheast\", \"brazilsouth\", \"brazilsoutheast\", \"canadacentral\", \"canadaeast\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"francesouth\",\"germanynorth\", \"germanywestcentral\", \"japaneast\", \"japanwest\", \"jioindiawest\", \"koreacentral\", \"koreasouth\", \"northcentralus\", \"northeurope\",\n \"norwayeast\", \"norwaywest\", \"southafricanorth\", \"southafricawest\", \"southcentralus\", \"southeastasia\", \"southindia\", \"switzerlandnorth\", \"switzerlandwest\", \"uaecentral\", \"uaenorth\", \"uksouth\", \"ukwest\", \"westcentralus\", \"westeurope\", \"westindia\", \"westus\", \"westus2\", \"westus3\"]' then 'ok'\n else 'alarm'\n end as status,\n case\n when p.log_event_location @> '[\"global\", \"australiacentral\", \"australiacentral2\", \"australiaeast\", \"australiasoutheast\", \"brazilsouth\", \"brazilsoutheast\", \"canadacentral\", \"canadaeast\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"francesouth\",\"germanynorth\", \"germanywestcentral\", \"japaneast\", \"japanwest\", \"jioindiawest\", \"koreacentral\", \"koreasouth\", \"northcentralus\", \"northeurope\",\n \"norwayeast\", \"norwaywest\", \"southafricanorth\", \"southafricawest\", \"southcentralus\", \"southeastasia\", \"southindia\", \"switzerlandnorth\", \"switzerlandwest\", \"uaecentral\", \"uaenorth\", \"uksouth\", \"ukwest\", \"westcentralus\", \"westeurope\", \"westindia\", \"westus\", \"westus2\", \"westus3\"]' then p.name || ' collect activity logs from all regions.'\n else p.name || ' not collect activity logs from all regions.'\n end as reason\n \n , p.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_log_profile as p\n left join azure_subscription sub on sub.subscription_id = p.subscription_id;\n" - PrimaryTable: azure_log_profile ListOfTables: - azure_log_profile - azure_subscription Parameters: [] + PrimaryTable: azure_log_profile + QueryToExecute: | + SELECT + p.id AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.log_event_location @> '["global", "australiacentral", "australiacentral2", "australiaeast", "australiasoutheast", "brazilsouth", "brazilsoutheast", "canadacentral", "canadaeast", "centralindia", "centralus", "eastasia", "eastus", "eastus2", "francecentral", "francesouth", "germanynorth", "germanywestcentral", "japaneast", "japanwest", "jioindiawest", "koreacentral", "koreasouth", "northcentralus", "northeurope", "norwayeast", "norwaywest", "southafricanorth", "southafricawest", "southcentralus", "southeastasia", "southindia", "switzerlandnorth", "switzerlandwest", "uaecentral", "uaenorth", "uksouth", "ukwest", "westcentralus", "westeurope", "westindia", "westus", "westus2", "westus3"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.log_event_location @> '["global", "australiacentral", "australiacentral2", "australiaeast", "australiasoutheast", "brazilsouth", "brazilsoutheast", "canadacentral", "canadaeast", "centralindia", "centralus", "eastasia", "eastus", "eastus2", "francecentral", "francesouth", "germanynorth", "germanywestcentral", "japaneast", "japanwest", "jioindiawest", "koreacentral", "koreasouth", "northcentralus", "northeurope", "norwayeast", "norwaywest", "southafricanorth", "southafricawest", "southcentralus", "southeastasia", "southindia", "switzerlandnorth", "switzerlandwest", "uaecentral", "uaenorth", "uksouth", "ukwest", "westcentralus", "westeurope", "westindia", "westus", "westus2", "westus3"]' THEN p.name || ' collect activity logs from all regions.' + ELSE p.name || ' not collect activity logs from all regions.' + END AS reason, + p.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_log_profile AS p + LEFT JOIN azure_subscription sub ON sub.subscription_id = p.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Azure Monitor should collect activity logs from all regions \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_log_profile_retention_365_days.yaml b/compliance/controls/azure/azure_monitor_log_profile_retention_365_days.yaml old mode 100755 new mode 100644 index 46fba9adb..05fdee46b --- a/compliance/controls/azure/azure_monitor_log_profile_retention_365_days.yaml +++ b/compliance/controls/azure/azure_monitor_log_profile_retention_365_days.yaml @@ -1,31 +1,31 @@ +Description: This control is non-compliant if Monitor log profile retention is set to less than 365 days. ID: azure_monitor_log_profile_retention_365_days -Title: "Monitor log profiles should have retention set to 365 days or greater" -Description: "This control is non-compliant if Monitor log profile retention is set to less than 365 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - p.id as resource, - p.og_account_id as og_account_id, - p.og_resource_id as og_resource_id, - case - when p.retention_policy ->> 'enabled' = 'false' then 'alarm' - when p.retention_policy ->> 'enabled' = 'true' and (p.retention_policy ->> 'days')::int >= 365 then 'ok' - else 'alarm' - end as status, - case - when p.retention_policy ->> 'enabled' = 'false' then p.name || ' retention policy disabled.' - else p.name || ' retention is set to ' || (p.retention_policy ->> 'days') || ' day(s).' - end as reason - from - azure_log_profile as p - left join azure_subscription sub on sub.subscription_id = p.subscription_id; - PrimaryTable: azure_log_profile ListOfTables: - azure_log_profile - azure_subscription Parameters: [] + PrimaryTable: azure_log_profile + QueryToExecute: | + SELECT + p.id AS resource, + p.og_account_id AS og_account_id, + p.og_resource_id AS og_resource_id, + CASE + WHEN p.retention_policy ->> 'enabled' = 'false' THEN 'alarm' + WHEN p.retention_policy ->> 'enabled' = 'true' AND (p.retention_policy ->> 'days')::int >= 365 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.retention_policy ->> 'enabled' = 'false' THEN p.name || ' retention policy disabled.' + ELSE p.name || ' retention is set to ' || (p.retention_policy ->> 'days') || ' day(s).' + END AS reason + FROM + azure_log_profile AS p + LEFT JOIN azure_subscription sub ON sub.subscription_id = p.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Monitor log profiles should have retention set to 365 days or greater \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_logs_storage_container_encryptes_with_byok.yaml b/compliance/controls/azure/azure_monitor_logs_storage_container_encryptes_with_byok.yaml old mode 100755 new mode 100644 index 7e2219339..62715d167 --- a/compliance/controls/azure/azure_monitor_logs_storage_container_encryptes_with_byok.yaml +++ b/compliance/controls/azure/azure_monitor_logs_storage_container_encryptes_with_byok.yaml @@ -1,15 +1,39 @@ +Description: The storage account with the activity log export container is configured to use BYOK (Use Your Own Key). ID: azure_monitor_logs_storage_container_encryptes_with_byok -Title: "Ensure the storage account containing the container with activity logs is encrypted with BYOK (Use Your Own Key)" -Description: "The storage account with the activity log export container is configured to use BYOK (Use Your Own Key)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault'\n then a.name || ' container insights-operational-logs encrypted with BYOK.'\n else a.name || ' container insights-operational-logs not encrypted with BYOK.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_container c,\n azure_storage_account a,\n azure_subscription sub\nwhere\n c.name = 'insights-operational-logs'\n and c.account_name = a.name\n and sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' + THEN a.name || ' container insights-operational-logs encrypted with BYOK.' + ELSE a.name || ' container insights-operational-logs not encrypted with BYOK.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_container c, + azure_storage_account a, + azure_subscription sub + WHERE + c.name = 'insights-operational-logs' + AND c.account_name = a.name + AND sub.subscription_id = a.subscription_id Severity: medium Tags: category: @@ -30,5 +54,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure the storage account containing the container with activity logs is encrypted with BYOK (Use Your Own Key) \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_logs_storage_container_insights_activity_logs_not_public_accessible.yaml b/compliance/controls/azure/azure_monitor_logs_storage_container_insights_activity_logs_not_public_accessible.yaml old mode 100755 new mode 100644 index 541b8fe7d..f45f933b2 --- a/compliance/controls/azure/azure_monitor_logs_storage_container_insights_activity_logs_not_public_accessible.yaml +++ b/compliance/controls/azure/azure_monitor_logs_storage_container_insights_activity_logs_not_public_accessible.yaml @@ -1,34 +1,34 @@ +Description: The storage account container containing the activity log export should not be publicly accessible. ID: azure_monitor_logs_storage_container_insights_activity_logs_not_public_accessible -Title: "Ensure the Storage Container Storing the Activity Logs is not Publicly Accessible" -Description: "The storage account container containing the activity log export should not be publicly accessible." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc.id as resource, - sc.og_account_id as og_account_id, - sc.og_resource_id as og_resource_id, - case - when public_access != 'None' then 'alarm' - else 'ok' - end as status, - case - when public_access != 'None' - then account_name || ' container insights-activity-logs storing activity logs publicly accessible.' - else account_name || ' container insights-activity-logs storing activity logs not publicly accessible.' - end as reason - from - azure_storage_container sc, - azure_subscription sub - where - name = 'insights-activity-logs' - and sub.subscription_id = sc.subscription_id; - PrimaryTable: azure_storage_container ListOfTables: - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_container + QueryToExecute: | + SELECT + sc.id AS resource, + sc.og_account_id AS og_account_id, + sc.og_resource_id AS og_resource_id, + CASE + WHEN public_access != 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_access != 'None' + THEN account_name || ' container insights-activity-logs storing activity logs publicly accessible.' + ELSE account_name || ' container insights-activity-logs storing activity logs not publicly accessible.' + END AS reason + FROM + azure_storage_container sc, + azure_subscription sub + WHERE + name = 'insights-activity-logs' + AND sub.subscription_id = sc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Ensure the Storage Container Storing the Activity Logs is not Publicly Accessible \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_logs_storage_container_insights_operational_logs_not_public_accessible.yaml b/compliance/controls/azure/azure_monitor_logs_storage_container_insights_operational_logs_not_public_accessible.yaml old mode 100755 new mode 100644 index 0bf287015..c79d2d34c --- a/compliance/controls/azure/azure_monitor_logs_storage_container_insights_operational_logs_not_public_accessible.yaml +++ b/compliance/controls/azure/azure_monitor_logs_storage_container_insights_operational_logs_not_public_accessible.yaml @@ -1,34 +1,34 @@ +Description: The storage account container containing the operational log export should not be publicly accessible. ID: azure_monitor_logs_storage_container_insights_operational_logs_not_public_accessible -Title: "Ensure the storage container storing the operational logs is not publicly accessible" -Description: "The storage account container containing the operational log export should not be publicly accessible." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sc.id as resource, - sc.og_account_id as og_account_id, - sc.og_resource_id as og_resource_id, - case - when public_access != 'None' then 'alarm' - else 'ok' - end as status, - case - when public_access != 'None' - then account_name || ' container insights-operational-logs storing activity logs publicly accessible.' - else account_name || ' container insights-operational-logs storing activity logs not publicly accessible.' - end as reason - from - azure_storage_container sc, - azure_subscription sub - where - name = 'insights-operational-logs' - and sub.subscription_id = sc.subscription_id; - PrimaryTable: azure_storage_container ListOfTables: - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_container + QueryToExecute: | + SELECT + sc.id AS resource, + sc.og_account_id AS og_account_id, + sc.og_resource_id AS og_resource_id, + CASE + WHEN public_access != 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_access != 'None' + THEN account_name || ' container insights-operational-logs storing activity logs publicly accessible.' + ELSE account_name || ' container insights-operational-logs storing activity logs not publicly accessible.' + END AS reason + FROM + azure_storage_container sc, + azure_subscription sub + WHERE + name = 'insights-operational-logs' + AND sub.subscription_id = sc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Ensure the storage container storing the operational logs is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/azure/azure_monitor_logs_storage_container_not_public_accessible.yaml b/compliance/controls/azure/azure_monitor_logs_storage_container_not_public_accessible.yaml old mode 100755 new mode 100644 index ee45c12b9..3d3834ee6 --- a/compliance/controls/azure/azure_monitor_logs_storage_container_not_public_accessible.yaml +++ b/compliance/controls/azure/azure_monitor_logs_storage_container_not_public_accessible.yaml @@ -1,35 +1,36 @@ +Description: The storage account container containing the activity log export should not be publicly accessible. ID: azure_monitor_logs_storage_container_not_public_accessible -Title: "Ensure the storage container storing the activity logs is not publicly accessible" -Description: "The storage account container containing the activity log export should not be publicly accessible." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - sc.id as resource, - sc.og_account_id as og_account_id, - sc.og_resource_id as og_resource_id, - case - when public_access != 'None' then 'alarm' - else 'ok' - end as status, - case - when public_access != 'None' - then account_name || ' container insights-operational-logs storing activity logs publicly accessible.' - else account_name || ' container insights-operational-logs storing activity logs not publicly accessible.' - end as reason - , sc.resource_group as resource_group - , sub.display_name as subscription - from - azure_storage_container sc, - azure_subscription sub - where - name LIKE 'insight%logs%' - and sub.subscription_id = sc.subscription_id; - PrimaryTable: azure_storage_container ListOfTables: - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_container + QueryToExecute: | + SELECT + sc.id AS resource, + sc.og_account_id AS og_account_id, + sc.og_resource_id AS og_resource_id, + CASE + WHEN public_access != 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_access != 'None' + THEN account_name || ' container insights-operational-logs storing activity logs publicly accessible.' + ELSE account_name || ' container insights-operational-logs storing activity logs not publicly accessible.' + END AS reason, + sc.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_container sc, + azure_subscription sub + WHERE + name LIKE 'insight%logs%' + AND sub.subscription_id = sc.subscription_id; Severity: high Tags: category: @@ -50,5 +51,4 @@ Tags: - azure service: - Azure/Monitor -IntegrationType: - - azure_subscription +Title: Ensure the storage container storing the activity logs is not publicly accessible \ No newline at end of file diff --git a/compliance/controls/azure/azure_mssql_managed_instance_encryption_at_rest_using_cmk.yaml b/compliance/controls/azure/azure_mssql_managed_instance_encryption_at_rest_using_cmk.yaml old mode 100755 new mode 100644 index a0d526247..adacce330 --- a/compliance/controls/azure/azure_mssql_managed_instance_encryption_at_rest_using_cmk.yaml +++ b/compliance/controls/azure/azure_mssql_managed_instance_encryption_at_rest_using_cmk.yaml @@ -1,14 +1,45 @@ +Description: Implementing Transparent Data Encryption (TDE) with your own key provides you with increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. This recommendation applies to organizations with a related compliance requirement. ID: azure_mssql_managed_instance_encryption_at_rest_using_cmk -Title: "SQL managed instances should use customer-managed keys to encrypt data at rest" -Description: "Implementing Transparent Data Encryption (TDE) with your own key provides you with increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. This recommendation applies to organizations with a related compliance requirement." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with encryption_protector as (\n select\n distinct i.id as id\n from\n azure_mssql_managed_instance as i,\n jsonb_array_elements(encryption_protectors) a\n where\n a ->> 'serverKeyType' = 'AzureKeyVault'\n and a ->> 'uri' is not null\n)\nselect\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when a.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.id is not null then s.title || ' encrypted with CMK.'\n else s.title || ' not encrypted with CMK.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mssql_managed_instance as s\n left join encryption_protector as a on s.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mssql_managed_instance ListOfTables: - azure_mssql_managed_instance - azure_subscription Parameters: [] + PrimaryTable: azure_mssql_managed_instance + QueryToExecute: | + WITH encryption_protector AS ( + SELECT + DISTINCT i.id AS id + FROM + azure_mssql_managed_instance AS i, + jsonb_array_elements(encryption_protectors) a + WHERE + a ->> 'serverKeyType' = 'AzureKeyVault' + AND a ->> 'uri' IS NOT NULL + ) + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN a.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.id IS NOT NULL THEN s.title || ' encrypted with CMK.' + ELSE s.title || ' not encrypted with CMK.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mssql_managed_instance AS s + LEFT JOIN encryption_protector AS a ON s.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id Severity: high Tags: hipaa_hitrust_v92: @@ -17,5 +48,4 @@ Tags: - "true" service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: SQL managed instances should use customer-managed keys to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_mssql_managed_instance_vulnerability_assessment_enabled.yaml b/compliance/controls/azure/azure_mssql_managed_instance_vulnerability_assessment_enabled.yaml old mode 100755 new mode 100644 index a6157e79c..a0d67ee5a --- a/compliance/controls/azure/azure_mssql_managed_instance_vulnerability_assessment_enabled.yaml +++ b/compliance/controls/azure/azure_mssql_managed_instance_vulnerability_assessment_enabled.yaml @@ -1,14 +1,45 @@ +Description: Audit each SQL Managed Instance which doesn't have recurring vulnerability assessment scans enabled. Vulnerability assessment can discover, track, and help you remediate potential database vulnerabilities. ID: azure_mssql_managed_instance_vulnerability_assessment_enabled -Title: "Vulnerability assessment should be enabled on SQL Managed Instance" -Description: "Audit each SQL Managed Instance which doesn't have recurring vulnerability assessment scans enabled. Vulnerability assessment can discover, track, and help you remediate potential database vulnerabilities." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vulnerability_assessments as (\n select\n distinct i.id as id\n from\n azure_mssql_managed_instance as i,\n jsonb_array_elements(vulnerability_assessments) a\n where\n a -> 'recurringScans' ->> 'isEnabled' = 'true'\n and a ->> 'name' = 'Default'\n)\nselect\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when a.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.id is not null then s.title || ' vulnerability assessment enabled.'\n else s.title || ' vulnerability assessment disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mssql_managed_instance as s\n left join vulnerability_assessments as a on s.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mssql_managed_instance ListOfTables: - azure_mssql_managed_instance - azure_subscription Parameters: [] + PrimaryTable: azure_mssql_managed_instance + QueryToExecute: | + WITH vulnerability_assessments AS ( + SELECT + DISTINCT i.id AS id + FROM + azure_mssql_managed_instance AS i, + jsonb_array_elements(vulnerability_assessments) a + WHERE + a -> 'recurringScans' ->> 'isEnabled' = 'true' + AND a ->> 'name' = 'Default' + ) + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN a.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.id IS NOT NULL THEN s.title || ' vulnerability assessment enabled.' + ELSE s.title || ' vulnerability assessment disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mssql_managed_instance AS s + LEFT JOIN vulnerability_assessments AS a ON s.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +48,4 @@ Tags: - "true" service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: Vulnerability assessment should be enabled on SQL Managed Instance \ No newline at end of file diff --git a/compliance/controls/azure/azure_mysql_db_server_geo_redundant_backup_enabled.yaml b/compliance/controls/azure/azure_mysql_db_server_geo_redundant_backup_enabled.yaml old mode 100755 new mode 100644 index 9a06c06e0..854272491 --- a/compliance/controls/azure/azure_mysql_db_server_geo_redundant_backup_enabled.yaml +++ b/compliance/controls/azure/azure_mysql_db_server_geo_redundant_backup_enabled.yaml @@ -1,14 +1,34 @@ +Description: Azure Database for MySQL allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create. ID: azure_mysql_db_server_geo_redundant_backup_enabled -Title: "Geo-redundant backup should be enabled for Azure Database for MySQL" -Description: "Azure Database for MySQL allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when geo_redundant_backup = 'Enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when geo_redundant_backup = 'Enabled' then name || ' Geo-redundant backup enabled.'\n else name || ' Geo-redundant backup disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mysql_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN geo_redundant_backup = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN geo_redundant_backup = 'Enabled' THEN name || ' Geo-redundant backup enabled.' + ELSE name || ' Geo-redundant backup disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +37,4 @@ Tags: - "true" service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: Geo-redundant backup should be enabled for Azure Database for MySQL \ No newline at end of file diff --git a/compliance/controls/azure/azure_mysql_server_audit_logging_enabled.yaml b/compliance/controls/azure/azure_mysql_server_audit_logging_enabled.yaml old mode 100755 new mode 100644 index 07b9dedba..263f058b7 --- a/compliance/controls/azure/azure_mysql_server_audit_logging_enabled.yaml +++ b/compliance/controls/azure/azure_mysql_server_audit_logging_enabled.yaml @@ -1,14 +1,36 @@ +Description: Enable audit logging on MySQL Servers. ID: azure_mysql_server_audit_logging_enabled -Title: "Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL Database Server" -Description: "Enable audit logging on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter audit_log_enabled off.'\n else s.name || ' server parameter audit_log_enabled on.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mysql_server as s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'audit_log_enabled'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter audit_log_enabled off.' + ELSE s.name || ' server parameter audit_log_enabled on.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mysql_server AS s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'audit_log_enabled' + AND sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_mysql_server_audit_logging_events_connection_set.yaml b/compliance/controls/azure/azure_mysql_server_audit_logging_events_connection_set.yaml old mode 100755 new mode 100644 index 0e2714981..6435ffa15 --- a/compliance/controls/azure/azure_mysql_server_audit_logging_events_connection_set.yaml +++ b/compliance/controls/azure/azure_mysql_server_audit_logging_events_connection_set.yaml @@ -1,14 +1,36 @@ +Description: Set audit_log_enabled to include CONNECTION on MySQL Servers. ID: azure_mysql_server_audit_logging_events_connection_set -Title: "Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL Database Server" -Description: "Set audit_log_enabled to include CONNECTION on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') = 'connection' then 'ok'\n else 'alarm'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') = 'connection' then s.name || ' server parameter audit_log_events has connection set.'\n else s.name || ' server parameter audit_log_events connection not set.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mysql_server as s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'audit_log_events'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') = 'connection' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') = 'connection' THEN s.name || ' server parameter audit_log_events has connection set.' + ELSE s.name || ' server parameter audit_log_events connection not set.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mysql_server AS s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'audit_log_events' + AND sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_mysql_server_encrypted_at_rest_using_cmk.yaml b/compliance/controls/azure/azure_mysql_server_encrypted_at_rest_using_cmk.yaml old mode 100755 new mode 100644 index 586a7339b..eec22714f --- a/compliance/controls/azure/azure_mysql_server_encrypted_at_rest_using_cmk.yaml +++ b/compliance/controls/azure/azure_mysql_server_encrypted_at_rest_using_cmk.yaml @@ -1,19 +1,49 @@ +Description: Use customer-managed keys to manage the encryption at rest of your MySQL servers. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_mysql_server_encrypted_at_rest_using_cmk -Title: "MySQL servers should use customer-managed keys to encrypt data at rest" -Description: "Use customer-managed keys to manage the encryption at rest of your MySQL servers. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with mysql_server_encrypted as (\n select\n distinct i.id as id\n from\n azure_mysql_server as i,\n jsonb_array_elements(server_keys) a\n where\n a ->> 'serverKeyType' = 'AzureKeyVault'\n and a ->> 'uri' is not null\n)\nselect\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when a.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.id is not null then s.title || ' encrypted with CMK.'\n else s.title || ' not encrypted with CMK.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mysql_server as s\n left join mysql_server_encrypted as a on s.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + WITH mysql_server_encrypted AS ( + SELECT + DISTINCT i.id AS id + FROM + azure_mysql_server AS i, + jsonb_array_elements(server_keys) a + WHERE + a ->> 'serverKeyType' = 'AzureKeyVault' + AND a ->> 'uri' IS NOT NULL + ) + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN a.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.id IS NOT NULL THEN s.title || ' encrypted with CMK.' + ELSE s.title || ' not encrypted with CMK.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mysql_server AS s + LEFT JOIN mysql_server_encrypted AS a ON s.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: MySQL servers should use customer-managed keys to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_mysql_server_infrastructure_encryption_enabled.yaml b/compliance/controls/azure/azure_mysql_server_infrastructure_encryption_enabled.yaml old mode 100755 new mode 100644 index 39a4119a3..bf1191ca4 --- a/compliance/controls/azure/azure_mysql_server_infrastructure_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_mysql_server_infrastructure_encryption_enabled.yaml @@ -1,19 +1,38 @@ +Description: Enable infrastructure encryption for Azure Database for MySQL servers to have a higher level of assurance that the data is secure. When infrastructure encryption is enabled, the data at rest is encrypted twice using FIPS 140-2 compliant Microsoft managed keys. ID: azure_mysql_server_infrastructure_encryption_enabled -Title: "Infrastructure encryption should be enabled for Azure Database for MySQL servers" -Description: "Enable infrastructure encryption for Azure Database for MySQL servers to have higher level of assurance that the data is secure. When infrastructure encryption is enabled, the data at rest is encrypted twice using FIPS 140-2 compliant Microsoft managed keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when infrastructure_encryption = 'Enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when infrastructure_encryption = 'Enabled' then s.name || ' infrastructure encryption enabled.'\n else s.name || ' infrastructure encryption disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mysql_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN s.name || ' infrastructure encryption enabled.' + ELSE s.name || ' infrastructure encryption disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: Infrastructure encryption should be enabled for Azure Database for MySQL servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_mysql_server_min_tls_1_2.yaml b/compliance/controls/azure/azure_mysql_server_min_tls_1_2.yaml old mode 100755 new mode 100644 index e76546ccc..39f923f30 --- a/compliance/controls/azure/azure_mysql_server_min_tls_1_2.yaml +++ b/compliance/controls/azure/azure_mysql_server_min_tls_1_2.yaml @@ -1,14 +1,36 @@ +Description: Ensure TLS version on MySQL flexible servers is set to the default value. ID: azure_mysql_server_min_tls_1_2 -Title: "Ensure 'TLS Version' is set to 'TLSV1.2' for MySQL flexible Database Server" -Description: "Ensure TLS version on MySQL flexible servers is set to the default value." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when minimal_tls_version = 'TLSEnforcementDisabled' then 'alarm'\n when minimal_tls_version = 'TLS1_2' then 'ok'\n else 'alarm'\n end as status,\n case\n when minimal_tls_version = 'TLSEnforcementDisabled' then s.name || ' TLS enforcement is disabled.'\n when minimal_tls_version = 'TLS1_2' then s.name || ' minimum TLS version set to ' || minimal_tls_version || '.'\n else s.name || ' minimum TLS version set to ' || minimal_tls_version || '.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mysql_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN minimal_tls_version = 'TLSEnforcementDisabled' THEN 'alarm' + WHEN minimal_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimal_tls_version = 'TLSEnforcementDisabled' THEN s.name || ' TLS enforcement is disabled.' + WHEN minimal_tls_version = 'TLS1_2' THEN s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' + ELSE s.name || ' minimum TLS version set to ' || minimal_tls_version || '.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: Ensure 'TLS Version' is set to 'TLSV1.2' for MySQL flexible Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_mysql_server_private_link_used.yaml b/compliance/controls/azure/azure_mysql_server_private_link_used.yaml old mode 100755 new mode 100644 index 64279b3e8..895085a73 --- a/compliance/controls/azure/azure_mysql_server_private_link_used.yaml +++ b/compliance/controls/azure/azure_mysql_server_private_link_used.yaml @@ -1,19 +1,38 @@ +Description: Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for MySQL. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure. ID: azure_mysql_server_private_link_used -Title: "Private endpoint should be enabled for MySQL servers" -Description: "Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for MySQL. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when sku_tier = 'Basic' then 'skip'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then 'ok'\n else 'alarm'\n end as status,\n case\n when sku_tier = 'Basic' then a.name || ' is of ' || sku_tier || ' tier.'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then a.name || ' using private link.'\n else a.name || ' not using private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mysql_server a,\n azure_subscription sub;\n" - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_tier = 'Basic' THEN 'skip' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_tier = 'Basic' THEN a.name || ' is of ' || sku_tier || ' tier.' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN a.name || ' using private link.' + ELSE a.name || ' not using private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mysql_server a, + azure_subscription sub; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: Private endpoint should be enabled for MySQL servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_mysql_server_public_network_access_disabled.yaml b/compliance/controls/azure/azure_mysql_server_public_network_access_disabled.yaml old mode 100755 new mode 100644 index b28fbdbfd..923677c02 --- a/compliance/controls/azure/azure_mysql_server_public_network_access_disabled.yaml +++ b/compliance/controls/azure/azure_mysql_server_public_network_access_disabled.yaml @@ -1,19 +1,38 @@ +Description: Disable the public network access property to improve security and ensure your Azure Database for MySQL can only be accessed from a private endpoint. This configuration strictly disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules. ID: azure_mysql_server_public_network_access_disabled -Title: "Public network access should be disabled for MySQL servers" -Description: "Disable the public network access property to improve security and ensure your Azure Database for MySQL can only be accessed from a private endpoint. This configuration strictly disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when public_network_access = 'Enabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when public_network_access = 'Enabled' then name || ' public network access enabled.'\n else name || ' public network access disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mysql_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN name || ' public network access enabled.' + ELSE name || ' public network access disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: Public network access should be disabled for MySQL servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_mysql_ssl_enabled.yaml b/compliance/controls/azure/azure_mysql_ssl_enabled.yaml old mode 100755 new mode 100644 index 64c5e9f66..9cc82cd20 --- a/compliance/controls/azure/azure_mysql_ssl_enabled.yaml +++ b/compliance/controls/azure/azure_mysql_ssl_enabled.yaml @@ -1,14 +1,34 @@ +Description: Azure Database for MySQL supports connecting your Azure Database for MySQL server to client applications using Secure Sockets Layer (SSL). Enforcing SSL connections between your database server and your client applications helps protect against 'man in the middle' attacks by encrypting the data stream between the server and your application. This configuration enforces that SSL is always enabled for accessing your database server. ID: azure_mysql_ssl_enabled -Title: "Enforce SSL connection should be enabled for MySQL database servers" -Description: "Azure Database for MySQL supports connecting your Azure Database for MySQL server to client applications using Secure Sockets Layer (SSL). Enforcing SSL connections between your database server and your client applications helps protect against 'man in the middle' attacks by encrypting the data stream between the server and your application. This configuration enforces that SSL is always enabled for accessing your database server." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when ssl_enforcement = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when ssl_enforcement = 'Disabled' then s.name || ' SSL connection disabled.'\n else s.name || ' SSL connection enabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_mysql_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN s.name || ' SSL connection disabled.' + ELSE s.name || ' SSL connection enabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mysql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/MySQL -IntegrationType: - - azure_subscription +Title: Enforce SSL connection should be enabled for MySQL database servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_bastion_host_min_1.yaml b/compliance/controls/azure/azure_network_bastion_host_min_1.yaml old mode 100755 new mode 100644 index 109e1d641..8017e1902 --- a/compliance/controls/azure/azure_network_bastion_host_min_1.yaml +++ b/compliance/controls/azure/azure_network_bastion_host_min_1.yaml @@ -1,46 +1,47 @@ +Description: The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service. ID: azure_network_bastion_host_min_1 -Title: "Ensure an Azure Bastion Host exists" -Description: "The Azure Bastion service allows secure remote access to Azure Virtual Machines over the Internet without exposing remote access protocol ports and services directly to the Internet. The Azure Bastion service provides this access using TLS over 443/TCP, and subscribes to hardened configurations within an organization's Azure Active Directory service." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_bastion_host + - azure_subscription + Parameters: [] + PrimaryTable: azure_bastion_host QueryToExecute: | - with bastion_hosts as ( - select + WITH bastion_hosts AS ( + SELECT subscription_id, _ctx, region, resource_group, - count(*) as no_bastion_host - from + COUNT(*) AS no_bastion_host + FROM azure_bastion_host - group by + GROUP BY subscription_id, _ctx, resource_group, region ) - select - sub.id as resource, - sub.og_account_id as og_account_id, - sub.og_resource_id as og_resource_id, - case - when i.subscription_id is null then 'alarm' - else 'ok' - end as status, - case - when i.subscription_id is null then sub.display_name || ' does not have bastion host.' - else sub.display_name || ' has ' || no_bastion_host || ' bastion host(s).' - end as reason - , i.resource_group as resource_group - , sub.display_name as subscription - from - azure_subscription as sub - left join bastion_hosts as i on i.subscription_id = sub.subscription_id; - PrimaryTable: azure_bastion_host - ListOfTables: - - azure_bastion_host - - azure_subscription - Parameters: [] + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN i.subscription_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.subscription_id IS NULL THEN sub.display_name || ' does not have bastion host.' + ELSE sub.display_name || ' has ' || no_bastion_host || ' bastion host(s).' + END AS reason, + i.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_subscription AS sub + LEFT JOIN bastion_hosts AS i ON i.subscription_id = sub.subscription_id; Severity: medium Tags: category: @@ -61,5 +62,4 @@ Tags: - azure service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: Ensure an Azure Bastion Host exists \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_ddos_enabled.yaml b/compliance/controls/azure/azure_network_ddos_enabled.yaml old mode 100755 new mode 100644 index 4464fd897..edc14141e --- a/compliance/controls/azure/azure_network_ddos_enabled.yaml +++ b/compliance/controls/azure/azure_network_ddos_enabled.yaml @@ -1,20 +1,47 @@ +Description: DDoS protection standard should be enabled for all virtual networks with a subnet that is part of an application gateway with a public IP. ID: azure_network_ddos_enabled -Title: "Azure DDoS Protection Standard should be enabled" -Description: "DDoS protection standard should be enabled for all virtual networks with a subnet that is part of an application gateway with a public IP." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with application_gateway_subnet as (\n select\n distinct (split_part(c -> 'properties' -> 'subnet' ->> 'id', '/', 9)) as vn_name\n from\n azure_application_gateway as ag,\n jsonb_array_elements(gateway_ip_configurations) as c\n)\nselect\n a.name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.vn_name is null then 'ok'\n when b.vn_name is not null and enable_ddos_protection::bool then 'ok'\n else 'alarm'\n end as status,\n case\n when b.vn_name is null then 'DDoS protection not required.'\n when b.vn_name is not null and enable_ddos_protection::bool then a.name || ' DDoS protection enabled.'\n else a.name || ' DDoS protection disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_virtual_network as a\n left join application_gateway_subnet as b on a.name = b.vn_name\n join azure_subscription sub on sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_virtual_network ListOfTables: - azure_application_gateway - azure_subscription - azure_virtual_network Parameters: [] + PrimaryTable: azure_virtual_network + QueryToExecute: | + WITH application_gateway_subnet AS ( + SELECT + DISTINCT (SPLIT_PART(c -> 'properties' -> 'subnet' ->> 'id', '/', 9)) AS vn_name + FROM + azure_application_gateway AS ag, + JSONB_ARRAY_ELEMENTS(gateway_ip_configurations) AS c + ) + SELECT + a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.vn_name IS NULL THEN 'ok' + WHEN b.vn_name IS NOT NULL AND enable_ddos_protection::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.vn_name IS NULL THEN 'DDoS protection not required.' + WHEN b.vn_name IS NOT NULL AND enable_ddos_protection::bool THEN a.name || ' DDoS protection enabled.' + ELSE a.name || ' DDoS protection disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_virtual_network AS a + LEFT JOIN application_gateway_subnet AS b ON a.name = b.vn_name + JOIN azure_subscription sub ON sub.subscription_id = a.subscription_id Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Azure DDoS Protection Standard should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_interface_ip_forwarding_disabled.yaml b/compliance/controls/azure/azure_network_interface_ip_forwarding_disabled.yaml old mode 100755 new mode 100644 index 6b6b50730..14032bdd2 --- a/compliance/controls/azure/azure_network_interface_ip_forwarding_disabled.yaml +++ b/compliance/controls/azure/azure_network_interface_ip_forwarding_disabled.yaml @@ -1,20 +1,53 @@ +Description: Enabling IP forwarding on a virtual machine's NIC allows the machine to receive traffic addressed to other destinations. IP forwarding is rarely required (e.g., when using the VM as a network virtual appliance), and therefore, this should be reviewed by the network security team. ID: azure_network_interface_ip_forwarding_disabled -Title: "IP Forwarding on your virtual machine should be disabled" -Description: "Enabling IP forwarding on a virtual machine's NIC allows the machine to receive traffic addressed to other destinations. IP forwarding is rarely required (e.g., when using the VM as a network virtual appliance), and therefore, this should be reviewed by the network security team." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vm_using_nic as (\n select\n id as vm_id,\n name as vm_name,\n resource_group,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n _ctx,\n region,\n subscription_id,\n b ->> 'id' as nic_id\n from\n azure_compute_virtual_machine as c,\n jsonb_array_elements(network_interfaces) as b\n)\nselect\n v.vm_id as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when i.enable_ip_forwarding then 'alarm'\n else 'ok'\n end as status,\n case\n when i.enable_ip_forwarding then v.vm_name || ' using ' || i.name || ' network interface enabled with IP forwarding.'\n else v.vm_name || ' using ' || i.name || ' network interface disabled with IP forwarding.'\n end as reason\n \n , v.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_subscription as sub,\n vm_using_nic as v\n left join azure_network_interface as i on i.id = v.nic_id;\n" - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_network_interface - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + WITH vm_using_nic AS ( + SELECT + id AS vm_id, + name AS vm_name, + resource_group, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + _ctx, + region, + subscription_id, + b ->> 'id' AS nic_id + FROM + azure_compute_virtual_machine AS c, + jsonb_array_elements(network_interfaces) AS b + ) + SELECT + v.vm_id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN i.enable_ip_forwarding THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.enable_ip_forwarding THEN v.vm_name || ' using ' || i.name || ' network interface enabled with IP forwarding.' + ELSE v.vm_name || ' using ' || i.name || ' network interface disabled with IP forwarding.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_subscription AS sub, + vm_using_nic AS v + LEFT JOIN azure_network_interface AS i ON i.id = v.nic_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Compute -IntegrationType: - - azure_subscription +Title: IP Forwarding on your virtual machine should be disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_lb_no_basic_sku.yaml b/compliance/controls/azure/azure_network_lb_no_basic_sku.yaml old mode 100755 new mode 100644 index 0ab2af468..1c41de655 --- a/compliance/controls/azure/azure_network_lb_no_basic_sku.yaml +++ b/compliance/controls/azure/azure_network_lb_no_basic_sku.yaml @@ -1,19 +1,38 @@ +Description: The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft will usually refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads. ID: azure_network_lb_no_basic_sku -Title: "Network load balancers should use standard SKUs as a minimum" -Description: "The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft will usually refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n l.id as resource,\n l.og_account_id as og_account_id,\n l.og_resource_id as og_resource_id,\n case\n when l.sku_name = 'Basic' then 'alarm'\n else 'ok'\n end as status,\n case\n when l.sku_name = 'Basic' then l.title || ' using basic SKU.'\n else l.title || ' using ' || sku_name || ' SKU.'\n end as reason\n \n , l.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_lb as l,\n azure_subscription as sub\nwhere\n sub.subscription_id = l.subscription_id;\n" - PrimaryTable: azure_lb ListOfTables: - azure_lb - azure_subscription Parameters: [] + PrimaryTable: azure_lb + QueryToExecute: | + SELECT + l.id AS resource, + l.og_account_id AS og_account_id, + l.og_resource_id AS og_resource_id, + CASE + WHEN l.sku_name = 'Basic' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN l.sku_name = 'Basic' THEN l.title || ' using basic SKU.' + ELSE l.title || ' using ' || sku_name || ' SKU.' + END AS reason, + l.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_lb AS l, + azure_subscription AS sub + WHERE + sub.subscription_id = l.subscription_id; Severity: medium Tags: cis: - "true" service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Network load balancers should use standard SKUs as a minimum \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_network_peering_connected.yaml b/compliance/controls/azure/azure_network_network_peering_connected.yaml old mode 100755 new mode 100644 index fd4427e72..8b74aebce --- a/compliance/controls/azure/azure_network_network_peering_connected.yaml +++ b/compliance/controls/azure/azure_network_network_peering_connected.yaml @@ -1,42 +1,42 @@ +Description: This control ensures whether virtual network network peering is in connected state. This control is non-compliant if network peering is not in connected state. ID: azure_network_network_peering_connected -Title: "Virtual network network peering should be in connected state" -Description: "This control ensures whether virtual network network peering is in connetecd state. This contol is non-compliant if network peering is not in connected state." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with disconnected_network_peering as ( - select - distinct id as vn_id - from - azure_virtual_network as n, - jsonb_array_elements(network_peerings) as p - where - p -> 'properties' ->> 'peeringState' = 'Disconnected' - ) - select - n.id as resource, - n.og_account_id as og_account_id, - n.og_resource_id as og_resource_id, - case - when jsonb_array_length(network_peerings) = 0 then 'ok' - when p.vn_id is not null then 'alarm' - else 'ok' - end as status, - case - when jsonb_array_length(network_peerings) = 0 then n.title || ' has no network peering.' - when p.vn_id is not null then n.title || ' has network peering in disconnected state.' - else n.title || ' has network peering in connected state.' - end as reason - from - azure_virtual_network as n - left join disconnected_network_peering as p on p.vn_id = n.id - join azure_subscription sub on sub.subscription_id = n.subscription_id; - PrimaryTable: azure_virtual_network ListOfTables: - azure_virtual_network - azure_subscription Parameters: [] + PrimaryTable: azure_virtual_network + QueryToExecute: | + WITH disconnected_network_peering AS ( + SELECT + DISTINCT id AS vn_id + FROM + azure_virtual_network AS n, + jsonb_array_elements(network_peerings) AS p + WHERE + p -> 'properties' ->> 'peeringState' = 'Disconnected' + ) + SELECT + n.id AS resource, + n.og_account_id AS og_account_id, + n.og_resource_id AS og_resource_id, + CASE + WHEN jsonb_array_length(network_peerings) = 0 THEN 'ok' + WHEN p.vn_id IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN jsonb_array_length(network_peerings) = 0 THEN n.title || ' has no network peering.' + WHEN p.vn_id IS NOT NULL THEN n.title || ' has network peering in disconnected state.' + ELSE n.title || ' has network peering in connected state.' + END AS reason + FROM + azure_virtual_network AS n + LEFT JOIN disconnected_network_peering AS p ON p.vn_id = n.id + JOIN azure_subscription sub ON sub.subscription_id = n.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Virtual network network peering should be in connected state \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_public_ip_no_basic_sku.yaml b/compliance/controls/azure/azure_network_public_ip_no_basic_sku.yaml old mode 100755 new mode 100644 index 26c6dd7db..84d8fdf51 --- a/compliance/controls/azure/azure_network_public_ip_no_basic_sku.yaml +++ b/compliance/controls/azure/azure_network_public_ip_no_basic_sku.yaml @@ -1,19 +1,38 @@ +Description: The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft will usually refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads. ID: azure_network_public_ip_no_basic_sku -Title: "Network public IPs should use standard SKUs as a minimum" -Description: "The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft will usually refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n i.id as resource,\n i.og_account_id as og_account_id,\n i.og_resource_id as og_resource_id,\n case\n when i.sku_name = 'Basic' then 'alarm'\n else 'ok'\n end as status,\n case\n when i.sku_name = 'Basic' then i.title || ' using basic SKU.'\n else i.title || ' using ' || sku_name || ' SKU.'\n end as reason\n \n , i.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_public_ip as i,\n azure_subscription as sub\nwhere\n sub.subscription_id = i.subscription_id;\n" - PrimaryTable: azure_public_ip ListOfTables: - azure_public_ip - azure_subscription Parameters: [] + PrimaryTable: azure_public_ip + QueryToExecute: | + SELECT + i.id AS resource, + i.og_account_id AS og_account_id, + i.og_resource_id AS og_resource_id, + CASE + WHEN i.sku_name = 'Basic' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.sku_name = 'Basic' THEN i.title || ' using basic SKU.' + ELSE i.title || ' using ' || sku_name || ' SKU.' + END AS reason, + i.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_public_ip AS i, + azure_subscription AS sub + WHERE + sub.subscription_id = i.subscription_id; Severity: low Tags: cis: - "true" service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Network public IPs should use standard SKUs as a minimum \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_diagnostic_setting_deployed.yaml b/compliance/controls/azure/azure_network_security_group_diagnostic_setting_deployed.yaml old mode 100755 new mode 100644 index 897f4a85c..87c2fdcd4 --- a/compliance/controls/azure/azure_network_security_group_diagnostic_setting_deployed.yaml +++ b/compliance/controls/azure/azure_network_security_group_diagnostic_setting_deployed.yaml @@ -1,19 +1,51 @@ +Description: This policy automatically deploys diagnostic settings to network security groups. A storage account with name '{storagePrefixParameter}{NSGLocation}' will be automatically created. ID: azure_network_security_group_diagnostic_setting_deployed -Title: "Deploy Diagnostic Settings for Network Security Groups" -Description: "This policy automatically deploys diagnostic settings to network security groups. A storage account with name '{storagePrefixParameter}{NSGLocation}' will be automatically created." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n distinct name as nsg_name\n from\n azure_network_security_group,\n jsonb_array_elements(diagnostic_settings) setting\n where\n diagnostic_settings is not null\n and setting ->> 'name' = 'setbypolicy'\n)\nselect\n a.resource_guid as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when a.diagnostic_settings is null then 'alarm'\n when l.nsg_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when a.diagnostic_settings is null then a.name || ' logging not enabled.'\n when l.nsg_name is null then a.name || ' logging not enabled.'\n else a.name || ' logging enabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_network_security_group as a\n left join logging_details as l on a.name = l.nsg_name,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH logging_details AS ( + SELECT + DISTINCT name AS nsg_name + FROM + azure_network_security_group, + jsonb_array_elements(diagnostic_settings) setting + WHERE + diagnostic_settings IS NOT NULL + AND setting ->> 'name' = 'setbypolicy' + ) + SELECT + a.resource_guid AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN a.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.nsg_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.diagnostic_settings IS NULL THEN a.name || ' logging not enabled.' + WHEN l.nsg_name IS NULL THEN a.name || ' logging not enabled.' + ELSE a.name || ' logging enabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_network_security_group AS a + LEFT JOIN logging_details AS l ON a.name = l.nsg_name, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Deploy Diagnostic Settings for Network Security Groups \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_https_access_restricted.yaml b/compliance/controls/azure/azure_network_security_group_https_access_restricted.yaml old mode 100755 new mode 100644 index 016bf6045..91cfc2060 --- a/compliance/controls/azure/azure_network_security_group_https_access_restricted.yaml +++ b/compliance/controls/azure/azure_network_security_group_https_access_restricted.yaml @@ -1,74 +1,65 @@ +Description: Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured. ID: azure_network_security_group_https_access_restricted -Title: "Ensure that HTTP(S) access from the Internet is evaluated and restricted" -Description: "Network security groups should be periodically evaluated for port misconfigurations. Where certain ports and protocols may be exposed to the Internet, they should be evaluated for necessity and restricted wherever they are not explicitly required and narrowly configured." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - with network_sg as ( - select distinct - name sg_name - from - azure_network_security_group nsg, - jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(case jsonb_typeof(COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb) - when 'array' then COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb - else ('[' || (COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb :: text) || ']') :: jsonb end) dport, - jsonb_array_elements_text(case jsonb_typeof(COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb) - when 'array' then COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb - else ('[' || (COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb :: text) || ']') :: jsonb end) sip - where - sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and sg -> 'properties' ->> 'protocol' ilike 'TCP' - and sip in - ( - '*', - '0.0.0.0', - '0.0.0.0/0', - 'Internet', - 'any', - '/0', - '/0' - ) - and - ( - dport in - ( - '80', - '*' - ) - or - ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 80 - and split_part(dport, '-', 2) :: integer >= 80 - ) - ) - ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts HTTPS access from internet.' - else sg.title || ' allows HTTPS access from internet.' - end as reason - - , sg.resource_group as resource_group - , sub.display_name as subscription - from - azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT DISTINCT + name sg_name + FROM + azure_network_security_group nsg, + jsonb_array_elements(security_rules) sg, + jsonb_array_elements_text( + CASE jsonb_typeof(COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange') :: jsonb) + WHEN 'array' THEN COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange') :: jsonb + ELSE ('[' || COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange') :: jsonb :: text || ']') :: jsonb + END + ) dport, + jsonb_array_elements_text( + CASE jsonb_typeof(COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) + WHEN 'array' THEN COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb + ELSE ('[' || COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb :: text || ']') :: jsonb + END + ) sip + WHERE + sg -> 'properties' ->> 'access' = 'Allow' + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' ILIKE 'TCP' + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('80', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1) :: integer <= 80 + AND split_part(dport, '-', 2) :: integer >= 80 + ) + ) + ) + SELECT + sg.id resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts HTTPS access from internet.' + ELSE sg.title || ' allows HTTPS access from internet.' + END AS reason, + sg.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_network_security_group sg + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: high Tags: category: @@ -89,5 +80,4 @@ Tags: - azure service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Ensure that HTTP(S) access from the Internet is evaluated and restricted \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_not_configured_gateway_subnets.yaml b/compliance/controls/azure/azure_network_security_group_not_configured_gateway_subnets.yaml old mode 100755 new mode 100644 index b0d790c14..48d44d036 --- a/compliance/controls/azure/azure_network_security_group_not_configured_gateway_subnets.yaml +++ b/compliance/controls/azure/azure_network_security_group_not_configured_gateway_subnets.yaml @@ -1,38 +1,39 @@ +Description: Protect your subnet from potential threats by restricting access to it with a Network Security Group (NSG). NSGs contain a list of Access Control List (ACL) rules that allow or deny network traffic to your subnet. ID: azure_network_security_group_not_configured_gateway_subnets -Title: "Gateway subnets should not be configured with a network security group" -Description: "Protect your subnet from potential threats by restricting access to it with a Network Security Group (NSG). NSGs contain a list of Access Control List (ACL) rules that allow or deny network traffic to your subnet." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - subnet.id resource, - subnet.og_account_id as og_account_id, - subnet.og_resource_id as og_resource_id, - case - when subnet.name = 'GatewaySubnet' and network_security_group_id is not null then 'alarm' - when subnet.name = 'GatewaySubnet' and network_security_group_id is null then 'ok' - else 'skip' - end as status, - case - when subnet.name = 'GatewaySubnet' and network_security_group_id is not null then 'Gateway subnet configured with network security group.' - when subnet.name = 'GatewaySubnet' and network_security_group_id is null then 'Gateway subnet not configured with network security group.' - else subnet.name || ' not of gateway subnet type.' - end as reason - , subnet.resource_group as resource_group - , sub.display_name as subscription - from - azure_subnet as subnet - join azure_subscription as sub on sub.subscription_id = subnet.subscription_id; - PrimaryTable: azure_subnet ListOfTables: - azure_subnet - azure_subscription Parameters: [] + PrimaryTable: azure_subnet + QueryToExecute: | + SELECT + subnet.id AS resource, + subnet.og_account_id AS og_account_id, + subnet.og_resource_id AS og_resource_id, + CASE + WHEN subnet.name = 'GatewaySubnet' AND network_security_group_id IS NOT NULL THEN 'alarm' + WHEN subnet.name = 'GatewaySubnet' AND network_security_group_id IS NULL THEN 'ok' + ELSE 'skip' + END AS status, + CASE + WHEN subnet.name = 'GatewaySubnet' AND network_security_group_id IS NOT NULL THEN 'Gateway subnet configured with network security group.' + WHEN subnet.name = 'GatewaySubnet' AND network_security_group_id IS NULL THEN 'Gateway subnet not configured with network security group.' + ELSE subnet.name || ' not of gateway subnet type.' + END AS reason, + subnet.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_subnet AS subnet + JOIN + azure_subscription AS sub ON sub.subscription_id = subnet.subscription_id; Severity: high Tags: hipaa_hitrust_v92: - "true" service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Gateway subnets should not be configured with a network security group \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_outbound_access_restricted.yaml b/compliance/controls/azure/azure_network_security_group_outbound_access_restricted.yaml old mode 100755 new mode 100644 index cd6b4e22f..eae417189 --- a/compliance/controls/azure/azure_network_security_group_outbound_access_restricted.yaml +++ b/compliance/controls/azure/azure_network_security_group_outbound_access_restricted.yaml @@ -1,53 +1,57 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted outbound access. ID: azure_network_security_group_outbound_access_restricted -Title: "Network security groups should restrict outbound access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted outbound access." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with unrestricted_outbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_outbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 + THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 + THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Outbound' - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and dport = '*' + AND sg -> 'properties' ->> 'direction' = 'Outbound' + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND dport = '*' ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts outbound access from internet.' - else sg.title || ' allows outbound access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts outbound access from internet.' + ELSE sg.title || ' allows outbound access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_outbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_outbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict outbound access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_rdp_access_restricted.yaml b/compliance/controls/azure/azure_network_security_group_rdp_access_restricted.yaml old mode 100755 new mode 100644 index f5797e502..6e69b0fc6 --- a/compliance/controls/azure/azure_network_security_group_rdp_access_restricted.yaml +++ b/compliance/controls/azure/azure_network_security_group_rdp_access_restricted.yaml @@ -1,60 +1,62 @@ +Description: Windows machines should have the specified Group Policy settings in the category 'User Rights Assignment' for allowing log on locally, RDP, access from the network, and many other user activities. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope. ID: azure_network_security_group_rdp_access_restricted -Title: "Windows machines should meet requirements for 'User Rights Assignment'" -Description: "Windows machines should have the specified Group Policy settings in the category 'User Rights Assignment' for allowing log on locally, RDP, access from the network, and many other user activities. This policy requires that the Guest Configuration prerequisites have been deployed to the policy assignment scope." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group QueryToExecute: | - with network_sg as ( - select - distinct name sg_name - from + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(case jsonb_typeof(COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb) - when 'array' then COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb - else ('[' || (COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb :: text) || ']') :: jsonb end) dport, - jsonb_array_elements_text(case jsonb_typeof(COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb) - when 'array' then COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb - else ('[' || (COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb :: text) || ']') :: jsonb end) sip - where + jsonb_array_elements_text(CASE jsonb_typeof(COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange')::jsonb) + WHEN 'array' THEN COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange')::jsonb + ELSE ('[' || COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange')::jsonb::text || ']')::jsonb + END) dport, + jsonb_array_elements_text(CASE jsonb_typeof(COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix')::jsonb) + WHEN 'array' THEN COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix')::jsonb + ELSE ('[' || COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix')::jsonb::text || ']')::jsonb + END) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('3389', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 3389 - and split_part(dport, '-', 2) :: integer >= 3389 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('3389', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::integer <= 3389 + AND split_part(dport, '-', 2)::integer >= 3389 ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts RDP access from internet.' - else sg.title || ' allows RDP access from internet.' - end as reason - - , sg.resource_group as resource_group - , sub.display_name as subscription - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts RDP access from internet.' + ELSE sg.title || ' allows RDP access from internet.' + END AS reason, + sg.resource_group AS resource_group, + sub.display_name AS subscription + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: high Tags: category: @@ -75,5 +77,4 @@ Tags: - azure service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Windows machines should meet requirements for 'User Rights Assignment' \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_remote_access_restricted.yaml b/compliance/controls/azure/azure_network_security_group_remote_access_restricted.yaml old mode 100755 new mode 100644 index d6fa5142e..b75b08fc0 --- a/compliance/controls/azure/azure_network_security_group_remote_access_restricted.yaml +++ b/compliance/controls/azure/azure_network_security_group_remote_access_restricted.yaml @@ -1,14 +1,66 @@ +Description: Open remote management ports are exposing your VM to a high level of risk from Internet-based attacks. + These attacks attempt to brute force credentials to gain admin access to the machine. ID: azure_network_security_group_remote_access_restricted -Title: "Management ports should be closed on your virtual machines" -Description: "Open remote management ports are exposing your VM to a high level of risk from Internet-based attacks. These attacks attempt to brute force credentials to gain admin access to the machine." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with network_sg as (\n select\n distinct name sg_name\n from\n azure_network_security_group nsg,\n jsonb_array_elements(security_rules) sg,\n jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport,\n jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip\n where\n sg -> 'properties' ->> 'access' = 'Allow'\n and sg -> 'properties' ->> 'direction' = 'Inbound'\n and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*')\n and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0')\n and (\n dport in ('22', '3389', '*')\n or (\n dport like '%-%'\n and (\n (\n split_part(dport, '-', 1) :: integer <= 3389\n and split_part(dport, '-', 2) :: integer >= 3389\n )\n or (\n split_part(dport, '-', 1) :: integer <= 22\n and split_part(dport, '-', 2) :: integer >= 22\n )\n )\n )\n )\n)\nselect\n sg.id resource,\n sg.og_account_id as og_account_id,\n sg.og_resource_id as og_resource_id,\n case\n when nsg.sg_name is null then 'ok'\n else 'alarm'\n end as status,\n case\n when nsg.sg_name is null then sg.title || ' restricts remote access from internet.'\n else sg.title || ' allows remote access from internet.'\n end as reason\n \n , sg.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_network_security_group as sg\n left join network_sg as nsg on nsg.sg_name = sg.name\n join azure_subscription as sub on sub.subscription_id = sg.subscription_id;\n" - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM + azure_network_security_group nsg, + jsonb_array_elements(security_rules) sg, + jsonb_array_elements_text(sg -> 'properties' -> 'destinationPortRanges' || + (sg -> 'properties' -> 'destinationPortRange') :: jsonb) dport, + jsonb_array_elements_text(sg -> 'properties' -> 'sourceAddressPrefixes' || + (sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) sip + WHERE + sg -> 'properties' ->> 'access' = 'Allow' + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('22', '3389', '*') + OR ( + dport LIKE '%-%' + AND ( + ( + split_part(dport, '-', 1) :: INTEGER <= 3389 + AND split_part(dport, '-', 2) :: INTEGER >= 3389 + ) + OR ( + split_part(dport, '-', 1) :: INTEGER <= 22 + AND split_part(dport, '-', 2) :: INTEGER >= 22 + ) + ) + ) + ) + ) + SELECT + sg.id resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts remote access from internet.' + ELSE sg.title || ' allows remote access from internet.' + END AS reason, + sg.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_network_security_group AS sg + LEFT JOIN network_sg AS nsg ON nsg.sg_name = sg.name + JOIN azure_subscription AS sub ON sub.subscription_id = sg.subscription_id; Severity: high Tags: hipaa_hitrust_v92: @@ -17,5 +69,4 @@ Tags: - "true" service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Management ports should be closed on your virtual machines \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_icmp_port.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_icmp_port.yaml old mode 100755 new mode 100644 index af79d9f02..c5c3b8b40 --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_icmp_port.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_icmp_port.yaml @@ -1,65 +1,65 @@ +Description: Network security group provides stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to ICMP port. ID: azure_network_security_group_restrict_inbound_icmp_port -Title: "Network security groups should restrict inbound ICMP port access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to ICMP port." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) AS sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'ICMP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'ICMP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( dport = '*' - or ( - dport like '%-%' - and ( + OR ( + dport LIKE '%-%' + AND ( split_part(dport, '-', 1) :: integer = 0 - and split_part(dport, '-', 2) :: integer = 65535 + AND split_part(dport, '-', 2) :: integer = 65535 ) ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts ICMP access from internet.' - else sg.title || ' allows ICMP access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts ICMP access from internet.' + ELSE sg.title || ' allows ICMP access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound ICMP port access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_135.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_135.yaml old mode 100755 new mode 100644 index 06ac1e919..b9ca25184 --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_135.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_135.yaml @@ -1,63 +1,65 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 135. ID: azure_network_security_group_restrict_inbound_tcp_port_135 -Title: "Network security groups should restrict inbound TCP port 135 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 135." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) AS sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('135', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 135 - and split_part(dport, '-', 2) :: integer = 135 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('135', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::INTEGER = 135 + AND split_part(dport, '-', 2)::INTEGER = 135 ) ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 135 access from internet.' - else sg.title || ' allows TCP port 135 access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 135 access from internet.' + ELSE sg.title || ' allows TCP port 135 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 135 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_1433.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_1433.yaml old mode 100755 new mode 100644 index 7759c4362..477bdb0ef --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_1433.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_1433.yaml @@ -1,65 +1,65 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 1433. ID: azure_network_security_group_restrict_inbound_tcp_port_1433 -Title: "Network security groups should restrict inbound TCP port 1433 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 1433." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('1433', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 1433 - and split_part(dport, '-', 2) :: integer = 214335 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('1433', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::integer = 1433 + AND split_part(dport, '-', 2)::integer = 214335 ) ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 1433 access from internet.' - else sg.title || ' allows TCP port 1433 access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 1433 access from internet.' + ELSE sg.title || ' allows TCP port 1433 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 1433 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_20.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_20.yaml old mode 100755 new mode 100644 index 42fbacfa6..c4da14fbe --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_20.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_20.yaml @@ -1,63 +1,63 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 20. ID: azure_network_security_group_restrict_inbound_tcp_port_20 -Title: "Network security groups should restrict inbound TCP port 20 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 20." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from - azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name AS sg_name + FROM + azure_network_security_group AS nsg, + jsonb_array_elements(security_rules || default_security_rules) AS sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('20', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 20 - and split_part(dport, '-', 2) :: integer >= 20 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('20', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1) :: INTEGER <= 20 + AND split_part(dport, '-', 2) :: INTEGER >= 20 ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 20 access from internet.' - else sg.title || ' allows TCP port 20 access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 20 access from internet.' + ELSE sg.title || ' allows TCP port 20 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 20 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_21.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_21.yaml old mode 100755 new mode 100644 index 6863e81a1..ac44f878f --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_21.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_21.yaml @@ -1,63 +1,63 @@ +Description: Network security group provides stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 21. ID: azure_network_security_group_restrict_inbound_tcp_port_21 -Title: "Network security groups should restrict inbound TCP port 21 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 20." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('21', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 21 - and split_part(dport, '-', 2) :: integer >= 21 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('21', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::integer <= 21 + AND split_part(dport, '-', 2)::integer >= 21 ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 21 access from internet.' - else sg.title || ' allows TCP port 21 access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 21 access from internet.' + ELSE sg.title || ' allows TCP port 21 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 21 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_23.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_23.yaml old mode 100755 new mode 100644 index acc4a8336..bebd47891 --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_23.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_23.yaml @@ -1,65 +1,63 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 23. ID: azure_network_security_group_restrict_inbound_tcp_port_23 -Title: "Network security groups should restrict inbound TCP port 23 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 23." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('23', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 23 - and split_part(dport, '-', 2) :: integer = 23 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('23', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::INTEGER = 23 + AND split_part(dport, '-', 2)::INTEGER = 23 ) ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 23 access from internet.' - else sg.title || ' allows TCP port 23 access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 23 access from internet.' + ELSE sg.title || ' allows TCP port 23 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 23 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_25.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_25.yaml old mode 100755 new mode 100644 index a8009be6b..0ae82c196 --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_25.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_25.yaml @@ -1,65 +1,65 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 25. ID: azure_network_security_group_restrict_inbound_tcp_port_25 -Title: "Network security groups should restrict inbound TCP port 25 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 25." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('25', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 25 - and split_part(dport, '-', 2) :: integer = 25 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('25', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::INTEGER = 25 + AND split_part(dport, '-', 2)::INTEGER = 25 ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 25 access from internet.' - else sg.title || ' allows TCP port 25 access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 25 access from internet.' + ELSE sg.title || ' allows TCP port 25 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 25 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_3306.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_3306.yaml old mode 100755 new mode 100644 index cdf99bf10..2fdff9bdb --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_3306.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_3306.yaml @@ -1,65 +1,67 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 3306. ID: azure_network_security_group_restrict_inbound_tcp_port_3306 -Title: "Network security groups should restrict inbound TCP port 3306 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 3306." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 + THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 + THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('3306', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 3306 - and split_part(dport, '-', 2) :: integer = 3306 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('3306', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::integer = 3306 + AND split_part(dport, '-', 2)::integer = 3306 ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 3306 access from internet.' - else sg.title || ' allows TCP port 3306 access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 3306 access from internet.' + ELSE sg.title || ' allows TCP port 3306 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 3306 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_4333.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_4333.yaml old mode 100755 new mode 100644 index 77e4de25b..4e83456cc --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_4333.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_4333.yaml @@ -1,59 +1,57 @@ ID: azure_network_security_group_restrict_inbound_tcp_port_4333 Title: "Network security groups should restrict inbound TCP port 4333 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 4333." +Description: "Network security group provides stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 4333." Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, - jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, - jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + JSONB_ARRAY_ELEMENTS(security_rules || default_security_rules) sg, + JSONB_ARRAY_ELEMENTS_TEXT( + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END) AS dport, + JSONB_ARRAY_ELEMENTS_TEXT( + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('4333', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 4333 - and split_part(dport, '-', 2) :: integer = 4333 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('4333', '*') + OR ( + dport LIKE '%-%' + AND ( + SPLIT_PART(dport, '-', 1)::integer = 4333 + AND SPLIT_PART(dport, '-', 2)::integer = 4333 ) ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 4333 access from internet.' - else sg.title || ' allows TCP port 4333 access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 4333 access from internet.' + ELSE sg.title || ' allows TCP port 4333 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group @@ -62,4 +60,4 @@ Query: Severity: low Tags: {} IntegrationType: - - azure_subscription + - azure_subscription \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_445.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_445.yaml old mode 100755 new mode 100644 index 7d89c2aa0..72f9e559e --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_445.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_445.yaml @@ -1,63 +1,67 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 445. ID: azure_network_security_group_restrict_inbound_tcp_port_445 -Title: "Network security groups should restrict inbound TCP port 445 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 445." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 + THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 + THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('445', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 445 - and split_part(dport, '-', 2) :: integer = 445 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('445', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1) :: INTEGER = 445 + AND split_part(dport, '-', 2) :: INTEGER = 445 ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 445 access from internet.' - else sg.title || ' allows TCP port 445 access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 445 access from internet.' + ELSE sg.title || ' allows TCP port 445 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 445 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_53.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_53.yaml old mode 100755 new mode 100644 index 5c38b601d..9b0b92f72 --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_53.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_53.yaml @@ -1,65 +1,67 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 53. ID: azure_network_security_group_restrict_inbound_tcp_port_53 -Title: "Network security groups should restrict inbound TCP port 53 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 53." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 + THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 + THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('53', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 53 - and split_part(dport, '-', 2) :: integer = 53 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('53', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::integer = 53 + AND split_part(dport, '-', 2)::integer = 53 ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 53 access from internet.' - else sg.title || ' allows TCP port 53 access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 53 access from internet.' + ELSE sg.title || ' allows TCP port 53 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 53 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5432.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5432.yaml old mode 100755 new mode 100644 index bacf52b91..edb75a871 --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5432.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5432.yaml @@ -1,63 +1,72 @@ +Description: Network security group provides stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 5432. ID: azure_network_security_group_restrict_inbound_tcp_port_5432 -Title: "Network security groups should restrict inbound TCP port 5432 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 5432." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT DISTINCT + name AS sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) AS sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 + THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 + THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('5432', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 5432 - and split_part(dport, '-', 2) :: integer = 5432 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND ( + sg -> 'properties' ->> 'protocol' ILIKE 'TCP' + OR sg -> 'properties' ->> 'protocol' = '*' + ) + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('5432', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::integer = 5432 + AND split_part(dport, '-', 2)::integer = 5432 ) ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 5432 access from internet.' - else sg.title || ' allows TCP port 5432 access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 5432 access from internet.' + ELSE sg.title || ' allows TCP port 5432 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg + ON nsg.sg_name = sg.name + JOIN azure_subscription sub + ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 5432 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5500.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5500.yaml old mode 100755 new mode 100644 index 7e05df769..9520e3390 --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5500.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5500.yaml @@ -1,65 +1,69 @@ +Description: Network security group provides stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 5500. ID: azure_network_security_group_restrict_inbound_tcp_port_5500 -Title: "Network security groups should restrict inbound TCP port 5500 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 5500." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from - azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT DISTINCT + name AS sg_name + FROM + azure_network_security_group AS nsg, + jsonb_array_elements(security_rules || default_security_rules) AS sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 + THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 + THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('5500', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 5500 - and split_part(dport, '-', 2) :: integer = 5500 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('5500', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::INTEGER = 5500 + AND split_part(dport, '-', 2)::INTEGER = 5500 ) ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 5500 access from internet.' - else sg.title || ' allows TCP port 5500 access from internet.' - end as reason - from - azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts TCP port 5500 access from internet.' + ELSE sg.title || ' allows TCP port 5500 access from internet.' + END AS reason + FROM + azure_network_security_group AS sg + LEFT JOIN unrestricted_inbound AS nsg ON nsg.sg_name = sg.name + JOIN azure_subscription AS sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 5500 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5900.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5900.yaml old mode 100755 new mode 100644 index 2ccd13774..a2ae2a96f --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5900.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_tcp_port_5900.yaml @@ -1,63 +1,65 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 5900. ID: azure_network_security_group_restrict_inbound_tcp_port_5900 -Title: "Network security groups should restrict inbound TCP port 5900 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to TCP port 5900." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('5900', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 5900 - and split_part(dport, '-', 2) :: integer = 5900 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('5900', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1) :: INTEGER = 5900 + AND split_part(dport, '-', 2) :: INTEGER = 5900 ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts TCP port 5900 access from internet.' - else sg.title || ' allows TCP port 5900 access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts TCP port 5900 access from internet.' + ELSE sg.title || ' allows TCP port 5900 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound TCP port 5900 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_137.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_137.yaml old mode 100755 new mode 100644 index 77fe0fcfc..1c3937f1c --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_137.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_137.yaml @@ -1,65 +1,65 @@ +Description: Network security group provides stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to UDP port 137. ID: azure_network_security_group_restrict_inbound_udp_port_137 -Title: "Network security groups should restrict inbound UDP port 137 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to UDP port 137." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name AS sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules || default_security_rules ) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'UDP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('137', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 137 - and split_part(dport, '-', 2) :: integer = 137 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'UDP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('137', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::INTEGER = 137 + AND split_part(dport, '-', 2)::INTEGER = 137 ) ) ) ) - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts UDP port 137 access from internet.' - else sg.title || ' allows UDP port 137 access from internet.' - end as reason - from + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts UDP port 137 access from internet.' + ELSE sg.title || ' allows UDP port 137 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound UDP port 137 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_138.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_138.yaml old mode 100755 new mode 100644 index 5b9a00ebb..898676125 --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_138.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_138.yaml @@ -1,65 +1,65 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to UDP port 137. ID: azure_network_security_group_restrict_inbound_udp_port_138 -Title: "Network security groups should restrict inbound UDP port 137 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to UDP port 137." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'UDP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('138', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 138 - and split_part(dport, '-', 2) :: integer = 138 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'UDP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('138', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::INTEGER = 138 + AND split_part(dport, '-', 2)::INTEGER = 138 ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts UDP port 138 access from internet.' - else sg.title || ' allows UDP port 138 access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts UDP port 138 access from internet.' + ELSE sg.title || ' allows UDP port 138 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound UDP port 137 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_1434.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_1434.yaml old mode 100755 new mode 100644 index d0185ff25..b9bcbb92f --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_1434.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_1434.yaml @@ -1,63 +1,65 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to UDP port 1434. ID: azure_network_security_group_restrict_inbound_udp_port_1434 -Title: "Network security groups should restrict inbound UDP port 1434 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to UDP port 1434." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'UDP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('1434', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 1434 - and split_part(dport, '-', 2) :: integer = 1434 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'UDP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('1434', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::integer = 1434 + AND split_part(dport, '-', 2)::integer = 1434 ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts UDP port 1434 access from internet.' - else sg.title || ' allows UDP port 1434 access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts UDP port 1434 access from internet.' + ELSE sg.title || ' allows UDP port 1434 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound UDP port 1434 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_445.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_445.yaml old mode 100755 new mode 100644 index 545334cb6..f98672bc7 --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_445.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_445.yaml @@ -1,63 +1,61 @@ +Description: Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to UDP port 445. ID: azure_network_security_group_restrict_inbound_udp_port_445 -Title: "Network security groups should restrict inbound UDP port 445 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to UDP port 445." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'UDP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('445', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1)::integer <= 445 - and split_part(dport, '-', 2)::integer >= 445 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'UDP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('445', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1)::integer <= 445 + AND split_part(dport, '-', 2)::integer >= 445 ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts UDP port 445 access from internet.' - else sg.title || ' allows UDP port 445 access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts UDP port 445 access from internet.' + ELSE sg.title || ' allows UDP port 445 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound UDP port 445 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_53.yaml b/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_53.yaml old mode 100755 new mode 100644 index 3ee667e9d..fe65c95ab --- a/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_53.yaml +++ b/compliance/controls/azure/azure_network_security_group_restrict_inbound_udp_port_53.yaml @@ -1,65 +1,65 @@ +Description: Network security group provides stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to UDP port 53. ID: azure_network_security_group_restrict_inbound_udp_port_53 -Title: "Network security groups should restrict inbound UDP port 53 access from internet" -Description: "Network security group provide stateful filtering of inbound/outbound network traffic to Azure resources. It is recommended that no network security group allows unrestricted inbound access to UDP port 53." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - ```sql - with unrestricted_inbound as ( - select - distinct name sg_name - from + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + WITH unrestricted_inbound AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, - jsonb_array_elements(security_rules || default_security_rules ) sg, + jsonb_array_elements(security_rules || default_security_rules) sg, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 then (sg -> 'properties' -> 'destinationPortRanges') - else jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') - end ) as dport, + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'destinationPortRanges') > 0 THEN (sg -> 'properties' -> 'destinationPortRanges') + ELSE jsonb_build_array(sg -> 'properties' -> 'destinationPortRange') + END + ) AS dport, jsonb_array_elements_text( - case - when jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 then (sg -> 'properties' -> 'sourceAddressPrefixes') - else jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') - end ) as sip - where + CASE + WHEN jsonb_array_length(sg -> 'properties' -> 'sourceAddressPrefixes') > 0 THEN (sg -> 'properties' -> 'sourceAddressPrefixes') + ELSE jsonb_build_array(sg -> 'properties' -> 'sourceAddressPrefix') + END + ) AS sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'UDP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('53', '*') - or ( - dport like '%-%' - and ( - split_part(dport, '-', 1) :: integer = 53 - and split_part(dport, '-', 2) :: integer = 53 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'UDP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('53', '*') + OR ( + dport LIKE '%-%' + AND ( + split_part(dport, '-', 1)::integer = 53 + AND split_part(dport, '-', 2)::integer = 53 ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null then sg.title || ' restricts UDP port 53 access from internet.' - else sg.title || ' allows UDP port 53 access from internet.' - end as reason - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL THEN sg.title || ' restricts UDP port 53 access from internet.' + ELSE sg.title || ' allows UDP port 53 access from internet.' + END AS reason + FROM azure_network_security_group sg - left join unrestricted_inbound nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - ``` - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN unrestricted_inbound nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network security groups should restrict inbound UDP port 53 access from internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_ssh_access_restricted.yaml b/compliance/controls/azure/azure_network_security_group_ssh_access_restricted.yaml old mode 100755 new mode 100644 index 4f0ff91ab..3db2e0204 --- a/compliance/controls/azure/azure_network_security_group_ssh_access_restricted.yaml +++ b/compliance/controls/azure/azure_network_security_group_ssh_access_restricted.yaml @@ -1,60 +1,68 @@ +Description: Disable SSH access on network security groups from the Internet. ID: azure_network_security_group_ssh_access_restricted -Title: "Ensure that SSH access is restricted from the internet" -Description: "Disable SSH access on network security groups from the Internet." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group QueryToExecute: | - with network_sg as ( - select - distinct name sg_name - from + WITH network_sg AS ( + SELECT DISTINCT + name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(case jsonb_typeof(COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb) - when 'array' then COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb - else ('[' || (COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb :: text) || ']') :: jsonb end) dport, - jsonb_array_elements_text(case jsonb_typeof(COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb) - when 'array' then COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb - else ('[' || (COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb :: text) || ']') :: jsonb end) sip - where + jsonb_array_elements_text( + CASE jsonb_typeof( + COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange') :: jsonb) + WHEN 'array' THEN COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange') :: jsonb + ELSE ('[' || (COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange') :: jsonb :: text) || ']') :: jsonb + END + ) dport, + jsonb_array_elements_text( + CASE jsonb_typeof( + COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb) + WHEN 'array' THEN COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb + ELSE ('[' || (COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix') :: jsonb :: text) || ']') :: jsonb + END + ) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and (sg -> 'properties' ->> 'protocol' ilike 'TCP' or sg -> 'properties' ->> 'protocol' = '*') - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( - dport in ('22', '*') - or ( - dport like '%-%' - and split_part(dport, '-', 1) :: integer <= 22 - and split_part(dport, '-', 2) :: integer >= 22 + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND (sg -> 'properties' ->> 'protocol' ILIKE 'TCP' OR sg -> 'properties' ->> 'protocol' = '*') + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( + dport IN ('22', '*') + OR ( + dport LIKE '%-%' + AND split_part(dport, '-', 1) :: integer <= 22 + AND split_part(dport, '-', 2) :: integer >= 22 ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts SSH access from internet.' - else sg.title || ' allows SSH access from internet.' - end as reason - - , sg.resource_group as resource_group - , sub.display_name as subscription - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts SSH access from internet.' + ELSE sg.title || ' allows SSH access from internet.' + END AS reason, + sg.resource_group AS resource_group, + sub.display_name AS subscription + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: high Tags: category: @@ -75,5 +83,4 @@ Tags: - azure service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Ensure that SSH access is restricted from the internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_subnet_associated.yaml b/compliance/controls/azure/azure_network_security_group_subnet_associated.yaml old mode 100755 new mode 100644 index b36596a5c..e57a87379 --- a/compliance/controls/azure/azure_network_security_group_subnet_associated.yaml +++ b/compliance/controls/azure/azure_network_security_group_subnet_associated.yaml @@ -1,14 +1,33 @@ +Description: This policy denies if a gateway subnet is configured with a network security group. Assigning a network security group to a gateway subnet will cause the gateway to stop functioning. ID: azure_network_security_group_subnet_associated -Title: "Subnets should be associated with a Network Security Group" -Description: "This policy denies if a gateway subnet is configured with a network security group. Assigning a network security group to a gateway subnet will cause the gateway to stop functioning." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sg.id resource,\n sg.og_account_id as og_account_id,\n sg.og_resource_id as og_resource_id,\n case\n when subnets is null then 'alarm'\n else 'ok'\n end as status,\n case\n when subnets is null then name || ' not associated with subnet.'\n else name || ' associated with ' || split_part(rtrim((subnet -> 'id') :: text, '\"'), '/subnets/',2) || '.'\n end as reason\n \n , sg.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_network_security_group as sg\n join azure_subscription as sub on sub.subscription_id = sg.subscription_id\n left join jsonb_array_elements(subnets) as subnet on true;\n" - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN subnets IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN subnets IS NULL THEN name || ' not associated with subnet.' + ELSE name || ' associated with ' || SPLIT_PART(RTRIM((subnet -> 'id')::TEXT, '\"'), '/subnets/', 2) || '.' + END AS reason, + sg.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_network_security_group AS sg + JOIN azure_subscription AS sub ON sub.subscription_id = sg.subscription_id + LEFT JOIN JSONB_ARRAY_ELEMENTS(subnets) AS subnet ON TRUE; Severity: high Tags: hipaa_hitrust_v92: @@ -17,5 +36,4 @@ Tags: - "true" service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Subnets should be associated with a Network Security Group \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_security_group_udp_service_restricted.yaml b/compliance/controls/azure/azure_network_security_group_udp_service_restricted.yaml old mode 100755 new mode 100644 index 7044620e7..134e6fe48 --- a/compliance/controls/azure/azure_network_security_group_udp_service_restricted.yaml +++ b/compliance/controls/azure/azure_network_security_group_udp_service_restricted.yaml @@ -1,65 +1,75 @@ +Description: Disable Internet exposed UDP ports on network security groups. ID: azure_network_security_group_udp_service_restricted -Title: "Ensure that UDP Services are restricted from the Internet" -Description: "Disable Internet exposed UDP ports on network security groups." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_network_security_group + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_security_group QueryToExecute: | - with network_sg as ( - select - distinct name sg_name - from + WITH network_sg AS ( + SELECT + DISTINCT name sg_name + FROM azure_network_security_group nsg, jsonb_array_elements(security_rules) sg, - jsonb_array_elements_text(case jsonb_typeof(COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb) - when 'array' then COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb - else ('[' || (COALESCE(sg -> 'properties' -> 'destinationPortRanges', (sg -> 'properties' -> 'destinationPortRange')) :: jsonb :: text) || ']') :: jsonb end) dport, - jsonb_array_elements_text(case jsonb_typeof(COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb) - when 'array' then COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb - else ('[' || (COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', (sg -> 'properties' -> 'sourceAddressPrefix')) :: jsonb :: text) || ']') :: jsonb end) sip - where + jsonb_array_elements_text( + CASE jsonb_typeof( + COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange')::jsonb + ) + WHEN 'array' THEN COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange')::jsonb + ELSE ('[' || (COALESCE(sg -> 'properties' -> 'destinationPortRanges', sg -> 'properties' -> 'destinationPortRange')::jsonb::text) || ']')::jsonb + END + ) dport, + jsonb_array_elements_text( + CASE jsonb_typeof( + COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix')::jsonb + ) + WHEN 'array' THEN COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix')::jsonb + ELSE ('[' || (COALESCE(sg -> 'properties' -> 'sourceAddressPrefixes', sg -> 'properties' -> 'sourceAddressPrefix')::jsonb::text) || ']')::jsonb + END + ) sip + WHERE sg -> 'properties' ->> 'access' = 'Allow' - and sg -> 'properties' ->> 'direction' = 'Inbound' - and sg -> 'properties' ->> 'protocol' = 'UDP' - and sip in ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') - and ( + AND sg -> 'properties' ->> 'direction' = 'Inbound' + AND sg -> 'properties' ->> 'protocol' = 'UDP' + AND sip IN ('*', '0.0.0.0', '0.0.0.0/0', 'Internet', 'any', '/0', '/0') + AND ( dport = '*' - or ( - dport like '%-%' - and ( - 53 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 123 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 161 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 389 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer - or 1900 between split_part(dport, '-', 1) :: integer and split_part(dport, '-', 2) :: integer + OR ( + dport LIKE '%-%' + AND ( + 53 BETWEEN split_part(dport, '-', 1)::integer AND split_part(dport, '-', 2)::integer + OR 123 BETWEEN split_part(dport, '-', 1)::integer AND split_part(dport, '-', 2)::integer + OR 161 BETWEEN split_part(dport, '-', 1)::integer AND split_part(dport, '-', 2)::integer + OR 389 BETWEEN split_part(dport, '-', 1)::integer AND split_part(dport, '-', 2)::integer + OR 1900 BETWEEN split_part(dport, '-', 1)::integer AND split_part(dport, '-', 2)::integer ) ) ) ) - select + SELECT sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when nsg.sg_name is null then 'ok' - else 'alarm' - end as status, - case - when nsg.sg_name is null - then sg.title || ' restricts UDP services from internet.' - else sg.title || ' allows UDP services from internet.' - end as reason - - , sg.resource_group as resource_group - , sub.display_name as subscription - from + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN nsg.sg_name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nsg.sg_name IS NULL + THEN sg.title || ' restricts UDP services from internet.' + ELSE sg.title || ' allows UDP services from internet.' + END AS reason, + sg.resource_group AS resource_group, + sub.display_name AS subscription + FROM azure_network_security_group sg - left join network_sg nsg on nsg.sg_name = sg.name - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group - ListOfTables: - - azure_network_security_group - - azure_subscription - Parameters: [] + LEFT JOIN network_sg nsg ON nsg.sg_name = sg.name + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: high Tags: category: @@ -80,5 +90,4 @@ Tags: - azure service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Ensure that UDP Services are restricted from the Internet \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_sg_flowlog_enabled.yaml b/compliance/controls/azure/azure_network_sg_flowlog_enabled.yaml old mode 100755 new mode 100644 index 781045ee3..c5963581c --- a/compliance/controls/azure/azure_network_sg_flowlog_enabled.yaml +++ b/compliance/controls/azure/azure_network_sg_flowlog_enabled.yaml @@ -1,30 +1,31 @@ +Description: Audit for network security groups to verify if flow logs are configured. Enabling flow logs allows to log information about IP traffic flowing through network security group. It can be used for optimizing network flows, monitoring throughput, verifying compliance, detecting intrusions and more. ID: azure_network_sg_flowlog_enabled -Title: "Flow logs should be configured for every network security group" -Description: "Audit for network security groups to verify if flow logs are configured. Enabling flow logs allows to log information about IP traffic flowing through network security group. It can be used for optimizing network flows, monitoring throughput, verifying compliance, detecting intrusions and more." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when sg.flow_logs is not null then 'ok' - else 'alarm' - end as status, - case - when sg.flow_logs is not null then sg.name || ' flowlog enabled.' - else sg.name || ' flowlog disabled.' - end as reason - from - azure_network_security_group as sg - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN sg.flow_logs IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sg.flow_logs IS NOT NULL THEN sg.name || ' flowlog enabled.' + ELSE sg.name || ' flowlog disabled.' + END AS reason + FROM + azure_network_security_group AS sg + JOIN + azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Flow logs should be configured for every network security group \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_sg_flowlog_retention_period_greater_than_90.yaml b/compliance/controls/azure/azure_network_sg_flowlog_retention_period_greater_than_90.yaml old mode 100755 new mode 100644 index 993c16fe8..6107850a4 --- a/compliance/controls/azure/azure_network_sg_flowlog_retention_period_greater_than_90.yaml +++ b/compliance/controls/azure/azure_network_sg_flowlog_retention_period_greater_than_90.yaml @@ -1,15 +1,37 @@ +Description: Network Security Group Flow Logs should be enabled and the retention period is set to greater than or equal to 90 days. ID: azure_network_sg_flowlog_retention_period_greater_than_90 -Title: "Ensure that Network Security Group Flow Log retention period is 'greater than 90 days'" -Description: "Network Security Group Flow Logs should be enabled and the retention period is set to greater than or equal to 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sg.id resource,\n sg.og_account_id as og_account_id,\n sg.og_resource_id as og_resource_id,\n case\n when fl.id is null or not fl.enabled or fl.retention_policy_days < 90 then 'alarm'\n else 'ok'\n end as status,\n case\n when fl.id is null or not fl.enabled\n then sg.name || ' flowlog not enabled.'\n when fl.retention_policy_days < 90\n then sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.'\n else sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.'\n end as reason\n \n , sg.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_network_security_group sg\n left join azure_network_watcher_flow_log fl on sg.id = fl.target_resource_id\n join azure_subscription sub on sub.subscription_id = sg.subscription_id;\n" - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_network_watcher_flow_log - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled OR fl.retention_policy_days < 90 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled + THEN sg.name || ' flowlog not enabled.' + WHEN fl.retention_policy_days < 90 + THEN sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.' + ELSE sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.' + END AS reason, + sg.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_network_security_group sg + LEFT JOIN azure_network_watcher_flow_log fl ON sg.id = fl.target_resource_id + JOIN azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: high Tags: category: @@ -30,5 +52,4 @@ Tags: - azure service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Ensure that Network Security Group Flow Log retention period is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_subnet_protected_by_firewall.yaml b/compliance/controls/azure/azure_network_subnet_protected_by_firewall.yaml old mode 100755 new mode 100644 index 76e68980e..7e5fd59b5 --- a/compliance/controls/azure/azure_network_subnet_protected_by_firewall.yaml +++ b/compliance/controls/azure/azure_network_subnet_protected_by_firewall.yaml @@ -1,24 +1,24 @@ +Description: Azure Security Center has identified that some of your subnets aren't protected with a next generation firewall. Protect your subnets from potential threats by restricting access to them with Azure Firewall or a supported next generation firewall. ID: azure_network_subnet_protected_by_firewall -Title: "All Internet traffic should be routed via your deployed Azure Firewall" -Description: "Azure Security Center has identified that some of your subnets aren't protected with a next generation firewall. Protect your subnets from potential threats by restricting access to them with Azure Firewall or a supported next generation firewall." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: All Internet traffic should be routed via your deployed Azure Firewall \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_virtual_network_gateway_no_basic_sku.yaml b/compliance/controls/azure/azure_network_virtual_network_gateway_no_basic_sku.yaml old mode 100755 new mode 100644 index ebe881871..a7d4df8ab --- a/compliance/controls/azure/azure_network_virtual_network_gateway_no_basic_sku.yaml +++ b/compliance/controls/azure/azure_network_virtual_network_gateway_no_basic_sku.yaml @@ -1,19 +1,38 @@ +Description: The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft will usually refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads. ID: azure_network_virtual_network_gateway_no_basic_sku -Title: "Virtual network gateways should use standard SKUs as a minimum" -Description: "The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft will usually refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n g.id as resource,\n g.og_account_id as og_account_id,\n g.og_resource_id as og_resource_id,\n case\n when g.sku_name = 'Basic' then 'alarm'\n else 'ok'\n end as status,\n case\n when g.sku_name = 'Basic' then g.title || ' using basic SKU.'\n else g.title || ' using ' || sku_name || ' SKU.'\n end as reason\n \n , g.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_virtual_network_gateway as g,\n azure_subscription as sub\nwhere\n sub.subscription_id = g.subscription_id;\n" - PrimaryTable: azure_virtual_network_gateway ListOfTables: - azure_subscription - azure_virtual_network_gateway Parameters: [] + PrimaryTable: azure_virtual_network_gateway + QueryToExecute: | + SELECT + g.id AS resource, + g.og_account_id AS og_account_id, + g.og_resource_id AS og_resource_id, + CASE + WHEN g.sku_name = 'Basic' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN g.sku_name = 'Basic' THEN g.title || ' using basic SKU.' + ELSE g.title || ' using ' || sku_name || ' SKU.' + END AS reason, + g.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_virtual_network_gateway AS g, + azure_subscription AS sub + WHERE + sub.subscription_id = g.subscription_id; Severity: medium Tags: cis: - "true" service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Virtual network gateways should use standard SKUs as a minimum \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_watcher_enabled.yaml b/compliance/controls/azure/azure_network_watcher_enabled.yaml old mode 100755 new mode 100644 index 7da11f396..9edc9a927 --- a/compliance/controls/azure/azure_network_watcher_enabled.yaml +++ b/compliance/controls/azure/azure_network_watcher_enabled.yaml @@ -1,15 +1,36 @@ +Description: Network Watcher is a regional service that enables you to monitor and diagnose conditions at a network scenario level in, to, and from Azure. Scenario level monitoring enables you to diagnose problems at an end to end network level view. It is required to have a network watcher resource group to be created in every region where a virtual network is present. An alert is enabled if a network watcher resource group is not available in a particular region. ID: azure_network_watcher_enabled -Title: "Network Watcher should be enabled" -Description: "Network Watcher is a regional service that enables you to monitor and diagnose conditions at a network scenario level in, to, and from Azure. Scenario level monitoring enables you to diagnose problems at an end to end network level view. It is required to have a network watcher resource group to be created in every region where a virtual network is present. An alert is enabled if a network watcher resource group is not available in a particular region." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n loc.id resource,\n loc.og_account_id as og_account_id,\n loc.og_resource_id as og_resource_id,\n case\n when watcher.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when watcher.id is null then 'Network watcher not enabled in ' || loc.name || '.'\n else 'Network watcher enabled in ' || loc.name || '.'\n end as reason,\n loc.name\n \n \n , sub.display_name as subscription\nfrom\n azure_location loc\n left join azure_network_watcher watcher on watcher.region = loc.name\n join azure_subscription sub on sub.subscription_id = loc.subscription_id;\n" - PrimaryTable: azure_location ListOfTables: - azure_location - azure_network_watcher - azure_subscription Parameters: [] + PrimaryTable: azure_location + QueryToExecute: | + SELECT + loc.id AS resource, + loc.og_account_id AS og_account_id, + loc.og_resource_id AS og_resource_id, + CASE + WHEN watcher.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN watcher.id IS NULL THEN 'Network watcher not enabled in ' || loc.name || '.' + ELSE 'Network watcher enabled in ' || loc.name || '.' + END AS reason, + loc.name, + sub.display_name AS subscription + FROM + azure_location loc + LEFT JOIN azure_network_watcher watcher + ON watcher.region = loc.name + JOIN azure_subscription sub + ON sub.subscription_id = loc.subscription_id; Severity: medium Tags: category: @@ -30,5 +51,4 @@ Tags: - azure service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Network Watcher should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_watcher_flow_log_enabled.yaml b/compliance/controls/azure/azure_network_watcher_flow_log_enabled.yaml old mode 100755 new mode 100644 index 93f5cb4b7..2febde84a --- a/compliance/controls/azure/azure_network_watcher_flow_log_enabled.yaml +++ b/compliance/controls/azure/azure_network_watcher_flow_log_enabled.yaml @@ -1,30 +1,31 @@ +Description: Audit for flow log resources to verify if flow log status is enabled. Enabling flow logs allows to log information about IP traffic flowing. It can be used for optimizing network flows, monitoring throughput, verifying compliance, detecting intrusions and more. ID: azure_network_watcher_flow_log_enabled -Title: "All flow log resources should be in enabled state" -Description: "Audit for flow log resources to verify if flow log status is enabled. Enabling flow logs allows to log information about IP traffic flowing. It can be used for optimizing network flows, monitoring throughput, verifying compliance, detecting intrusions and more." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when sg.enabled then 'ok' - else 'alarm' - end as status, - case - when sg.enabled then sg.name || ' flowlog enabled.' - else sg.name || ' flowlog disabled.' - end as reason - from - azure_network_watcher_flow_log as sg - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_watcher_flow_log ListOfTables: - azure_network_watcher_flow_log - azure_subscription Parameters: [] + PrimaryTable: azure_network_watcher_flow_log + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN sg.enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sg.enabled THEN sg.name || ' flowlog enabled.' + ELSE sg.name || ' flowlog disabled.' + END AS reason + FROM + azure_network_watcher_flow_log AS sg + JOIN azure_subscription sub + ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: All flow log resources should be in enabled state \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_watcher_flow_log_traffic_analytics_enabled.yaml b/compliance/controls/azure/azure_network_watcher_flow_log_traffic_analytics_enabled.yaml old mode 100755 new mode 100644 index 9fc9d0e03..9f547c871 --- a/compliance/controls/azure/azure_network_watcher_flow_log_traffic_analytics_enabled.yaml +++ b/compliance/controls/azure/azure_network_watcher_flow_log_traffic_analytics_enabled.yaml @@ -1,30 +1,37 @@ +Description: Traffic analytics analyzes flow logs to provide insights into traffic flow in your Azure cloud. It can be used to visualize network activity across your Azure subscriptions and identify hot spots, identify security threats, understand traffic flow patterns, pinpoint network misconfigurations and more. ID: azure_network_watcher_flow_log_traffic_analytics_enabled -Title: "Network Watcher flow logs should have traffic analytics enabled" -Description: "Traffic analytics analyzes flow logs to provide insights into traffic flow in your Azure cloud. It can be used to visualize network activity across your Azure subscriptions and identify hot spots, identify security threats, understand traffic flow patterns, pinpoint network misconfigurations and more." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sg.id resource, - sg.og_account_id as og_account_id, - sg.og_resource_id as og_resource_id, - case - when sg.enabled and traffic_analytics ->> 'enabled' = 'true' and (traffic_analytics ->> 'trafficAnalyticsInterval')::int between 10 and 60 then 'ok' - else 'alarm' - end as status, - case - when sg.enabled and traffic_analytics ->> 'enabled' = 'true' and (traffic_analytics ->> 'trafficAnalyticsInterval')::int between 10 and 60 then sg.name || ' flowlog traffic analytics enabled.' - else sg.name || ' flowlog traffic analytics disabled.' - end as reason - from - azure_network_watcher_flow_log as sg - join azure_subscription sub on sub.subscription_id = sg.subscription_id; - PrimaryTable: azure_network_watcher_flow_log ListOfTables: - azure_network_watcher_flow_log - azure_subscription Parameters: [] + PrimaryTable: azure_network_watcher_flow_log + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id AS og_account_id, + sg.og_resource_id AS og_resource_id, + CASE + WHEN sg.enabled + AND traffic_analytics ->> 'enabled' = 'true' + AND (traffic_analytics ->> 'trafficAnalyticsInterval')::int BETWEEN 10 AND 60 + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sg.enabled + AND traffic_analytics ->> 'enabled' = 'true' + AND (traffic_analytics ->> 'trafficAnalyticsInterval')::int BETWEEN 10 AND 60 + THEN sg.name || ' flowlog traffic analytics enabled.' + ELSE sg.name || ' flowlog traffic analytics disabled.' + END AS reason + FROM + azure_network_watcher_flow_log AS sg + JOIN azure_subscription sub + ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Network Watcher flow logs should have traffic analytics enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_network_watcher_in_regions_with_virtual_network.yaml b/compliance/controls/azure/azure_network_watcher_in_regions_with_virtual_network.yaml old mode 100755 new mode 100644 index 2c4cc776d..6e8ffe81c --- a/compliance/controls/azure/azure_network_watcher_in_regions_with_virtual_network.yaml +++ b/compliance/controls/azure/azure_network_watcher_in_regions_with_virtual_network.yaml @@ -1,20 +1,40 @@ +Description: This policy creates a network watcher resource in regions with virtual networks. You need to ensure existence of a resource group named networkWatcherRG, which will be used to deploy network watcher instances. ID: azure_network_watcher_in_regions_with_virtual_network -Title: "Deploy network watcher when virtual networks are created" -Description: "This policy creates a network watcher resource in regions with virtual networks. You need to ensure existence of a resource group named networkWatcherRG, which will be used to deploy network watcher instances." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when b.region is null then 'alarm'\n when lower(b.resource_group) = 'networkwatcherrg' then 'ok'\n else 'alarm'\n end as status,\n case\n when b.region is null then 'Network watcher does not exist in region' || a.region || '.'\n when lower(b.resource_group) = 'networkwatcherrg' then b.name || ' exist in networkWatcherRG resource group.'\n else b.name || ' does not exist in networkWatcherRG resource group.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_virtual_network as a\n left join azure_network_watcher as b on a.region = b.region\n join azure_subscription sub on sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_virtual_network ListOfTables: - azure_network_watcher - azure_subscription - azure_virtual_network Parameters: [] + PrimaryTable: azure_virtual_network + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN b.region IS NULL THEN 'alarm' + WHEN LOWER(b.resource_group) = 'networkwatcherrg' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.region IS NULL THEN 'Network watcher does not exist in region' || a.region || '.' + WHEN LOWER(b.resource_group) = 'networkwatcherrg' THEN b.name || ' exist in networkWatcherRG resource group.' + ELSE b.name || ' does not exist in networkWatcherRG resource group.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_virtual_network AS a + LEFT JOIN azure_network_watcher AS b ON a.region = b.region + JOIN azure_subscription sub ON sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Deploy network watcher when virtual networks are created \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_db_server_allow_access_to_azure_services_disabled.yaml b/compliance/controls/azure/azure_postgres_db_server_allow_access_to_azure_services_disabled.yaml old mode 100755 new mode 100644 index 6f4676030..38c811f4d --- a/compliance/controls/azure/azure_postgres_db_server_allow_access_to_azure_services_disabled.yaml +++ b/compliance/controls/azure/azure_postgres_db_server_allow_access_to_azure_services_disabled.yaml @@ -1,15 +1,46 @@ +Description: Disable access from Azure services to PostgreSQL Database Server. ID: azure_postgres_db_server_allow_access_to_azure_services_disabled -Title: "Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled" -Description: "Disable access from Azure services to PostgreSQL Database Server." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with postgres_db_with_allow_access_to_azure_services as (\n select\n id\n from\n azure_postgresql_server,\n jsonb_array_elements(firewall_rules) as r\n where\n r -> 'properties' ->> 'endIpAddress' = '255.255.255.255'\n and r -> 'properties' ->> 'startIpAddress' = '0.0.0.0'\n)\nselect\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when a.id is not null then 'alarm'\n else 'ok'\n end as status,\n case\n when a.id is not null then s.title || ' does not restrict access to azure services.'\n else s.title || ' restricts access to azure services.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server as s\n left join postgres_db_with_allow_access_to_azure_services as a on a.id = s.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_services - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + WITH postgres_db_with_allow_access_to_azure_services AS ( + SELECT + id + FROM + azure_postgresql_server, + jsonb_array_elements(firewall_rules) AS r + WHERE + r -> 'properties' ->> 'endIpAddress' = '255.255.255.255' + AND r -> 'properties' ->> 'startIpAddress' = '0.0.0.0' + ) + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN a.id IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.id IS NOT NULL THEN s.title || ' does not restrict access to azure services.' + ELSE s.title || ' restricts access to azure services.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server AS s + LEFT JOIN postgres_db_with_allow_access_to_azure_services AS a ON a.id = s.id, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: category: @@ -30,5 +61,4 @@ Tags: - azure service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_db_server_connection_throttling_on.yaml b/compliance/controls/azure/azure_postgres_db_server_connection_throttling_on.yaml old mode 100755 new mode 100644 index 1b35a7246..f21997cad --- a/compliance/controls/azure/azure_postgres_db_server_connection_throttling_on.yaml +++ b/compliance/controls/azure/azure_postgres_db_server_connection_throttling_on.yaml @@ -1,14 +1,36 @@ +Description: Enable connection_throttling on PostgreSQL Servers. ID: azure_postgres_db_server_connection_throttling_on -Title: "Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable connection_throttling on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter connection_throttling off.'\n else s.name || ' server parameter connection_throttling on.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'connection_throttling'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter connection_throttling off.' + ELSE s.name || ' server parameter connection_throttling on.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'connection_throttling' + AND sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_db_server_geo_redundant_backup_enabled.yaml b/compliance/controls/azure/azure_postgres_db_server_geo_redundant_backup_enabled.yaml old mode 100755 new mode 100644 index d84efa70b..94acf3bee --- a/compliance/controls/azure/azure_postgres_db_server_geo_redundant_backup_enabled.yaml +++ b/compliance/controls/azure/azure_postgres_db_server_geo_redundant_backup_enabled.yaml @@ -1,14 +1,34 @@ +Description: Azure Database for PostgreSQL allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create. ID: azure_postgres_db_server_geo_redundant_backup_enabled -Title: "Geo-redundant backup should be enabled for Azure Database for PostgreSQL" -Description: "Azure Database for PostgreSQL allows you to choose the redundancy option for your database server. It can be set to a geo-redundant backup storage in which the data is not only stored within the region in which your server is hosted, but is also replicated to a paired region to provide recovery option in case of a region failure. Configuring geo-redundant storage for backup is only allowed during server create." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when geo_redundant_backup = 'Enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when geo_redundant_backup = 'Enabled' then name || ' Geo-redundant backup enabled.'\n else name || ' Geo-redundant backup disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN geo_redundant_backup = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN geo_redundant_backup = 'Enabled' THEN name || ' Geo-redundant backup enabled.' + ELSE name || ' Geo-redundant backup disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +37,4 @@ Tags: - "true" service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Geo-redundant backup should be enabled for Azure Database for PostgreSQL \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_db_server_latest_tls_version.yaml b/compliance/controls/azure/azure_postgres_db_server_latest_tls_version.yaml old mode 100755 new mode 100644 index 8b56828f2..76bda9be6 --- a/compliance/controls/azure/azure_postgres_db_server_latest_tls_version.yaml +++ b/compliance/controls/azure/azure_postgres_db_server_latest_tls_version.yaml @@ -1,32 +1,32 @@ +Description: This control checks if the PostgreSQL server is upgraded to the latest TLS version. ID: azure_postgres_db_server_latest_tls_version -Title: "PostgreSQL servers should have the latest TLS version" -Description: "This control checks if the PostgreSQL server is upgraded to the latest TLS version." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when minimal_tls_version = 'TLS1_2' then 'ok' - else 'alarm' - end as status, - case - when minimal_tls_version = 'TLS1_2' then name || ' uses the latest version of TLS encryption.' - else name || ' does not use the latest version of TLS encryption.' - end as reason - from - azure_postgresql_server as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN minimal_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimal_tls_version = 'TLS1_2' THEN name || ' uses the latest version of TLS encryption.' + ELSE name || ' does not use the latest version of TLS encryption.' + END AS reason + FROM + azure_postgresql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: PostgreSQL servers should have the latest TLS version \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_db_server_log_checkpoints_on.yaml b/compliance/controls/azure/azure_postgres_db_server_log_checkpoints_on.yaml old mode 100755 new mode 100644 index 452efbf6a..59c6f9c37 --- a/compliance/controls/azure/azure_postgres_db_server_log_checkpoints_on.yaml +++ b/compliance/controls/azure/azure_postgres_db_server_log_checkpoints_on.yaml @@ -1,14 +1,36 @@ +Description: Enable log_checkpoints on PostgreSQL Servers. ID: azure_postgres_db_server_log_checkpoints_on -Title: "Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_checkpoints on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_checkpoints off.'\n else s.name || ' server parameter log_checkpoints on.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_checkpoints'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_checkpoints off.' + ELSE s.name || ' server parameter log_checkpoints on.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server s, + JSONB_ARRAY_ELEMENTS(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_checkpoints' + AND sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_db_server_log_connections_on.yaml b/compliance/controls/azure/azure_postgres_db_server_log_connections_on.yaml old mode 100755 new mode 100644 index 3e940593b..5c576c649 --- a/compliance/controls/azure/azure_postgres_db_server_log_connections_on.yaml +++ b/compliance/controls/azure/azure_postgres_db_server_log_connections_on.yaml @@ -1,14 +1,36 @@ +Description: Enable log_connections on PostgreSQL Servers. ID: azure_postgres_db_server_log_connections_on -Title: "Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_connections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_connections off.'\n else s.name || ' server parameter log_connections on.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_connections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_connections off.' + ELSE s.name || ' server parameter log_connections on.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server s, + JSONB_ARRAY_ELEMENTS(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_connections' + AND sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_db_server_log_disconnections_on.yaml b/compliance/controls/azure/azure_postgres_db_server_log_disconnections_on.yaml old mode 100755 new mode 100644 index 58977cce1..727854627 --- a/compliance/controls/azure/azure_postgres_db_server_log_disconnections_on.yaml +++ b/compliance/controls/azure/azure_postgres_db_server_log_disconnections_on.yaml @@ -1,14 +1,36 @@ +Description: Enable log_disconnections on PostgreSQL Servers. ID: azure_postgres_db_server_log_disconnections_on -Title: "Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_disconnections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then name || ' server parameter log_disconnections off.'\n else name || ' server parameter log_disconnections on.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_disconnections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN name || ' server parameter log_disconnections off.' + ELSE name || ' server parameter log_disconnections on.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_disconnections' + AND sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_db_server_log_retention_days_3.yaml b/compliance/controls/azure/azure_postgres_db_server_log_retention_days_3.yaml old mode 100755 new mode 100644 index d263b901d..e811351eb --- a/compliance/controls/azure/azure_postgres_db_server_log_retention_days_3.yaml +++ b/compliance/controls/azure/azure_postgres_db_server_log_retention_days_3.yaml @@ -1,14 +1,36 @@ +Description: Enable log_retention_days on PostgreSQL Servers. ID: azure_postgres_db_server_log_retention_days_3 -Title: "Ensure server parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server" -Description: "Enable log_retention_days on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then 'alarm'\n else 'ok'\n end as status,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then s.name || ' log files are retained for 3 days or lesser.'\n else s.name || ' log files are retained for more than 3 days.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) as config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_retention_days'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 THEN s.name || ' log files are retained for 3 days or lesser.' + ELSE s.name || ' log files are retained for more than 3 days.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) AS config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_retention_days' + AND sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Ensure server parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_server_private_link_used.yaml b/compliance/controls/azure/azure_postgres_server_private_link_used.yaml old mode 100755 new mode 100644 index 156476af1..33f517f1c --- a/compliance/controls/azure/azure_postgres_server_private_link_used.yaml +++ b/compliance/controls/azure/azure_postgres_server_private_link_used.yaml @@ -1,19 +1,38 @@ +Description: Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for PostgreSQL. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure. ID: azure_postgres_server_private_link_used -Title: "Private endpoint should be enabled for PostgreSQL servers" -Description: "Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for PostgreSQL. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n -- Only applicable to standard tier\n when sku_tier = 'Basic' then 'skip'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then 'ok'\n else 'alarm'\n end as status,\n case\n when sku_tier = 'Basic' then a.name || ' is of ' || sku_tier || ' tier.'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then a.name || ' using private link.'\n else a.name || ' not using private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server a,\n azure_subscription sub;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_tier = 'Basic' THEN 'skip' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_tier = 'Basic' THEN a.name || ' is of ' || sku_tier || ' tier.' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN a.name || ' using private link.' + ELSE a.name || ' not using private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server a, + azure_subscription sub; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Private endpoint should be enabled for PostgreSQL servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_sql_server_encrypted_at_rest_using_cmk.yaml b/compliance/controls/azure/azure_postgres_sql_server_encrypted_at_rest_using_cmk.yaml old mode 100755 new mode 100644 index 28b442457..fe84f8af6 --- a/compliance/controls/azure/azure_postgres_sql_server_encrypted_at_rest_using_cmk.yaml +++ b/compliance/controls/azure/azure_postgres_sql_server_encrypted_at_rest_using_cmk.yaml @@ -1,20 +1,44 @@ +Description: Use customer-managed keys to manage the encryption at rest of your PostgreSQL servers. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_postgres_sql_server_encrypted_at_rest_using_cmk -Title: "PostgreSQL servers should use customer-managed keys to encrypt data at rest" -Description: "Use customer-managed keys to manage the encryption at rest of your PostgreSQL servers. By default, the data is encrypted at rest with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with pgql_server_encrypted as (\n select\n distinct i.id as id\n from\n azure_mysql_server as i,\n jsonb_array_elements(server_keys) a\n where\n a ->> 'serverKeyType' = 'AzureKeyVault'\n and a ->> 'uri' is not null\n)\nselect\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when a.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when a.id is not null then s.title || ' encrypted with CMK.'\n else s.title || ' not encrypted with CMK.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server as s\n left join pgql_server_encrypted as a on s.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_mysql_server - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + WITH pgql_server_encrypted AS ( + SELECT DISTINCT i.id AS id + FROM azure_mysql_server AS i, + jsonb_array_elements(server_keys) a + WHERE a ->> 'serverKeyType' = 'AzureKeyVault' + AND a ->> 'uri' IS NOT NULL + ) + SELECT s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN a.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.id IS NOT NULL THEN s.title || ' encrypted with CMK.' + ELSE s.title || ' not encrypted with CMK.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM azure_postgresql_server AS s + LEFT JOIN pgql_server_encrypted AS a ON s.id = a.id, + azure_subscription AS sub + WHERE sub.subscription_id = s.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: PostgreSQL servers should use customer-managed keys to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgres_sql_ssl_enabled.yaml b/compliance/controls/azure/azure_postgres_sql_ssl_enabled.yaml old mode 100755 new mode 100644 index 34304aff4..e06c6d4ae --- a/compliance/controls/azure/azure_postgres_sql_ssl_enabled.yaml +++ b/compliance/controls/azure/azure_postgres_sql_ssl_enabled.yaml @@ -1,14 +1,34 @@ +Description: Azure Database for PostgreSQL supports connecting your Azure Database for PostgreSQL server to client applications using Secure Sockets Layer (SSL). Enforcing SSL connections between your database server and your client applications helps protect against 'man in the middle' attacks by encrypting the data stream between the server and your application. This configuration enforces that SSL is always enabled for accessing your database server ID: azure_postgres_sql_ssl_enabled -Title: "Enforce SSL connection should be enabled for PostgreSQL database servers" -Description: "Azure Database for PostgreSQL supports connecting your Azure Database for PostgreSQL server to client applications using Secure Sockets Layer (SSL). Enforcing SSL connections between your database server and your client applications helps protect against 'man in the middle' attacks by encrypting the data stream between the server and your application. This configuration enforces that SSL is always enabled for accessing your database server" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when ssl_enforcement = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when ssl_enforcement = 'Disabled' then name || ' SSL connection disabled.'\n else name || ' SSL connection enabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server s,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN ssl_enforcement = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ssl_enforcement = 'Disabled' THEN name || ' SSL connection disabled.' + ELSE name || ' SSL connection enabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Enforce SSL connection should be enabled for PostgreSQL database servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgresql_server_infrastructure_encryption_enabled.yaml b/compliance/controls/azure/azure_postgresql_server_infrastructure_encryption_enabled.yaml old mode 100755 new mode 100644 index 3ef3da2df..34ee73dce --- a/compliance/controls/azure/azure_postgresql_server_infrastructure_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_postgresql_server_infrastructure_encryption_enabled.yaml @@ -1,14 +1,34 @@ +Description: Enable infrastructure encryption for Azure Database for PostgreSQL servers to have higher level of assurance that the data is secure. When infrastructure encryption is enabled, the data at rest is encrypted twice using FIPS 140-2 compliant Microsoft managed keys. ID: azure_postgresql_server_infrastructure_encryption_enabled -Title: "Infrastructure encryption should be enabled for Azure Database for PostgreSQL servers" -Description: "Enable infrastructure encryption for Azure Database for PostgreSQL servers to have higher level of assurance that the data is secure. When infrastructure encryption is enabled, the data at rest is encrypted twice using FIPS 140-2 compliant Microsoft managed keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when infrastructure_encryption = 'Enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when infrastructure_encryption = 'Enabled' then name || ' infrastructure encryption enabled.'\n else name || ' infrastructure encryption disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN infrastructure_encryption = 'Enabled' THEN name || ' infrastructure encryption enabled.' + ELSE name || ' infrastructure encryption disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Infrastructure encryption should be enabled for Azure Database for PostgreSQL servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_postgresql_server_public_network_access_disabled.yaml b/compliance/controls/azure/azure_postgresql_server_public_network_access_disabled.yaml old mode 100755 new mode 100644 index 65e0367cb..17b212001 --- a/compliance/controls/azure/azure_postgresql_server_public_network_access_disabled.yaml +++ b/compliance/controls/azure/azure_postgresql_server_public_network_access_disabled.yaml @@ -1,19 +1,38 @@ +Description: Disable the public network access property to improve security and ensure your Azure Database for PostgreSQL can only be accessed from a private endpoint. This configuration disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules. ID: azure_postgresql_server_public_network_access_disabled -Title: "Public network access should be disabled for PostgreSQL servers" -Description: "Disable the public network access property to improve security and ensure your Azure Database for PostgreSQL can only be accessed from a private endpoint. This configuration disables access from any public address space outside of Azure IP range, and denies all logins that match IP or virtual network-based firewall rules." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when public_network_access = 'Enabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when public_network_access = 'Enabled' then name || ' public network access enabled.'\n else name || ' public network access disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_postgresql_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_postgresql_server ListOfTables: - azure_postgresql_server - azure_subscription Parameters: [] + PrimaryTable: azure_postgresql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN name || ' public network access enabled.' + ELSE name || ' public network access disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_postgresql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/PostgreSQL -IntegrationType: - - azure_subscription +Title: Public network access should be disabled for PostgreSQL servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_recovery_service_vault_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_recovery_service_vault_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 833a38b55..77ddb7569 --- a/compliance/controls/azure/azure_recovery_service_vault_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_recovery_service_vault_encrypted_with_cmk.yaml @@ -3,15 +3,15 @@ Title: "Azure Recovery Services vaults should use customer-managed keys for encr Description: "Use customer-managed keys to manage the encryption at rest of your backup data. By default, customer data is encrypted with service-managed keys, but customer-managed keys are commonly required to meet regulatory compliance standards. Customer-managed keys enable the data to be encrypted with an Azure Key Vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. Learn more at https://aka.ms/AB-CmkEncryption." Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM azure_subscription; PrimaryTable: "" ListOfTables: [] @@ -21,4 +21,4 @@ Tags: manual-verification: - "true" IntegrationType: - - azure_subscription + - azure_subscription \ No newline at end of file diff --git a/compliance/controls/azure/azure_recovery_service_vault_uses_managed_identity.yaml b/compliance/controls/azure/azure_recovery_service_vault_uses_managed_identity.yaml old mode 100755 new mode 100644 index 6b9507b05..c2426e43b --- a/compliance/controls/azure/azure_recovery_service_vault_uses_managed_identity.yaml +++ b/compliance/controls/azure/azure_recovery_service_vault_uses_managed_identity.yaml @@ -1,32 +1,32 @@ +Description: Recovery Services vaults should use a managed identity for enhanced authentication security. ID: azure_recovery_service_vault_uses_managed_identity -Title: "Recovery Services vaults should use managed identity" -Description: "Recovery Services vaults should use a managed identity for enhanced authentication security." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when identity is null or identity ->> 'type' = 'None' then 'alarm' - else 'ok' - end as status, - case - when identity is null or identity ->> 'type' = 'None' then name || ' not uses managed identity.' - else name || ' uses managed identity.' - end as reason - from - azure_recovery_services_vault as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_recovery_services_vault ListOfTables: - azure_recovery_services_vault - azure_subscription Parameters: [] + PrimaryTable: azure_recovery_services_vault + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN identity IS NULL OR identity ->> 'type' = 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity IS NULL OR identity ->> 'type' = 'None' THEN name || ' not uses managed identity.' + ELSE name || ' uses managed identity.' + END AS reason + FROM + azure_recovery_services_vault AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Recovery Services vaults should use managed identity \ No newline at end of file diff --git a/compliance/controls/azure/azure_recovery_service_vault_uses_private_link.yaml b/compliance/controls/azure/azure_recovery_service_vault_uses_private_link.yaml old mode 100755 new mode 100644 index a2044813f..99bc261bb --- a/compliance/controls/azure/azure_recovery_service_vault_uses_private_link.yaml +++ b/compliance/controls/azure/azure_recovery_service_vault_uses_private_link.yaml @@ -1,32 +1,32 @@ +Description: 'Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Recovery Services vaults, data leakage risks are reduced. Learn more about private links for Azure Site Recovery at: https://aka.ms/HybridScenarios-PrivateLink and https://aka.ms/AzureToAzure-PrivateLink.' ID: azure_recovery_service_vault_uses_private_link -Title: "Recovery Services vaults should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Recovery Services vaults, data leakage risks are reduced. Learn more about private links for Azure Site Recovery at: https://aka.ms/HybridScenarios-PrivateLink and https://aka.ms/AzureToAzure-PrivateLink." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when private_endpoint_state_for_site_recovery = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when private_endpoint_state_for_site_recovery = 'Enabled' then 'Private link for site recovery is enabled.' - else 'Private link for site recovery is disabled.' - end as reason - from - azure_recovery_services_vault as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_recovery_services_vault ListOfTables: - azure_recovery_services_vault - azure_subscription Parameters: [] + PrimaryTable: azure_recovery_services_vault + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN private_endpoint_state_for_site_recovery = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN private_endpoint_state_for_site_recovery = 'Enabled' THEN 'Private link for site recovery is enabled.' + ELSE 'Private link for site recovery is disabled.' + END AS reason + FROM + azure_recovery_services_vault AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Recovery Services vaults should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_recovery_service_vault_uses_private_link_for_backup.yaml b/compliance/controls/azure/azure_recovery_service_vault_uses_private_link_for_backup.yaml old mode 100755 new mode 100644 index 8808a1a13..e91ac8d33 --- a/compliance/controls/azure/azure_recovery_service_vault_uses_private_link_for_backup.yaml +++ b/compliance/controls/azure/azure_recovery_service_vault_uses_private_link_for_backup.yaml @@ -1,32 +1,32 @@ +Description: 'Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Recovery Services vaults, data leakage risks are reduced. Learn more about private links at: https://aka.ms/AB-PrivateEndpoints.' ID: azure_recovery_service_vault_uses_private_link_for_backup -Title: "Azure Recovery Services vaults should use private link for backup" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Recovery Services vaults, data leakage risks are reduced. Learn more about private links at: https://aka.ms/AB-PrivateEndpoints." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when private_endpoint_state_for_backup = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when private_endpoint_state_for_backup = 'Enabled' then 'Private link for backup is enabled.' - else 'Private link for backup is disabled.' - end as reason - from - azure_recovery_services_vault as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_recovery_services_vault ListOfTables: - azure_recovery_services_vault - azure_subscription Parameters: [] + PrimaryTable: azure_recovery_services_vault + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN private_endpoint_state_for_backup = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN private_endpoint_state_for_backup = 'Enabled' THEN 'Private link for backup is enabled.' + ELSE 'Private link for backup is disabled.' + END AS reason + FROM + azure_recovery_services_vault AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Azure Recovery Services vaults should use private link for backup \ No newline at end of file diff --git a/compliance/controls/azure/azure_redis_cache_in_virtual_network.yaml b/compliance/controls/azure/azure_redis_cache_in_virtual_network.yaml old mode 100755 new mode 100644 index 28206f9e6..b5247de2b --- a/compliance/controls/azure/azure_redis_cache_in_virtual_network.yaml +++ b/compliance/controls/azure/azure_redis_cache_in_virtual_network.yaml @@ -1,32 +1,32 @@ +Description: Azure Virtual Network deployment provides enhanced security and isolation for your Azure Cache for Redis, as well as subnets, access control policies, and other features to further restrict access. When an Azure Cache for Redis instance is configured with a virtual network, it is not publicly addressable and can only be accessed from virtual machines and applications within the virtual network. ID: azure_redis_cache_in_virtual_network -Title: "Azure Cache for Redis should reside within a virtual network" -Description: "Azure Virtual Network deployment provides enhanced security and isolation for your Azure Cache for Redis, as well as subnets, access control policies, and other features to further restrict access.When an Azure Cache for Redis instance is configured with a virtual network, it is not publicly addressable and can only be accessed from virtual machines and applications within the virtual network." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - redis.id as resource, - redis.og_account_id as og_account_id, - redis.og_resource_id as og_resource_id, - case - when subnet_id is not null then 'ok' - else 'alarm' - end as status, - case - when subnet_id is not null then redis.name || ' in virtual network.' - else redis.name || ' not in virtual network.' - end as reason - from - azure_redis_cache as redis, - azure_subscription as sub - where - sub.subscription_id = redis.subscription_id; - PrimaryTable: azure_redis_cache ListOfTables: - azure_redis_cache - azure_subscription Parameters: [] + PrimaryTable: azure_redis_cache + QueryToExecute: | + SELECT + redis.id AS resource, + redis.og_account_id AS og_account_id, + redis.og_resource_id AS og_resource_id, + CASE + WHEN subnet_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN subnet_id IS NOT NULL THEN redis.name || ' in virtual network.' + ELSE redis.name || ' not in virtual network.' + END AS reason + FROM + azure_redis_cache AS redis, + azure_subscription AS sub + WHERE + sub.subscription_id = redis.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Azure Cache for Redis should reside within a virtual network \ No newline at end of file diff --git a/compliance/controls/azure/azure_redis_cache_min_tls_1_2.yaml b/compliance/controls/azure/azure_redis_cache_min_tls_1_2.yaml old mode 100755 new mode 100644 index 036498423..4182d4ab2 --- a/compliance/controls/azure/azure_redis_cache_min_tls_1_2.yaml +++ b/compliance/controls/azure/azure_redis_cache_min_tls_1_2.yaml @@ -1,33 +1,33 @@ +Description: This control checks whether 'Minimum TLS version' is set to 1.2. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to later protocols such as TLS 1.2. ID: azure_redis_cache_min_tls_1_2 -Title: "Redis Caches 'Minimum TLS version' should be set to 'Version 1.2'" -Description: "This control checks whether 'Minimum TLS version' is set to 1.2. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to later protocols such as TLS 1.2." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - c.id as resource, - c.og_account_id as og_account_id, - c.og_resource_id as og_resource_id, - case - when minimum_tls_version is null then 'alarm' - when minimum_tls_version = '1.2' then 'ok' - else 'alarm' - end as status, - case - when minimum_tls_version is null then c.name || ' minimum TLS version not set.' - else c.name || ' minimum TLS version set to ' || minimum_tls_version || '.' - end as reason - from - azure_redis_cache as c, - azure_subscription sub - where - sub.subscription_id = c.subscription_id; - PrimaryTable: azure_redis_cache ListOfTables: - azure_redis_cache - azure_subscription Parameters: [] + PrimaryTable: azure_redis_cache + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN minimum_tls_version IS NULL THEN 'alarm' + WHEN minimum_tls_version = '1.2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_tls_version IS NULL THEN c.name || ' minimum TLS version not set.' + ELSE c.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + END AS reason + FROM + azure_redis_cache AS c, + azure_subscription sub + WHERE + sub.subscription_id = c.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Redis Caches 'Minimum TLS version' should be set to 'Version 1.2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_redis_cache_no_basic_sku.yaml b/compliance/controls/azure/azure_redis_cache_no_basic_sku.yaml old mode 100755 new mode 100644 index 7c4f7ae66..1bc6f4c4b --- a/compliance/controls/azure/azure_redis_cache_no_basic_sku.yaml +++ b/compliance/controls/azure/azure_redis_cache_no_basic_sku.yaml @@ -1,19 +1,38 @@ +Description: The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft will usually refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads. ID: azure_redis_cache_no_basic_sku -Title: "Azure Cache for Redis should use standard SKUs as a minimum" -Description: "The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft will usually refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n c.id as resource,\n c.og_account_id as og_account_id,\n c.og_resource_id as og_resource_id,\n case\n when c.sku_name = 'Basic' then 'alarm'\n else 'ok'\n end as status,\n case\n when c.sku_name = 'Basic' then c.title || ' using basic SKU.'\n else c.title || ' using ' || sku_name || ' SKU.'\n end as reason\n \n , c.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_redis_cache as c,\n azure_subscription as sub\nwhere\n sub.subscription_id = c.subscription_id;\n" - PrimaryTable: azure_redis_cache ListOfTables: - azure_redis_cache - azure_subscription Parameters: [] + PrimaryTable: azure_redis_cache + QueryToExecute: | + SELECT + c.id AS resource, + c.og_account_id AS og_account_id, + c.og_resource_id AS og_resource_id, + CASE + WHEN c.sku_name = 'Basic' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.sku_name = 'Basic' THEN c.title || ' using basic SKU.' + ELSE c.title || ' using ' || sku_name || ' SKU.' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_redis_cache AS c, + azure_subscription AS sub + WHERE + sub.subscription_id = c.subscription_id; Severity: medium Tags: cis: - "true" service: - Azure/Redis -IntegrationType: - - azure_subscription +Title: Azure Cache for Redis should use standard SKUs as a minimum \ No newline at end of file diff --git a/compliance/controls/azure/azure_redis_cache_ssl_enabled.yaml b/compliance/controls/azure/azure_redis_cache_ssl_enabled.yaml old mode 100755 new mode 100644 index 10183ef00..04a5e4b25 --- a/compliance/controls/azure/azure_redis_cache_ssl_enabled.yaml +++ b/compliance/controls/azure/azure_redis_cache_ssl_enabled.yaml @@ -1,32 +1,32 @@ +Description: Audit enabling of only connections via SSL to Azure Cache for Redis. Use of secure connections ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking. ID: azure_redis_cache_ssl_enabled -Title: "Only secure connections to your Azure Cache for Redis should be enabled" -Description: "Audit enabling of only connections via SSL to Azure Cache for Redis. Use of secure connections ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - redis.id as resource, - redis.og_account_id as og_account_id, - redis.og_resource_id as og_resource_id, - case - when enable_non_ssl_port then 'alarm' - else 'ok' - end as status, - case - when enable_non_ssl_port then redis.name || ' secure connections disabled.' - else redis.name || ' secure connections enabled.' - end as reason - from - azure_redis_cache as redis, - azure_subscription as sub - where - sub.subscription_id = redis.subscription_id; - PrimaryTable: azure_redis_cache ListOfTables: - azure_redis_cache - azure_subscription Parameters: [] + PrimaryTable: azure_redis_cache + QueryToExecute: | + SELECT + redis.id AS resource, + redis.og_account_id AS og_account_id, + redis.og_resource_id AS og_resource_id, + CASE + WHEN enable_non_ssl_port THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN enable_non_ssl_port THEN redis.name || ' secure connections disabled.' + ELSE redis.name || ' secure connections enabled.' + END AS reason + FROM + azure_redis_cache AS redis, + azure_subscription AS sub + WHERE + sub.subscription_id = redis.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Only secure connections to your Azure Cache for Redis should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_redis_cache_uses_private_link.yaml b/compliance/controls/azure/azure_redis_cache_uses_private_link.yaml old mode 100755 new mode 100644 index 0a23ce23a..d674a3d93 --- a/compliance/controls/azure/azure_redis_cache_uses_private_link.yaml +++ b/compliance/controls/azure/azure_redis_cache_uses_private_link.yaml @@ -1,42 +1,42 @@ +Description: Private endpoints lets you connect your virtual network to Azure services without a public IP address at the source or destination. By mapping private endpoints to your Azure Cache for Redis instances, data leakage risks are reduced. ID: azure_redis_cache_uses_private_link -Title: "Azure Cache for Redis should use private link" -Description: "Private endpoints lets you connect your virtual network to Azure services without a public IP address at the source or destination. By mapping private endpoints to your Azure Cache for Redis instances, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with redis_private_connection as ( - select - distinct a.id - from - azure_redis_cache as a, - jsonb_array_elements(private_endpoint_connections) as connection - where - connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' - ) - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when c.id is null then 'alarm' - else 'ok' - end as status, - case - when c.id is null then a.name || ' not uses private link.' - else a.name || ' uses private link.' - end as reason - from - azure_redis_cache as a - left join redis_private_connection as c on c.id = a.id, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_redis_cache ListOfTables: - azure_redis_cache - azure_subscription Parameters: [] + PrimaryTable: azure_redis_cache + QueryToExecute: | + WITH redis_private_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_redis_cache AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason + FROM + azure_redis_cache AS a + LEFT JOIN redis_private_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Azure Cache for Redis should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_search_service_logging_enabled.yaml b/compliance/controls/azure/azure_search_service_logging_enabled.yaml old mode 100755 new mode 100644 index 381f33ba0..d4efabe0e --- a/compliance/controls/azure/azure_search_service_logging_enabled.yaml +++ b/compliance/controls/azure/azure_search_service_logging_enabled.yaml @@ -1,14 +1,62 @@ +Description: Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised. ID: azure_search_service_logging_enabled -Title: "Resource logs in Search services should be enabled" -Description: "Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n distinct name as search_service_name\n from\n azure_search_service,\n jsonb_array_elements(diagnostic_settings) setting,\n jsonb_array_elements(setting -> 'properties' -> 'logs') log\n where\n diagnostic_settings is not null\n and (\n (\n (log ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy' ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy') :: JSONB ? 'days'\n )\n or\n (\n (log ->> 'enabled') :: boolean\n and (\n log -> 'retentionPolicy' ->> 'enabled' <> 'true'\n or setting -> 'properties' ->> 'storageAccountId' = ''\n )\n )\n )\n)\nselect\n v.id as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when v.diagnostic_settings is null then 'alarm'\n when l.search_service_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when v.diagnostic_settings is null then v.name || ' logging not enabled.'\n when l.search_service_name is null then v.name || ' logging not enabled.'\n else v.name || ' logging enabled.'\n end as reason\n \n , v.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_search_service as v\n left join logging_details as l on v.name = l.search_service_name,\n azure_subscription as sub\nwhere\n sub.subscription_id = v.subscription_id;\n" - PrimaryTable: azure_search_service ListOfTables: - azure_search_service - azure_subscription Parameters: [] + PrimaryTable: azure_search_service + QueryToExecute: | + WITH logging_details AS ( + SELECT + DISTINCT name AS search_service_name + FROM + azure_search_service, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND ( + ( + (log ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy' ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy')::JSONB ? 'days' + ) + OR + ( + (log ->> 'enabled')::BOOLEAN + AND ( + log -> 'retentionPolicy' ->> 'enabled' <> 'true' + OR setting -> 'properties' ->> 'storageAccountId' = '' + ) + ) + ) + ) + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.search_service_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.search_service_name IS NULL THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_search_service AS v + LEFT JOIN logging_details AS l ON v.name = l.search_service_name, + azure_subscription AS sub + WHERE + sub.subscription_id = v.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +65,4 @@ Tags: - "true" service: - Azure/CognitiveSearch -IntegrationType: - - azure_subscription +Title: Resource logs in Search services should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_search_service_public_network_access_disabled.yaml b/compliance/controls/azure/azure_search_service_public_network_access_disabled.yaml old mode 100755 new mode 100644 index 4698dadc2..eaaee647e --- a/compliance/controls/azure/azure_search_service_public_network_access_disabled.yaml +++ b/compliance/controls/azure/azure_search_service_public_network_access_disabled.yaml @@ -1,19 +1,38 @@ +Description: Disabling public network access improves security by ensuring that your Azure Cognitive Search service is not exposed on the public internet. Creating private endpoints can limit exposure of your Search service. ID: azure_search_service_public_network_access_disabled -Title: "Azure Cognitive Search services should disable public network access" -Description: "Disabling public network access improves security by ensuring that your Azure Cognitive Search service is not exposed on the public internet. Creating private endpoints can limit exposure of your Search service." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when public_network_access = 'Enabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when public_network_access = 'Enabled' then name || ' public network access enabled.'\n else name || ' public network access disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_search_service as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_search_service ListOfTables: - azure_search_service - azure_subscription Parameters: [] + PrimaryTable: azure_search_service + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN name || ' public network access enabled.' + ELSE name || ' public network access disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_search_service AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/CognitiveSearch -IntegrationType: - - azure_subscription +Title: Azure Cognitive Search services should disable public network access \ No newline at end of file diff --git a/compliance/controls/azure/azure_search_service_replica_count_3.yaml b/compliance/controls/azure/azure_search_service_replica_count_3.yaml old mode 100755 new mode 100644 index d0b23e6eb..b20f54fd3 --- a/compliance/controls/azure/azure_search_service_replica_count_3.yaml +++ b/compliance/controls/azure/azure_search_service_replica_count_3.yaml @@ -1,29 +1,29 @@ +Description: This control checks if Cognitive Search maintains SLA for index updates. ID: azure_search_service_replica_count_3 -Title: "Cognitive Search services should maintain SLA for index updates" -Description: "This control checks if Cognitive Search maintains SLA for index updates." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when replica_count > 3 then 'ok' - else 'alarm' - end as status, - name || ' has ' || replica_count || ' replica count.' as reason - from - azure_search_service as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_search_service ListOfTables: - azure_search_service - azure_subscription Parameters: [] + PrimaryTable: azure_search_service + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN replica_count > 3 THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' has ' || replica_count || ' replica count.' AS reason + FROM + azure_search_service AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Cognitive Search services should maintain SLA for index updates \ No newline at end of file diff --git a/compliance/controls/azure/azure_search_service_uses_managed_identity.yaml b/compliance/controls/azure/azure_search_service_uses_managed_identity.yaml old mode 100755 new mode 100644 index 2ba8e3dc0..83042f93a --- a/compliance/controls/azure/azure_search_service_uses_managed_identity.yaml +++ b/compliance/controls/azure/azure_search_service_uses_managed_identity.yaml @@ -1,32 +1,32 @@ +Description: Cognitive Search services should use a managed identity for enhanced authentication security. ID: azure_search_service_uses_managed_identity -Title: "Cognitive Search services should use managed identity" -Description: "Cognitive Search services should use a managed identity for enhanced authentication security." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when identity ->> 'type' = 'SystemAssigned' then 'ok' - else 'alarm' - end as status, - case - when identity ->> 'type' = 'SystemAssigned' then name || ' use managed identity.' - else name || ' not use managed identity.' - end as reason - from - azure_search_service as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_search_service ListOfTables: - azure_search_service - azure_subscription Parameters: [] + PrimaryTable: azure_search_service + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN identity ->> 'type' = 'SystemAssigned' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN identity ->> 'type' = 'SystemAssigned' THEN name || ' use managed identity.' + ELSE name || ' not use managed identity.' + END AS reason + FROM + azure_search_service AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Cognitive Search services should use managed identity \ No newline at end of file diff --git a/compliance/controls/azure/azure_search_service_uses_private_link.yaml b/compliance/controls/azure/azure_search_service_uses_private_link.yaml old mode 100755 new mode 100644 index 23ddbedbd..39a228cb0 --- a/compliance/controls/azure/azure_search_service_uses_private_link.yaml +++ b/compliance/controls/azure/azure_search_service_uses_private_link.yaml @@ -1,19 +1,48 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Cognitive Search, data leakage risks are reduced. ID: azure_search_service_uses_private_link -Title: "Azure Cognitive Search services should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Cognitive Search, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with search_service_connection as (\n select\n distinct a.id\n from\n azure_search_service as a,\n jsonb_array_elements(private_endpoint_connections) as connection\n where\n connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when c.id is null then a.title || ' not uses private link.'\n else a.title || ' uses private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_search_service as a\n left join search_service_connection as c on c.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_search_service ListOfTables: - azure_search_service - azure_subscription Parameters: [] + PrimaryTable: azure_search_service + QueryToExecute: | + WITH search_service_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_search_service AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.title || ' not uses private link.' + ELSE a.title || ' uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_search_service AS a + LEFT JOIN search_service_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/CognitiveSearch -IntegrationType: - - azure_subscription +Title: Azure Cognitive Search services should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_search_service_uses_sku_supporting_private_link.yaml b/compliance/controls/azure/azure_search_service_uses_sku_supporting_private_link.yaml old mode 100755 new mode 100644 index 096a2dcd9..4aee01b34 --- a/compliance/controls/azure/azure_search_service_uses_sku_supporting_private_link.yaml +++ b/compliance/controls/azure/azure_search_service_uses_sku_supporting_private_link.yaml @@ -1,19 +1,38 @@ +Description: With supported SKUs of Azure Cognitive Search, Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Search service, data leakage risks are reduced. ID: azure_search_service_uses_sku_supporting_private_link -Title: "Azure Cognitive Search service should use a SKU that supports private link" -Description: "With supported SKUs of Azure Cognitive Search, Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Search service, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when sku_name = 'free' then 'alarm'\n else 'ok'\n end as status,\n case\n when sku_name = 'free' then s.title || ' SKU does not supports private link.'\n else s.title || ' SKU supports private link.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_search_service as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_search_service ListOfTables: - azure_search_service - azure_subscription Parameters: [] + PrimaryTable: azure_search_service + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN sku_name = 'free' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sku_name = 'free' THEN s.title || ' SKU does not support private link.' + ELSE s.title || ' SKU supports private link.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_search_service AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/CognitiveSearch -IntegrationType: - - azure_subscription +Title: Azure Cognitive Search service should use a SKU that supports private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_additional_email_configured.yaml b/compliance/controls/azure/azure_securitycenter_additional_email_configured.yaml old mode 100755 new mode 100644 index 3a619eea6..f43321de5 --- a/compliance/controls/azure/azure_securitycenter_additional_email_configured.yaml +++ b/compliance/controls/azure/azure_securitycenter_additional_email_configured.yaml @@ -1,14 +1,45 @@ +Description: Security Center emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address. ID: azure_securitycenter_additional_email_configured -Title: "Ensure 'Additional email addresses' is configured with a security contact email" -Description: "Security Center emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with contact_info as (\n select\n jsonb_agg(email) filter (where name = 'default' and email != '') as default_email,\n count(*) filter (where name != 'default') as non_default_count,\n count(*) filter (where name = 'default') as default_count,\n subscription_id\n from\n azure_security_center_contact\n group by\n subscription_id\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when non_default_count > 0 then 'ok'\n when default_count = 1 and jsonb_array_length(default_email) != 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when non_default_count > 0 then 'Additional email addresses configured.'\n when default_count = 1 and default_email is not null then'Additional email addresses configured.'\n else 'Additional email addresses not configured.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join contact_info ci on sub.subscription_id = ci.subscription_id;\n" - PrimaryTable: azure_security_center_contact ListOfTables: - azure_security_center_contact - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_contact + QueryToExecute: | + WITH contact_info AS ( + SELECT + jsonb_agg(email) FILTER (WHERE name = 'default' AND email != '') AS default_email, + COUNT(*) FILTER (WHERE name != 'default') AS non_default_count, + COUNT(*) FILTER (WHERE name = 'default') AS default_count, + subscription_id + FROM + azure_security_center_contact + GROUP BY + subscription_id + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN non_default_count > 0 THEN 'OK' + WHEN default_count = 1 AND jsonb_array_length(default_email) != 0 THEN 'OK' + ELSE 'ALARM' + END AS status, + CASE + WHEN non_default_count > 0 THEN 'Additional email addresses configured.' + WHEN default_count = 1 AND default_email IS NOT NULL THEN 'Additional email addresses configured.' + ELSE 'Additional email addresses not configured.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: high Tags: category: @@ -29,5 +60,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Ensure 'Additional email addresses' is configured with a security contact email \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_asc_default_setting_not_disabled.yaml b/compliance/controls/azure/azure_securitycenter_asc_default_setting_not_disabled.yaml old mode 100755 new mode 100644 index 68f144236..e4eb32e8c --- a/compliance/controls/azure/azure_securitycenter_asc_default_setting_not_disabled.yaml +++ b/compliance/controls/azure/azure_securitycenter_asc_default_setting_not_disabled.yaml @@ -1,14 +1,53 @@ +Description: None of the settings offered by ASC Default policy should be set to effect "Disabled". ID: azure_securitycenter_asc_default_setting_not_disabled -Title: "Ensure any of the ASC Default policy setting is not set to \\\"Disabled\\\"" -Description: "None of the settings offered by ASC Default policy should be set to effect \\\"Disabled\\\"." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with policy_assignment_parameters as (\n select\n id,\n name,\n key,\n parameters -> key ->> 'value' as value,\n subscription_id\n from\n azure_policy_assignment,\n jsonb_object_keys(parameters) as key\n where\n name = 'SecurityCenterBuiltIn'\n)\nselect\n sub.id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when count(value = 'Disabled') > 0 then 'alarm'\n else 'ok'\n end as status,\n case\n when count(value = 'Disabled') > 0 then 'Settings disabled for ' || count(*) filter (where value = 'Disabled') || ' parameters.'\n else 'Settings enabled for all the parameters.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n policy_assignment_parameters pol_assignment\n right join azure_subscription sub on pol_assignment.subscription_id = sub.subscription_id\ngroup by\n sub.id,\n sub.og_account_id,\n sub.og_resource_id,\n pol_assignment.id,\n sub._ctx,\n sub.subscription_id,\n pol_assignment.subscription_id,\n sub.display_name;\n" - PrimaryTable: azure_policy_assignment ListOfTables: - azure_policy_assignment - azure_subscription Parameters: [] + PrimaryTable: azure_policy_assignment + QueryToExecute: | + WITH policy_assignment_parameters AS ( + SELECT + id, + name, + key, + parameters -> key ->> 'value' AS value, + subscription_id + FROM + azure_policy_assignment, + jsonb_object_keys(parameters) AS key + WHERE + name = 'SecurityCenterBuiltIn' + ) + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN COUNT(value = 'Disabled') > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(value = 'Disabled') > 0 THEN 'Settings disabled for ' || COUNT(*) FILTER (WHERE value = 'Disabled') || ' parameters.' + ELSE 'Settings enabled for all the parameters.' + END AS reason, + sub.display_name AS subscription + FROM + policy_assignment_parameters pol_assignment + RIGHT JOIN azure_subscription sub ON pol_assignment.subscription_id = sub.subscription_id + GROUP BY + sub.id, + sub.og_account_id, + sub.og_resource_id, + pol_assignment.id, + sub._ctx, + sub.subscription_id, + pol_assignment.subscription_id, + sub.display_name Severity: high Tags: category: @@ -29,5 +68,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Ensure any of the ASC Default policy setting is not set to "Disabled" \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_automatic_provisioning_monitoring_agent_on.yaml b/compliance/controls/azure/azure_securitycenter_automatic_provisioning_monitoring_agent_on.yaml old mode 100755 new mode 100644 index 9ed3e11ff..3646fc852 --- a/compliance/controls/azure/azure_securitycenter_automatic_provisioning_monitoring_agent_on.yaml +++ b/compliance/controls/azure/azure_securitycenter_automatic_provisioning_monitoring_agent_on.yaml @@ -1,14 +1,31 @@ +Description: To monitor for security vulnerabilities and threats, Azure Security Center collects data from your Azure virtual machines. Data is collected by the Log Analytics agent, formerly known as the Microsoft Monitoring Agent (MMA), which reads various security-related configurations and event logs from the machine and copies the data to your Log Analytics workspace for analysis. We recommend enabling auto provisioning to automatically deploy the agent to all supported Azure VMs and any new ones that are created. ID: azure_securitycenter_automatic_provisioning_monitoring_agent_on -Title: "Auto provisioning of the Log Analytics agent should be enabled on your subscription" -Description: "To monitor for security vulnerabilities and threats, Azure Security Center collects data from your Azure virtual machines. Data is collected by the Log Analytics agent, formerly known as the Microsoft Monitoring Agent (MMA), which reads various security-related configurations and event logs from the machine and copies the data to your Log Analytics workspace for analysis. We recommend enabling auto provisioning to automatically deploy the agent to all supported Azure VMs and any new ones that are created." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sc_prov.id as resource,\n sc_prov.og_account_id as og_account_id,\n sc_prov.og_resource_id as og_resource_id,\n case\n when auto_provision = 'On' then 'ok'\n else 'alarm'\n end as status,\n case\n when auto_provision = 'On' then 'Automatic provisioning of monitoring agent is on.'\n else 'Automatic provisioning of monitoring agent is off.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_auto_provisioning sc_prov\n right join azure_subscription sub on sc_prov.subscription_id = sub.subscription_id;\n" - PrimaryTable: azure_security_center_auto_provisioning ListOfTables: - azure_security_center_auto_provisioning - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_auto_provisioning + QueryToExecute: | + SELECT + sc_prov.id AS resource, + sc_prov.og_account_id AS og_account_id, + sc_prov.og_resource_id AS og_resource_id, + CASE + WHEN auto_provision = 'On' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN auto_provision = 'On' THEN 'Automatic provisioning of monitoring agent is on.' + ELSE 'Automatic provisioning of monitoring agent is off.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_auto_provisioning sc_prov + RIGHT JOIN azure_subscription sub ON sc_prov.subscription_id = sub.subscription_id; Severity: high Tags: category: @@ -29,5 +46,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Auto provisioning of the Log Analytics agent should be enabled on your subscription \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_appservice.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_appservice.yaml old mode 100755 new mode 100644 index 0499070af..7e5f6bf67 --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_appservice.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_appservice.yaml @@ -1,14 +1,33 @@ +Description: Azure Defender for App Service leverages the scale of the cloud, and the visibility that Azure has as a cloud provider, to monitor for common web app attacks. ID: azure_securitycenter_azure_defender_on_for_appservice -Title: "Azure Defender for App Service should be enabled" -Description: "Azure Defender for App Service leverages the scale of the cloud, and the visibility that Azure has as a cloud provider, to monitor for common web app attacks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for App Services.'\n else 'Azure Defender off for App Services.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'AppServices';\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for App Services.' + ELSE 'Azure Defender off for App Services.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'AppServices'; Severity: low Tags: category: @@ -29,5 +48,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Azure Defender for App Service should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_containerregistry.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_containerregistry.yaml old mode 100755 new mode 100644 index 686b5da09..cdb4da9a9 --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_containerregistry.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_containerregistry.yaml @@ -1,14 +1,36 @@ +Description: Azure Defender for container registries provides vulnerability scanning of any images pulled within the last 30 days, pushed to your registry, or imported, and exposes detailed findings per image. ID: azure_securitycenter_azure_defender_on_for_containerregistry -Title: "Azure Defender for container registries should be enabled" -Description: "Azure Defender for container registries provides vulnerability scanning of any images pulled within the last 30 days, pushed to your registry, or imported, and exposes detailed findings per image." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Container Registry.'\n else 'Azure Defender off for Container Registry.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'ContainerRegistry';\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Container Registry.' + ELSE 'Azure Defender off for Container Registry.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'ContainerRegistry'; Severity: low Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Azure Defender for container registries should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_containers.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_containers.yaml old mode 100755 new mode 100644 index a725c2285..3c302d708 --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_containers.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_containers.yaml @@ -1,32 +1,33 @@ +Description: Microsoft Defender for Containers provides hardening, vulnerability assessment and run-time protections for your Azure, hybrid, and multi-cloud Kubernetes environments. ID: azure_securitycenter_azure_defender_on_for_containers -Title: "Microsoft Defender for Containers should be enabled" -Description: "Microsoft Defender for Containers provides hardening, vulnerability assessment and run-time protections for your Azure, hybrid, and multi-cloud Kubernetes environments." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Containers.' - else 'Azure Defender off for Containers.' - end as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - name = 'Containers'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Containers.' + ELSE 'Azure Defender off for Containers.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'Containers'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Microsoft Defender for Containers should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_cosmosdb.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_cosmosdb.yaml old mode 100755 new mode 100644 index 106a08bdc..64e5d009a --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_cosmosdb.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_cosmosdb.yaml @@ -1,33 +1,34 @@ +Description: Microsoft Defender for Azure Cosmos DB scans all incoming network requests for threats to your Azure Cosmos DB resources. ID: azure_securitycenter_azure_defender_on_for_cosmosdb -Title: "Ensure That Microsoft Defender for Azure Cosmos DB is set to 'On'" -Description: "Microsoft Defender for Azure Cosmos DB scans all incoming network requests for threats to your Azure Cosmos DB resources." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when pricing_tier = 'Standard' then 'Azure Defender on for Cosmos DB.' - else 'Azure Defender off for Cosmos DB.' - end as reason - - , sub.display_name as subscription - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id - where - sub_pricing.title = 'CosmosDbs'; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Cosmos DB.' + ELSE 'Azure Defender off for Cosmos DB.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + sub_pricing.title = 'CosmosDbs'; Severity: high Tags: category: @@ -48,5 +49,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Ensure That Microsoft Defender for Azure Cosmos DB is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_database.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_database.yaml old mode 100755 new mode 100644 index 6e5e9dccd..1bb448983 --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_database.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_database.yaml @@ -1,14 +1,56 @@ +Description: Turning on Microsoft Defender for Databases enables threat detection for the instances running + your database software. This provides threat intelligence, anomaly detection, and behavior + analytics in the Azure Microsoft Defender for Cloud. Instead of being enabled on services + like Platform as a Service (PaaS), this implementation will run within your instances as + Infrastructure as a Service (IaaS) on the Operating Systems hosting your databases. ID: azure_securitycenter_azure_defender_on_for_database -Title: "Ensure That Microsoft Defender for Databases is set to 'On'" -Description: "Turning on Microsoft Defender for Databases enables threat detection for the instances running your database software. This provides threat intelligence, anomaly detection, and behavior analytics in the Azure Microsoft Defender for Cloud. Instead of being enabled on services like Platform as a Service (PaaS), this implementation will run within your instances as Infrastructure as a Service (IaaS) on the Operating Systems hosting your databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with defender_list as (\n select\n json_object_agg(name, pricing_tier) as data,\n subscription_id\n from\n azure_security_center_subscription_pricing\n where\n title = any(ARRAY ['CosmosDbs', 'OpenSourceRelationalDatabases', 'SqlServerVirtualMachines', 'SqlServers'])\n group by\n subscription_id\n)\nselect\n sub.id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when\n data ->> 'CosmosDbs' = 'Standard'\n and data ->> 'OpenSourceRelationalDatabases' = 'Standard'\n and data ->> 'SqlServerVirtualMachines' = 'Standard'\n and data ->> 'SqlServers' = 'Standard'\n then 'ok'\n else 'alarm'\n end as status,\n case\n when\n data ->> 'CosmosDbs' = 'Standard'\n and data ->> 'OpenSourceRelationalDatabases' = 'Standard'\n and data ->> 'SqlServerVirtualMachines' = 'Standard'\n and data ->> 'SqlServers' = 'Standard'\n then 'Azure Defender on for Databases.'\n else 'Azure Defender off for Databases.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription as sub\n left join defender_list as l on l.subscription_id = sub.subscription_id;\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + WITH defender_list AS ( + SELECT + JSON_OBJECT_AGG(name, pricing_tier) AS data, + subscription_id + FROM + azure_security_center_subscription_pricing + WHERE + title = ANY(ARRAY ['CosmosDbs', 'OpenSourceRelationalDatabases', 'SqlServerVirtualMachines', 'SqlServers']) + GROUP BY + subscription_id + ) + SELECT + sub.id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN + data ->> 'CosmosDbs' = 'Standard' + AND data ->> 'OpenSourceRelationalDatabases' = 'Standard' + AND data ->> 'SqlServerVirtualMachines' = 'Standard' + AND data ->> 'SqlServers' = 'Standard' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN + data ->> 'CosmosDbs' = 'Standard' + AND data ->> 'OpenSourceRelationalDatabases' = 'Standard' + AND data ->> 'SqlServerVirtualMachines' = 'Standard' + AND data ->> 'SqlServers' = 'Standard' + THEN 'Azure Defender on for Databases.' + ELSE 'Azure Defender off for Databases.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription AS sub + LEFT JOIN defender_list AS l ON l.subscription_id = sub.subscription_id; Severity: high Tags: category: @@ -29,5 +71,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Ensure That Microsoft Defender for Databases is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_dns.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_dns.yaml old mode 100755 new mode 100644 index f91922ef4..561c355ca --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_dns.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_dns.yaml @@ -1,14 +1,36 @@ +Description: Azure Defender for DNS provides an additional layer of protection for your cloud resources by continuously monitoring all DNS queries from your Azure resources. Azure Defender alerts you about suspicious activity at the DNS layer. ID: azure_securitycenter_azure_defender_on_for_dns -Title: "Azure Defender for DNS should be enabled" -Description: "Azure Defender for DNS provides an additional layer of protection for your cloud resources by continuously monitoring all DNS queries from your Azure resources. Azure Defender alerts you about suspicious activity at the DNS layer." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for DNS.'\n else 'Azure Defender off for DNS.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'Dns';\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for DNS.' + ELSE 'Azure Defender off for DNS.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'Dns'; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Azure Defender for DNS should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_k8s.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_k8s.yaml old mode 100755 new mode 100644 index 747128f0f..fc956efa9 --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_k8s.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_k8s.yaml @@ -3,7 +3,25 @@ Title: "Azure Defender for Kubernetes should be enabled" Description: "Azure Defender for Kubernetes provides real-time threat protection for containerized environments and generates alerts for suspicious activities." Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Kubernetes.'\n else 'Azure Defender off for Kubernetes.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'KubernetesService';\n" + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Kubernetes.' + ELSE 'Azure Defender off for Kubernetes.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'KubernetesService'; PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing @@ -30,4 +48,4 @@ Tags: service: - Azure/SecurityCenter IntegrationType: - - azure_subscription + - azure_subscription \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_keyvault.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_keyvault.yaml old mode 100755 new mode 100644 index a01de9d87..7a4fb6cd5 --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_keyvault.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_keyvault.yaml @@ -1,14 +1,33 @@ +Description: Azure Defender for Key Vault provides an additional layer of protection and security intelligence by detecting unusual and potentially harmful attempts to access or exploit key vault accounts. ID: azure_securitycenter_azure_defender_on_for_keyvault -Title: "Azure Defender for Key Vault should be enabled" -Description: "Azure Defender for Key Vault provides an additional layer of protection and security intelligence by detecting unusual and potentially harmful attempts to access or exploit key vault accounts." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Key Vaults.'\n else 'Azure Defender off for Key Vaults.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'KeyVaults';\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Key Vaults.' + ELSE 'Azure Defender off for Key Vaults.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'KeyVaults'; Severity: low Tags: category: @@ -29,5 +48,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Azure Defender for Key Vault should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_opensource_relational_db.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_opensource_relational_db.yaml old mode 100755 new mode 100644 index 87de371aa..8ebb871a3 --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_opensource_relational_db.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_opensource_relational_db.yaml @@ -1,14 +1,34 @@ +Description: Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_securitycenter_azure_defender_on_for_opensource_relational_db -Title: "Ensure That Microsoft Defender for Open-Source Relational Databases is set to 'On'" -Description: "Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Open Source Relational Databases.'\n else 'Azure Defender off for Open Source Relational Databases.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n sub_pricing.title = 'OpenSourceRelationalDatabases';\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Open Source Relational Databases.' + ELSE 'Azure Defender off for Open Source Relational Databases.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + sub_pricing.title = 'OpenSourceRelationalDatabases'; Severity: high Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Ensure That Microsoft Defender for Open-Source Relational Databases is set to 'On' \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_resource_manager.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_resource_manager.yaml old mode 100755 new mode 100644 index e26470287..837d64639 --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_resource_manager.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_resource_manager.yaml @@ -1,14 +1,34 @@ +Description: Azure Defender for Resource Manager automatically monitors the resource management operations in your organization. Azure Defender detects threats and alerts you about suspicious activity. ID: azure_securitycenter_azure_defender_on_for_resource_manager -Title: "Azure Defender for Resource Manager should be enabled" -Description: "Azure Defender for Resource Manager automatically monitors the resource management operations in your organization. Azure Defender detects threats and alerts you about suspicious activity." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Resource Manager.'\n else 'Azure Defender off for Resource Manager.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'Arm';\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Resource Manager.' + ELSE 'Azure Defender off for Resource Manager.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'Arm'; Severity: high Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Azure Defender for Resource Manager should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_server.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_server.yaml old mode 100755 new mode 100644 index 0ed7dbc93..4c5576c6e --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_server.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_server.yaml @@ -1,14 +1,33 @@ +Description: Azure Defender for servers provides real-time threat protection for server workloads and generates hardening recommendations as well as alerts about suspicious activities. ID: azure_securitycenter_azure_defender_on_for_server -Title: "Azure Defender for servers should be enabled" -Description: "Azure Defender for servers provides real-time threat protection for server workloads and generates hardening recommendations as well as alerts about suspicious activities." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Servers.'\n else 'Azure Defender off for Servers.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'VirtualMachines';\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Servers.' + ELSE 'Azure Defender off for Servers.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'VirtualMachines'; Severity: low Tags: category: @@ -29,5 +48,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Azure Defender for servers should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_sqldb.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_sqldb.yaml old mode 100755 new mode 100644 index d7ea4ca04..27343cc00 --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_sqldb.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_sqldb.yaml @@ -1,14 +1,34 @@ +Description: Azure Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, and discovering and classifying sensitive data. ID: azure_securitycenter_azure_defender_on_for_sqldb -Title: "Azure Defender for Azure SQL Database servers should be enabled" -Description: "Azure Defender for SQL provides functionality for surfacing and mitigating potential database vulnerabilities, detecting anomalous activities that could indicate threats to SQL databases, and discovering and classifying sensitive data." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for SQL database servers.'\n else 'Azure Defender off for SQL database servers.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'SqlServers';\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL database servers.' + ELSE 'Azure Defender off for SQL database servers.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServers'; Severity: low Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Azure Defender for Azure SQL Database servers should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_sqlservervm.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_sqlservervm.yaml old mode 100755 new mode 100644 index 67901e0af..dea9b2d7c --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_sqlservervm.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_sqlservervm.yaml @@ -1,14 +1,33 @@ +Description: Audit each SQL Managed Instance without advanced data security. ID: azure_securitycenter_azure_defender_on_for_sqlservervm -Title: "Azure Defender for SQL should be enabled for unprotected SQL Managed Instances" -Description: "Audit each SQL Managed Instance without advanced data security." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for SQL servers on machines.'\n else 'Azure Defender off for SQL servers on machines.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'SqlServerVirtualMachines';\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for SQL servers on machines.' + ELSE 'Azure Defender off for SQL servers on machines.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'SqlServerVirtualMachines'; Severity: low Tags: category: @@ -29,5 +48,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Azure Defender for SQL should be enabled for unprotected SQL Managed Instances \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_storage.yaml b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_storage.yaml old mode 100755 new mode 100644 index a619e822c..88932c5ba --- a/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_storage.yaml +++ b/compliance/controls/azure/azure_securitycenter_azure_defender_on_for_storage.yaml @@ -1,14 +1,33 @@ +Description: Azure Defender for Storage provides detections of unusual and potentially harmful attempts to access or exploit storage accounts. ID: azure_securitycenter_azure_defender_on_for_storage -Title: "Microsoft Defender for Storage (Classic) should be enabled" -Description: "Azure Defender for Storage provides detections of unusual and potentially harmful attempts to access or exploit storage accounts." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n sub_pricing.og_account_id as og_account_id,\n sub_pricing.og_resource_id as og_resource_id,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Storage.'\n else 'Azure Defender off for Storage.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'StorageAccounts';\n" - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Storage.' + ELSE 'Azure Defender off for Storage.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'StorageAccounts'; Severity: high Tags: category: @@ -29,5 +48,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Microsoft Defender for Storage (Classic) should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_container_image_scan_enabled.yaml b/compliance/controls/azure/azure_securitycenter_container_image_scan_enabled.yaml old mode 100755 new mode 100644 index 52f94a599..b439e397e --- a/compliance/controls/azure/azure_securitycenter_container_image_scan_enabled.yaml +++ b/compliance/controls/azure/azure_securitycenter_container_image_scan_enabled.yaml @@ -1,15 +1,31 @@ +Description: This control ensures that image scan for container registries are enabled. ID: azure_securitycenter_container_image_scan_enabled -Title: "Security Center container image scan should be enabled" -Description: "This control ensures that image scan for container registries are enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_assessment.id as resource,\n sub_assessment.og_account_id as og_account_id,\n sub_assessment.og_resource_id as og_resource_id,\n case\n when container_registry_vulnerability_properties ->> 'AssessedResourceType' = 'ContainerRegistryVulnerability' then 'ok'\n else 'alarm'\n end as status,\n case\n when container_registry_vulnerability_properties ->> 'AssessedResourceType' = 'ContainerRegistryVulnerability' then sub_assessment.name || ' container image scan enabled.'\n else sub_assessment.name || ' container image scan disabled.'\n end as reason \nfrom\n azure_security_center_sub_assessment sub_assessment\n right join azure_subscription sub on sub_assessment.subscription_id = sub.subscription_id;" - PrimaryTable: azure_security_center_sub_assessment ListOfTables: - azure_security_center_sub_assessment - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_sub_assessment + QueryToExecute: | + SELECT + sub_assessment.id AS resource, + sub_assessment.og_account_id AS og_account_id, + sub_assessment.og_resource_id AS og_resource_id, + CASE + WHEN container_registry_vulnerability_properties ->> 'AssessedResourceType' = 'ContainerRegistryVulnerability' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN container_registry_vulnerability_properties ->> 'AssessedResourceType' = 'ContainerRegistryVulnerability' THEN sub_assessment.name || ' container image scan enabled.' + ELSE sub_assessment.name || ' container image scan disabled.' + END AS reason + FROM + azure_security_center_sub_assessment sub_assessment + RIGHT JOIN azure_subscription sub + ON sub_assessment.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Security Center container image scan should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_email_configured.yaml b/compliance/controls/azure/azure_securitycenter_email_configured.yaml old mode 100755 new mode 100644 index c959c900e..efb29f411 --- a/compliance/controls/azure/azure_securitycenter_email_configured.yaml +++ b/compliance/controls/azure/azure_securitycenter_email_configured.yaml @@ -1,19 +1,49 @@ +Description: To ensure the relevant people in your organization are notified when there is a potential security breach in one of your subscriptions, set a security contact to receive email notifications from Security Center. ID: azure_securitycenter_email_configured -Title: "Subscriptions should have a contact email address for security issues" -Description: "To ensure the relevant people in your organization are notified when there is a potential security breach in one of your subscriptions, set a security contact to receive email notifications from Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with contact_info as (\n select\n jsonb_agg(email) filter (where name = 'default' and email != '') as default_email,\n count(*) filter (where name != 'default') as non_default_count,\n count(*) filter (where name = 'default') as default_count,\n subscription_id\n from\n azure_security_center_contact\n group by\n subscription_id\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when non_default_count > 0 then 'ok'\n when default_count = 1 and jsonb_array_length(default_email) != 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when non_default_count > 0 then 'Additional email addresses configured.'\n when default_count = 1 and default_email is not null then'Additional email addresses configured.'\n else 'Additional email addresses not configured.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join contact_info ci on sub.subscription_id = ci.subscription_id;\n" - PrimaryTable: azure_security_center_contact ListOfTables: - azure_security_center_contact - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_contact + QueryToExecute: | + WITH contact_info AS ( + SELECT + jsonb_agg(email) FILTER (WHERE name = 'default' AND email != '') AS default_email, + COUNT(*) FILTER (WHERE name != 'default') AS non_default_count, + COUNT(*) FILTER (WHERE name = 'default') AS default_count, + subscription_id + FROM + azure_security_center_contact + GROUP BY + subscription_id + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN non_default_count > 0 THEN 'ok' + WHEN default_count = 1 AND jsonb_array_length(default_email) != 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN non_default_count > 0 THEN 'Additional email addresses configured.' + WHEN default_count = 1 AND default_email IS NOT NULL THEN 'Additional email addresses configured.' + ELSE 'Additional email addresses not configured.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Subscriptions should have a contact email address for security issues \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_mcas_integration.yaml b/compliance/controls/azure/azure_securitycenter_mcas_integration.yaml old mode 100755 new mode 100644 index ed12e76cc..92a121afa --- a/compliance/controls/azure/azure_securitycenter_mcas_integration.yaml +++ b/compliance/controls/azure/azure_securitycenter_mcas_integration.yaml @@ -1,14 +1,36 @@ +Description: This setting enables Microsoft Defender for Cloud Apps (MCAS) integration with Microsoft Defender for Cloud. ID: azure_securitycenter_mcas_integration -Title: "Ensure that Microsoft Defender for Cloud Apps (MCAS) Integration with Microsoft Defender for Cloud is selected" -Description: "This setting enables Microsoft Defender for Cloud Apps (MCAS) integration with Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sc_sett.id as resource,\n sc_sett.og_account_id as og_account_id,\n sc_sett.og_resource_id as og_resource_id,\n case\n when enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when enabled then 'Windows Defender ATP (WDATP) integrated with Security Center.'\n else 'Windows Defender ATP (WDATP) not integrated with Security Center.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_setting sc_sett\n right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id\nwhere\n name = 'MCAS';\n" - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Windows Defender ATP (WDATP) integrated with Security Center.' + ELSE 'Windows Defender ATP (WDATP) not integrated with Security Center.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_setting sc_sett + RIGHT JOIN + azure_subscription sub + ON + sc_sett.subscription_id = sub.subscription_id + WHERE + name = 'MCAS'; Severity: high Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Ensure that Microsoft Defender for Cloud Apps (MCAS) Integration with Microsoft Defender for Cloud is selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_notify_alerts_configured.yaml b/compliance/controls/azure/azure_securitycenter_notify_alerts_configured.yaml old mode 100755 new mode 100644 index 2ef87bbaa..bb45e2199 --- a/compliance/controls/azure/azure_securitycenter_notify_alerts_configured.yaml +++ b/compliance/controls/azure/azure_securitycenter_notify_alerts_configured.yaml @@ -1,14 +1,41 @@ +Description: To ensure the relevant people in your organization are notified when there is a potential security breach in one of your subscriptions, enable email notifications for high severity alerts in Security Center. ID: azure_securitycenter_notify_alerts_configured -Title: "Email notification for high severity alerts should be enabled" -Description: "To ensure the relevant people in your organization are notified when there is a potential security breach in one of your subscriptions, enable email notifications for high severity alerts in Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with contact_info as (\n select\n count(*) filter (where alert_notifications = 'On') as notification_alert_count,\n subscription_id\n from\n azure_security_center_contact\n group by\n subscription_id\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when notification_alert_count > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when notification_alert_count > 0 then '\"Notify about alerts with the following severity\" set to High.'\n else '\"Notify about alerts with the following severity\" not set to High.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join contact_info ci on sub.subscription_id = ci.subscription_id;\n" - PrimaryTable: azure_security_center_contact ListOfTables: - azure_security_center_contact - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_contact + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alert_notifications = 'On') AS notification_alert_count, + subscription_id + FROM + azure_security_center_contact + GROUP BY + subscription_id + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN notification_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN notification_alert_count > 0 THEN '"Notify about alerts with the following severity" set to High.' + ELSE '"Notify about alerts with the following severity" not set to High.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN contact_info ci ON sub.subscription_id = ci.subscription_id; Severity: low Tags: category: @@ -29,5 +56,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Email notification for high severity alerts should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_pricing_standard.yaml b/compliance/controls/azure/azure_securitycenter_pricing_standard.yaml old mode 100755 new mode 100644 index 0c920d0b5..d86d927ad --- a/compliance/controls/azure/azure_securitycenter_pricing_standard.yaml +++ b/compliance/controls/azure/azure_securitycenter_pricing_standard.yaml @@ -1,27 +1,28 @@ +Description: This control checks whether Security center pricing is set to standard. This control is non-compliant if pricing is set to free. ID: azure_securitycenter_pricing_standard -Title: "Security center pricing should be set to standard" -Description: "This control checks whether Security center pricing is set to standard. This control is non-compliant if pricing is set to free." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sub_pricing.id as resource, - sub_pricing.og_account_id as og_account_id, - sub_pricing.og_resource_id as og_resource_id, - case - when pricing_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - sub_pricing.name || ' is using ' || pricing_tier || ' pricing tier.' as reason - from - azure_security_center_subscription_pricing sub_pricing - right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id; - PrimaryTable: azure_security_center_subscription_pricing ListOfTables: - azure_security_center_subscription_pricing - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_subscription_pricing + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + sub_pricing.og_account_id AS og_account_id, + sub_pricing.og_resource_id AS og_resource_id, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + sub_pricing.name || ' is using ' || pricing_tier || ' pricing tier.' AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Security center pricing should be set to standard \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_security_alerts_to_owner_enabled.yaml b/compliance/controls/azure/azure_securitycenter_security_alerts_to_owner_enabled.yaml old mode 100755 new mode 100644 index 521633718..cfc3358d2 --- a/compliance/controls/azure/azure_securitycenter_security_alerts_to_owner_enabled.yaml +++ b/compliance/controls/azure/azure_securitycenter_security_alerts_to_owner_enabled.yaml @@ -1,14 +1,42 @@ +Description: To ensure your subscription owners are notified when there is a potential security breach in their subscription, set email notifications to subscription owners for high severity alerts in Security Center. ID: azure_securitycenter_security_alerts_to_owner_enabled -Title: "Email notification to subscription owner for high severity alerts should be enabled" -Description: "To ensure your subscription owners are notified when there is a potential security breach in their subscription, set email notifications to subscription owners for high severity alerts in Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with contact_info as (\n select\n count(*) filter (where alerts_to_admins = 'On') as admin_alert_count,\n subscription_id\n from\n azure_security_center_contact\n group by\n subscription_id\n limit 1\n)\nselect\n sub.subscription_id as resource,\n sub.og_account_id as og_account_id,\n sub.og_resource_id as og_resource_id,\n case\n when admin_alert_count > 0 then 'ok'\n else 'alarm'\n end as status,\n case\n when admin_alert_count > 0 then '\"All users with the following roles\" set to Owner'\n else '\"All users with the following roles\" not set to Owner.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_subscription sub\n left join contact_info ci on sub.subscription_id = ci.subscription_id;\n" - PrimaryTable: azure_security_center_contact ListOfTables: - azure_security_center_contact - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_contact + QueryToExecute: | + WITH contact_info AS ( + SELECT + COUNT(*) FILTER (WHERE alerts_to_admins = 'On') AS admin_alert_count, + subscription_id + FROM + azure_security_center_contact + GROUP BY + subscription_id + LIMIT 1 + ) + SELECT + sub.subscription_id AS resource, + sub.og_account_id AS og_account_id, + sub.og_resource_id AS og_resource_id, + CASE + WHEN admin_alert_count > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN admin_alert_count > 0 THEN '"All users with the following roles" set to Owner' + ELSE '"All users with the following roles" not set to Owner.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription sub + LEFT JOIN contact_info ci + ON sub.subscription_id = ci.subscription_id; Severity: medium Tags: category: @@ -29,5 +57,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Email notification to subscription owner for high severity alerts should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_securitycenter_wdatp_integration.yaml b/compliance/controls/azure/azure_securitycenter_wdatp_integration.yaml old mode 100755 new mode 100644 index dc94df211..c69d35d60 --- a/compliance/controls/azure/azure_securitycenter_wdatp_integration.yaml +++ b/compliance/controls/azure/azure_securitycenter_wdatp_integration.yaml @@ -1,14 +1,34 @@ +Description: This setting enables Windows Defender ATP (WDATP) integration with Security Center. ID: azure_securitycenter_wdatp_integration -Title: "Ensure that Windows Defender ATP (WDATP) integration with Security Center is selected" -Description: "This setting enables Windows Defender ATP (WDATP) integration with Security Center." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sc_sett.id as resource,\n sc_sett.og_account_id as og_account_id,\n sc_sett.og_resource_id as og_resource_id,\n case\n when enabled then 'ok'\n else 'alarm'\n end as status,\n case\n when enabled then 'Microsoft Cloud App Security (MCAS) integrated with Security Center.'\n else 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.'\n end as reason\n \n , sub.display_name as subscription\nfrom\n azure_security_center_setting sc_sett\n right join azure_subscription sub on sc_sett.subscription_id = sub.subscription_id\nwhere\n sc_sett.title = 'WDATP';\n" - PrimaryTable: azure_security_center_setting ListOfTables: - azure_security_center_setting - azure_subscription Parameters: [] + PrimaryTable: azure_security_center_setting + QueryToExecute: | + SELECT + sc_sett.id AS resource, + sc_sett.og_account_id AS og_account_id, + sc_sett.og_resource_id AS og_resource_id, + CASE + WHEN enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled THEN 'Microsoft Cloud App Security (MCAS) integrated with Security Center.' + ELSE 'Microsoft Cloud App Security (MCAS) not integrated with Security Center.' + END AS reason, + sub.display_name AS subscription + FROM + azure_security_center_setting sc_sett + RIGHT JOIN azure_subscription sub + ON sc_sett.subscription_id = sub.subscription_id + WHERE + sc_sett.title = 'WDATP'; Severity: high Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/SecurityCenter -IntegrationType: - - azure_subscription +Title: Ensure that Windows Defender ATP (WDATP) integration with Security Center is selected \ No newline at end of file diff --git a/compliance/controls/azure/azure_servicebus_name_space_private_link_used.yaml b/compliance/controls/azure/azure_servicebus_name_space_private_link_used.yaml old mode 100755 new mode 100644 index 13a0a1bfc..3222aa6ad --- a/compliance/controls/azure/azure_servicebus_name_space_private_link_used.yaml +++ b/compliance/controls/azure/azure_servicebus_name_space_private_link_used.yaml @@ -1,19 +1,40 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Service Bus namespaces, data leakage risks are reduced. ID: azure_servicebus_name_space_private_link_used -Title: "Azure Service Bus namespaces should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Service Bus namespaces, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when sku_name in ('Basic', 'Standard') then 'skip'\n when private_endpoint_connections is null then 'info'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then 'ok'\n else 'alarm'\n end as status,\n case\n when sku_name in ('Basic', 'Standard') then a.name || ' is of ' || sku_name || ' tier.'\n when private_endpoint_connections is null then a.name || ' no private link exists.'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb\n then a.name || ' using private link.'\n else a.name || ' not using private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_servicebus_namespace a,\n azure_subscription sub;\n" - PrimaryTable: azure_servicebus_namespace ListOfTables: - azure_servicebus_namespace - azure_subscription Parameters: [] + PrimaryTable: azure_servicebus_namespace + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_name IN ('Basic', 'Standard') THEN 'skip' + WHEN private_endpoint_connections IS NULL THEN 'info' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_name IN ('Basic', 'Standard') THEN a.name || ' is of ' || sku_name || ' tier.' + WHEN private_endpoint_connections IS NULL THEN a.name || ' no private link exists.' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN a.name || ' using private link.' + ELSE a.name || ' not using private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_servicebus_namespace a, + azure_subscription sub; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/ServiceBus -IntegrationType: - - azure_subscription +Title: Azure Service Bus namespaces should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_servicebus_namespace_azure_ad_authentication_enabled.yaml b/compliance/controls/azure/azure_servicebus_namespace_azure_ad_authentication_enabled.yaml old mode 100755 new mode 100644 index 80c48276b..96c147363 --- a/compliance/controls/azure/azure_servicebus_namespace_azure_ad_authentication_enabled.yaml +++ b/compliance/controls/azure/azure_servicebus_namespace_azure_ad_authentication_enabled.yaml @@ -1,32 +1,32 @@ +Description: This policy identifies Service bus namespaces that are not configured with Azure Active Directory (Azure AD) authentication and are enabled with local authentication. Azure AD provides superior security and ease of use over shared access signatures (SAS). With Azure AD, there's no need to store the tokens in your code and risk potential security vulnerabilities. It is recommended to configure the Service bus namespaces with Azure AD authentication so that all actions are strongly authenticated. ID: azure_servicebus_namespace_azure_ad_authentication_enabled -Title: "Service bus namespace should be configured with Azure Active Directory (Azure AD) authentication" -Description: "This policy identifies Service bus namespaces that are not configured with Azure Active Directory (Azure AD) authentication and are enabled with local authentication. Azure AD provides superior security and ease of use over shared access signatures (SAS). With Azure AD, there's no need to store the tokens in your code and risk potential security vulnerabilities. It is recommended to configure the Service bus namespaces with Azure AD authentication so that all actions are strongly authenticated." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when status = 'Active' - and not disable_local_auth then 'alarm' - else 'ok' - end as status, - case - when status = 'Active' - and not disable_local_auth then a.name || ' namespace not configured with Azure AD authentication.' - else a.name || ' namespace configured with Azure AD authentication.' - end as reason - from - azure_servicebus_namespace a, - azure_subscription sub; - PrimaryTable: azure_servicebus_namespace ListOfTables: - azure_servicebus_namespace - azure_subscription Parameters: [] + PrimaryTable: azure_servicebus_namespace + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN status = 'Active' + AND NOT disable_local_auth THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status = 'Active' + AND NOT disable_local_auth THEN a.name || ' namespace not configured with Azure AD authentication.' + ELSE a.name || ' namespace configured with Azure AD authentication.' + END AS reason + FROM + azure_servicebus_namespace a, + azure_subscription sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Service bus namespace should be configured with Azure Active Directory (Azure AD) authentication \ No newline at end of file diff --git a/compliance/controls/azure/azure_servicebus_namespace_logging_enabled.yaml b/compliance/controls/azure/azure_servicebus_namespace_logging_enabled.yaml old mode 100755 new mode 100644 index 4c548cb21..7e0d82f5a --- a/compliance/controls/azure/azure_servicebus_namespace_logging_enabled.yaml +++ b/compliance/controls/azure/azure_servicebus_namespace_logging_enabled.yaml @@ -1,14 +1,62 @@ +Description: Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised. ID: azure_servicebus_namespace_logging_enabled -Title: "Resource logs in Service Bus should be enabled" -Description: "Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n distinct name as namespace_name\n from\n azure_servicebus_namespace,\n jsonb_array_elements(diagnostic_settings) setting,\n jsonb_array_elements(setting -> 'properties' -> 'logs') log\n where\n diagnostic_settings is not null\n and (\n (\n (log ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy' ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy') :: JSONB ? 'days'\n )\n or\n (\n (log ->> 'enabled') :: boolean\n and (\n log -> 'retentionPolicy' ->> 'enabled' <> 'true'\n or setting -> 'properties' ->> 'storageAccountId' = ''\n )\n )\n )\n)\nselect\n v.id as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when v.diagnostic_settings is null then 'alarm'\n when l.namespace_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when v.diagnostic_settings is null then v.name || ' logging not enabled.'\n when l.namespace_name is null then v.name || ' logging not enabled.'\n else v.name || ' logging enabled.'\n end as reason\n \n , v.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_servicebus_namespace as v\n left join logging_details as l on v.name = l.namespace_name,\n azure_subscription as sub\nwhere\n sub.subscription_id = v.subscription_id;\n" - PrimaryTable: azure_servicebus_namespace ListOfTables: - azure_servicebus_namespace - azure_subscription Parameters: [] + PrimaryTable: azure_servicebus_namespace + QueryToExecute: | + WITH logging_details AS ( + SELECT + DISTINCT name AS namespace_name + FROM + azure_servicebus_namespace, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND ( + ( + (log ->> 'enabled') :: BOOLEAN + AND (log -> 'retentionPolicy' ->> 'enabled') :: BOOLEAN + AND (log -> 'retentionPolicy') :: JSONB ? 'days' + ) + OR + ( + (log ->> 'enabled') :: BOOLEAN + AND ( + log -> 'retentionPolicy' ->> 'enabled' <> 'true' + OR setting -> 'properties' ->> 'storageAccountId' = '' + ) + ) + ) + ) + SELECT + v.id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.namespace_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.namespace_name IS NULL THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_servicebus_namespace AS v + LEFT JOIN logging_details AS l ON v.name = l.namespace_name, + azure_subscription AS sub + WHERE + sub.subscription_id = v.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +65,4 @@ Tags: - "true" service: - Azure/ServiceBus -IntegrationType: - - azure_subscription +Title: Resource logs in Service Bus should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_servicebus_namespace_no_overly_permissive_network_access.yaml b/compliance/controls/azure/azure_servicebus_namespace_no_overly_permissive_network_access.yaml old mode 100755 new mode 100644 index 940ae6120..30ba47dd9 --- a/compliance/controls/azure/azure_servicebus_namespace_no_overly_permissive_network_access.yaml +++ b/compliance/controls/azure/azure_servicebus_namespace_no_overly_permissive_network_access.yaml @@ -1,36 +1,38 @@ +Description: This policy identifies Azure Service bus namespaces configured with overly permissive network access. By default, Service Bus namespaces are accessible from the internet as long as the request comes with valid authentication and authorization. With an IP firewall, you can restrict it further to only a set of IPv4 addresses or IPv4 address ranges. With Virtual Networks, the network traffic path is secured on both ends. It is recommended to configure the Service bus namespace with an IP firewall or by Virtual Network; so that the Service bus namespace is accessible only to restricted entities. ID: azure_servicebus_namespace_no_overly_permissive_network_access -Title: "Service bus namespace should not be configured with overly permissive network access" -Description: "This policy identifies Azure Service bus namespaces configured with overly permissive network access. By default, Service Bus namespaces are accessible from the internet as long as the request comes with valid authentication and authorization. With an IP firewall, you can restrict it further to only a set of IPv4 addresses or IPv4 address ranges. With Virtual Networks, the network traffic path is secured on both ends. It is recommended to configure the Service bus namespace with an IP firewall or by Virtual Network; so that the Service bus namespace is accessible only to restricted entities." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when status = 'Active' - and sku_tier = 'Premium' - and network_rule_set -> 'properties' ->> 'defaultAction' = 'Allow' - and network_rule_set -> 'properties' ->> 'publicNetworkAccess' = 'Enabled' then 'alarm' - else 'ok' - end as status, - case - when status = 'Active' - and sku_tier = 'Premium' - and network_rule_set -> 'properties' ->> 'defaultAction' = 'Allow' - and network_rule_set -> 'properties' ->> 'publicNetworkAccess' = 'Enabled' then a.name || ' namespace configured with overly permissive network access.' - else a.name || ' namespace not configured with overly permissive network access.' - end as reason - from - azure_servicebus_namespace a, - azure_subscription sub; - PrimaryTable: azure_servicebus_namespace ListOfTables: - azure_servicebus_namespace - azure_subscription Parameters: [] + PrimaryTable: azure_servicebus_namespace + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN status = 'Active' + AND sku_tier = 'Premium' + AND network_rule_set -> 'properties' ->> 'defaultAction' = 'Allow' + AND network_rule_set -> 'properties' ->> 'publicNetworkAccess' = 'Enabled' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status = 'Active' + AND sku_tier = 'Premium' + AND network_rule_set -> 'properties' ->> 'defaultAction' = 'Allow' + AND network_rule_set -> 'properties' ->> 'publicNetworkAccess' = 'Enabled' + THEN a.name || ' namespace configured with overly permissive network access.' + ELSE a.name || ' namespace not configured with overly permissive network access.' + END AS reason + FROM + azure_servicebus_namespace a, + azure_subscription sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Service bus namespace should not be configured with overly permissive network access \ No newline at end of file diff --git a/compliance/controls/azure/azure_servicebus_premium_namespace_cmk_encrypted.yaml b/compliance/controls/azure/azure_servicebus_premium_namespace_cmk_encrypted.yaml old mode 100755 new mode 100644 index b0e6f1eaa..5aa54a0a9 --- a/compliance/controls/azure/azure_servicebus_premium_namespace_cmk_encrypted.yaml +++ b/compliance/controls/azure/azure_servicebus_premium_namespace_cmk_encrypted.yaml @@ -1,19 +1,38 @@ +Description: Azure Service Bus supports the option of encrypting data at rest with either Microsoft-managed keys (default) or customer-managed keys. Choosing to encrypt data using customer-managed keys enables you to assign, rotate, disable, and revoke access to the keys that Service Bus will use to encrypt data in your namespace. Note that Service Bus only supports encryption with customer-managed keys for premium namespaces. ID: azure_servicebus_premium_namespace_cmk_encrypted -Title: "Service Bus Premium namespaces should use a customer-managed key for encryption" -Description: "Azure Service Bus supports the option of encrypting data at rest with either Microsoft-managed keys (default) or customer-managed keys. Choosing to encrypt data using customer-managed keys enables you to assign, rotate, disable, and revoke access to the keys that Service Bus will use to encrypt data in your namespace. Note that Service Bus only supports encryption with customer-managed keys for premium namespaces." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when sku_tier <> 'Premium' then 'skip'\n when encryption -> 'keySource' = '\"Microsoft.KeyVault\"' then 'ok'\n else 'alarm'\n end as status,\n case\n when sku_tier <> 'Premium' then a.name || ' is of ' || sku_tier || ' tier.'\n when encryption -> 'keySource' = '\"Microsoft.KeyVault\"' then a.name || ' encrypted using CMK.'\n else a.name || ' not encrypted using CMK.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_servicebus_namespace a,\n azure_subscription sub;\n" - PrimaryTable: azure_servicebus_namespace ListOfTables: - azure_servicebus_namespace - azure_subscription Parameters: [] + PrimaryTable: azure_servicebus_namespace + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_tier <> 'Premium' THEN 'skip' + WHEN encryption -> 'keySource' = '"Microsoft.KeyVault"' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_tier <> 'Premium' THEN a.name || ' is of ' || sku_tier || ' tier.' + WHEN encryption -> 'keySource' = '"Microsoft.KeyVault"' THEN a.name || ' encrypted using CMK.' + ELSE a.name || ' not encrypted using CMK.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_servicebus_namespace a, + azure_subscription sub; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/ServiceBus -IntegrationType: - - azure_subscription +Title: Service Bus Premium namespaces should use a customer-managed key for encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_servicebus_use_virtual_service_endpoint.yaml b/compliance/controls/azure/azure_servicebus_use_virtual_service_endpoint.yaml old mode 100755 new mode 100644 index 0eac25748..bda8adff0 --- a/compliance/controls/azure/azure_servicebus_use_virtual_service_endpoint.yaml +++ b/compliance/controls/azure/azure_servicebus_use_virtual_service_endpoint.yaml @@ -1,54 +1,54 @@ +Description: Ensure that Service Bus uses virtual service endpoint. This control is non-compliant if service bus does not use a virtual service endpoint. ID: azure_servicebus_use_virtual_service_endpoint -Title: "Service Bus should use virtual service endpoint" -Description: "Ensure that Service Bus uses virtual service endpoint. This contol is non-compliant if service bus does not uses virtual service endpoint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with service_bus as ( - select + ListOfTables: + - azure_servicebus_namespace + - azure_subscription + Parameters: [] + PrimaryTable: azure_servicebus_namespace + QueryToExecute: | + WITH service_bus AS ( + SELECT name, region, - network_rule_set -> 'properties' -> 'virtualNetworkRules' as virtual_network_rules - from + network_rule_set -> 'properties' -> 'virtualNetworkRules' AS virtual_network_rules + FROM azure_servicebus_namespace - where + WHERE sku_tier = 'Premium' - and ( + AND ( jsonb_array_length(network_rule_set -> 'properties' -> 'virtualNetworkRules') = 0 - or exists ( - select + OR EXISTS ( + SELECT * - from - jsonb_array_elements(network_rule_set -> 'properties' -> 'virtualNetworkRules') as t - where - t -> 'subnet' ->> 'id' is null + FROM + jsonb_array_elements(network_rule_set -> 'properties' -> 'virtualNetworkRules') AS t + WHERE + t -> 'subnet' ->> 'id' IS NULL ) ) ) - select - bus.id as resource, - bus.og_account_id as og_account_id, - bus.og_resource_id as og_resource_id, - case - when bus.name != service_bus.name then 'ok' - else 'alarm' - end as status, - case - when bus.name != service_bus.name then bus.name || ' configured with virtual service endpoint.' - else bus.name || ' not configured with virtual service endpoint.' - end as reason - from - azure_servicebus_namespace as bus, - azure_subscription as sub - left join service_bus on true - where + SELECT + bus.id AS resource, + bus.og_account_id AS og_account_id, + bus.og_resource_id AS og_resource_id, + CASE + WHEN bus.name != service_bus.name THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bus.name != service_bus.name THEN bus.name || ' configured with virtual service endpoint.' + ELSE bus.name || ' not configured with virtual service endpoint.' + END AS reason + FROM + azure_servicebus_namespace AS bus, + azure_subscription AS sub + LEFT JOIN service_bus ON TRUE + WHERE sub.subscription_id = bus.subscription_id; - PrimaryTable: azure_servicebus_namespace - ListOfTables: - - azure_servicebus_namespace - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Service Bus should use virtual service endpoint \ No newline at end of file diff --git a/compliance/controls/azure/azure_servicefabric_cluster_active_directory_authentication_enabled.yaml b/compliance/controls/azure/azure_servicefabric_cluster_active_directory_authentication_enabled.yaml old mode 100755 new mode 100644 index 6233774cd..648b68924 --- a/compliance/controls/azure/azure_servicefabric_cluster_active_directory_authentication_enabled.yaml +++ b/compliance/controls/azure/azure_servicefabric_cluster_active_directory_authentication_enabled.yaml @@ -1,20 +1,37 @@ +Description: Audit usage of client authentication only via Azure Active Directory in Service Fabric. ID: azure_servicefabric_cluster_active_directory_authentication_enabled -Title: "Service Fabric clusters should only use Azure Active Directory for client authentication" -Description: "Audit usage of client authentication only via Azure Active Directory in Service Fabric." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when azure_active_directory is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when azure_active_directory is not null then a.name || ' using Azure Active Directory for client authentication.'\n else a.name || ' not using Azure Active Directory for client authentication.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_service_fabric_cluster a,\n azure_subscription sub;\n" - PrimaryTable: azure_service_fabric_cluster ListOfTables: - azure_active_directory - azure_service_fabric_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_service_fabric_cluster + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN azure_active_directory IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN azure_active_directory IS NOT NULL THEN a.name || ' using Azure Active Directory for client authentication.' + ELSE a.name || ' not using Azure Active Directory for client authentication.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_service_fabric_cluster a, + azure_subscription sub; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/ServiceFabric -IntegrationType: - - azure_subscription +Title: Service Fabric clusters should only use Azure Active Directory for client authentication \ No newline at end of file diff --git a/compliance/controls/azure/azure_servicefabric_cluster_protection_level_as_encrypt_and_sign.yaml b/compliance/controls/azure/azure_servicefabric_cluster_protection_level_as_encrypt_and_sign.yaml old mode 100755 new mode 100644 index 565cf9171..846c9fe31 --- a/compliance/controls/azure/azure_servicefabric_cluster_protection_level_as_encrypt_and_sign.yaml +++ b/compliance/controls/azure/azure_servicefabric_cluster_protection_level_as_encrypt_and_sign.yaml @@ -1,14 +1,32 @@ +Description: Service Fabric provides three levels of protection (None, Sign and EncryptAndSign) for node-to-node communication using a primary cluster certificate. Set the protection level to ensure that all node-to-node messages are encrypted and digitally signed. ID: azure_servicefabric_cluster_protection_level_as_encrypt_and_sign -Title: "Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign" -Description: "Service Fabric provides three levels of protection (None, Sign and EncryptAndSign) for node-to-node communication using a primary cluster certificate. Set the protection level to ensure that all node-to-node messages are encrypted and digitally signed." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when fabric_settings @> '[{\"parameters\":[{\"value\": \"EncryptAndSign\"}]}]'::jsonb then 'ok'\n else 'alarm'\n end as status,\n case\n when fabric_settings @> '[{\"parameters\":[{\"value\": \"EncryptAndSign\"}]}]'::jsonb then a.name || ' ClusterProtectionLevel property set to EncryptAndSign.'\n else a.name || ' ClusterProtectionLevel property not set to EncryptAndSign.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_service_fabric_cluster a,\n azure_subscription sub;\n" - PrimaryTable: azure_service_fabric_cluster ListOfTables: - azure_service_fabric_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_service_fabric_cluster + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN fabric_settings @> '[{"parameters":[{"value": "EncryptAndSign"}]}]'::jsonb THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN fabric_settings @> '[{"parameters":[{"value": "EncryptAndSign"}]}]'::jsonb THEN a.name || ' ClusterProtectionLevel property set to EncryptAndSign.' + ELSE a.name || ' ClusterProtectionLevel property not set to EncryptAndSign.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_service_fabric_cluster a, + azure_subscription sub; Severity: high Tags: nist_sp_800_53_rev_5: @@ -17,5 +35,4 @@ Tags: - "true" service: - Azure/ServiceFabric -IntegrationType: - - azure_subscription +Title: Service Fabric clusters should have the ClusterProtectionLevel property set to EncryptAndSign \ No newline at end of file diff --git a/compliance/controls/azure/azure_signalr_service_no_free_tier_sku.yaml b/compliance/controls/azure/azure_signalr_service_no_free_tier_sku.yaml old mode 100755 new mode 100644 index d70955f79..c72aea438 --- a/compliance/controls/azure/azure_signalr_service_no_free_tier_sku.yaml +++ b/compliance/controls/azure/azure_signalr_service_no_free_tier_sku.yaml @@ -1,29 +1,29 @@ +Description: This control checks whether SignalR service uses paid SKU for its SLA. ID: azure_signalr_service_no_free_tier_sku -Title: "SignalR Service should not use free tier SKU" -Description: "This control checks whether SignalR service uses paid SKU for its SLA." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - a.id as resource, - a.og_account_id as og_account_id, - a.og_resource_id as og_resource_id, - case - when sku ->> 'tier' = 'Free' then 'alarm' - else 'ok' - end as status, - a.name || ' is of ' || (sku ->>'tier' )|| ' tier.' as reason - from - azure_signalr_service as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_signalr_service ListOfTables: - azure_signalr_service - azure_subscription Parameters: [] + PrimaryTable: azure_signalr_service + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku ->> 'tier' = 'Free' THEN 'alarm' + ELSE 'ok' + END AS status, + a.name || ' is of ' || (sku ->> 'tier') || ' tier.' AS reason + FROM + azure_signalr_service AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: SignalR Service should not use free tier SKU \ No newline at end of file diff --git a/compliance/controls/azure/azure_signalr_service_private_link_used.yaml b/compliance/controls/azure/azure_signalr_service_private_link_used.yaml old mode 100755 new mode 100644 index 836db751a..79ac190b8 --- a/compliance/controls/azure/azure_signalr_service_private_link_used.yaml +++ b/compliance/controls/azure/azure_signalr_service_private_link_used.yaml @@ -1,19 +1,50 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Azure SignalR Service resource instead of the entire service, you'll reduce your data leakage risks. ID: azure_signalr_service_private_link_used -Title: "Azure SignalR Service should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Azure SignalR Service resource instead of the entire service, you'll reduce your data leakage risks." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with signalr_service_connection as (\n select\n distinct a.id\n from\n azure_signalr_service as a,\n jsonb_array_elements(private_endpoint_connections) as connection\n where\n connection -> 'PrivateLinkServiceConnectionState' ->> 'status' = 'Approved'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when sku ->> 'tier' = 'Free' then 'skip'\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when sku ->>'tier' = 'Free' then a.name || ' is of ' || (sku ->>'tier' )|| ' tier.'\n when c.id is null then a.name || ' not uses private link.'\n else a.name || ' uses private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_signalr_service as a\n left join signalr_service_connection as c on c.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_signalr_service ListOfTables: - azure_signalr_service - azure_subscription Parameters: [] + PrimaryTable: azure_signalr_service + QueryToExecute: | + WITH signalr_service_connection AS ( + SELECT DISTINCT + a.id + FROM + azure_signalr_service AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'PrivateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku ->> 'tier' = 'Free' THEN 'skip' + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sku ->> 'tier' = 'Free' THEN a.name || ' is of ' || (sku ->> 'tier') || ' tier.' + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_signalr_service AS a + LEFT JOIN signalr_service_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SignalRService -IntegrationType: - - azure_subscription +Title: Azure SignalR Service should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_spring_cloud_service_network_injection_enabled.yaml b/compliance/controls/azure/azure_spring_cloud_service_network_injection_enabled.yaml old mode 100755 new mode 100644 index 6f8a3a571..e3d8f4f3b --- a/compliance/controls/azure/azure_spring_cloud_service_network_injection_enabled.yaml +++ b/compliance/controls/azure/azure_spring_cloud_service_network_injection_enabled.yaml @@ -1,19 +1,40 @@ +Description: 'Azure Spring Cloud instances should use virtual network injection for the following purposes: 1. Isolate Azure Spring Cloud from Internet. 2. Enable Azure Spring Cloud to interact with systems in either on premises data centers or Azure service in other virtual networks. 3. Empower customers to control inbound and outbound network communications for Azure Spring Cloud.' ID: azure_spring_cloud_service_network_injection_enabled -Title: "Azure Spring Cloud should use network injection" -Description: "Azure Spring Cloud instances should use virtual network injection for the following purposes: 1. Isolate Azure Spring Cloud from Internet. 2. Enable Azure Spring Cloud to interact with systems in either on premises data centers or Azure service in other virtual networks. 3. Empower customers to control inbound and outbound network communications for Azure Spring Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n distinct a.name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when sku_tier <> 'Standard' then 'Skip'\n when sku_tier = 'Standard' and network_profile ->> 'ServiceRuntimeSubnetID' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when sku_tier <> 'Standard' then a.name || ' is of ' || sku_tier || ' tier.'\n when sku_tier = 'Standard' and network_profile ->> 'ServiceRuntimeSubnetID' is not null then a.name || ' network injection enabled.'\n else a.name || ' network injection disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_spring_cloud_service as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_spring_cloud_service ListOfTables: - azure_spring_cloud_service - azure_subscription Parameters: [] + PrimaryTable: azure_spring_cloud_service + QueryToExecute: | + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN sku_tier <> 'Standard' THEN 'Skip' + WHEN sku_tier = 'Standard' AND network_profile ->> 'ServiceRuntimeSubnetID' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_tier <> 'Standard' THEN a.name || ' is of ' || sku_tier || ' tier.' + WHEN sku_tier = 'Standard' AND network_profile ->> 'ServiceRuntimeSubnetID' IS NOT NULL THEN a.name || ' network injection enabled.' + ELSE a.name || ' network injection disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_spring_cloud_service AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SpringCloud -IntegrationType: - - azure_subscription +Title: Azure Spring Cloud should use network injection \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_database_allow_internet_access.yaml b/compliance/controls/azure/azure_sql_database_allow_internet_access.yaml old mode 100755 new mode 100644 index f54fc1383..a19786517 --- a/compliance/controls/azure/azure_sql_database_allow_internet_access.yaml +++ b/compliance/controls/azure/azure_sql_database_allow_internet_access.yaml @@ -1,14 +1,38 @@ +Description: Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP). ID: azure_sql_database_allow_internet_access -Title: "Ensure no SQL Databases allow ingress 0.0.0.0/0 (ANY IP)" -Description: "Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when firewall_rules @> '[{\"properties\":{\"endIpAddress\":\"0.0.0.0\",\"startIpAddress\":\"0.0.0.0\"}}]'\n or firewall_rules @> '[{\"properties\":{\"endIpAddress\":\"255.255.255.255\",\"startIpAddress\":\"0.0.0.0\"}}]'\n then 'alarm'\n else 'ok'\n end as status,\n case\n when firewall_rules @> '[{\"properties\":{\"endIpAddress\":\"0.0.0.0\",\"startIpAddress\":\"0.0.0.0\"}}]'\n or firewall_rules @> '[{\"properties\":{\"endIpAddress\":\"255.255.255.255\",\"startIpAddress\":\"0.0.0.0\"}}]'\n then s.title || ' allows ingress 0.0.0.0/0 or any ip over internet.'\n else s.title || ' not allows ingress 0.0.0.0/0 or any ip over internet.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server s,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN firewall_rules @> '[{"properties":{"endIpAddress":"0.0.0.0","startIpAddress":"0.0.0.0"}}]' + OR firewall_rules @> '[{"properties":{"endIpAddress":"255.255.255.255","startIpAddress":"0.0.0.0"}}]' + THEN s.title || ' allows ingress 0.0.0.0/0 or any IP over internet.' + ELSE s.title || ' does not allow ingress 0.0.0.0/0 or any IP over internet.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: category: @@ -29,5 +53,4 @@ Tags: - azure service: - Azure/Network -IntegrationType: - - azure_subscription +Title: Ensure no SQL Databases allow ingress 0.0.0.0/0 (ANY IP) \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_database_long_term_geo_redundant_backup_enabled.yaml b/compliance/controls/azure/azure_sql_database_long_term_geo_redundant_backup_enabled.yaml old mode 100755 new mode 100644 index d7dce8453..b31932d44 --- a/compliance/controls/azure/azure_sql_database_long_term_geo_redundant_backup_enabled.yaml +++ b/compliance/controls/azure/azure_sql_database_long_term_geo_redundant_backup_enabled.yaml @@ -1,14 +1,41 @@ +Description: This policy audits any Azure SQL Database with long-term geo-redundant backup not enabled. ID: azure_sql_database_long_term_geo_redundant_backup_enabled -Title: "Long-term geo-redundant backup should be enabled for Azure SQL Databases" -Description: "This policy audits any Azure SQL Database with long-term geo-redundant backup not enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.database_id resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when retention_policy_property ->> 'monthlyRetention' <> 'PT0S'\n or retention_policy_property ->> 'weeklyRetention' <> 'PT0S'\n or retention_policy_property ->> 'yearlyRetention' <> 'PT0S'\n then 'ok'\n else 'alarm'\n end as status,\n case\n when retention_policy_property ->> 'monthlyRetention' <> 'PT0S'\n or retention_policy_property ->> 'weeklyRetention' <> 'PT0S'\n or retention_policy_property ->> 'yearlyRetention' <> 'PT0S'\n then s.title || ' long-term geo-redundant backup enabled.'\n else s.title || ' long-term geo-redundant backup disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_database s,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id\n and s.name <> 'master';\n" - PrimaryTable: azure_sql_database ListOfTables: - azure_sql_database - azure_subscription Parameters: [] + PrimaryTable: azure_sql_database + QueryToExecute: | + SELECT + s.database_id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN retention_policy_property ->> 'monthlyRetention' <> 'PT0S' + OR retention_policy_property ->> 'weeklyRetention' <> 'PT0S' + OR retention_policy_property ->> 'yearlyRetention' <> 'PT0S' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN retention_policy_property ->> 'monthlyRetention' <> 'PT0S' + OR retention_policy_property ->> 'weeklyRetention' <> 'PT0S' + OR retention_policy_property ->> 'yearlyRetention' <> 'PT0S' + THEN s.title || ' long-term geo-redundant backup enabled.' + ELSE s.title || ' long-term geo-redundant backup disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_database s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id + AND s.name <> 'master'; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +44,4 @@ Tags: - "true" service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Long-term geo-redundant backup should be enabled for Azure SQL Databases \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_database_transparent_data_encryption_enabled.yaml b/compliance/controls/azure/azure_sql_database_transparent_data_encryption_enabled.yaml old mode 100755 new mode 100644 index afddd95c9..0876f2153 --- a/compliance/controls/azure/azure_sql_database_transparent_data_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_sql_database_transparent_data_encryption_enabled.yaml @@ -1,14 +1,39 @@ +Description: Transparent data encryption should be enabled to protect data-at-rest and meet compliance requirements. ID: azure_sql_database_transparent_data_encryption_enabled -Title: "SQL databases transparent data encryption should be enabled" -Description: "Transparent data encryption should be enabled to protect data-at-rest and meet compliance requirements." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.database_id resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then s.title || ' transparent data encryption enabled.'\n else s.title || ' transparent data encryption disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_database as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id\n and s.name <> 'master';\n" - PrimaryTable: azure_sql_database ListOfTables: - azure_sql_database - azure_subscription Parameters: [] + PrimaryTable: azure_sql_database + QueryToExecute: | + SELECT + s.database_id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' + OR transparent_data_encryption ->> 'state' = 'Enabled' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' + OR transparent_data_encryption ->> 'state' = 'Enabled' + THEN s.title || ' transparent data encryption enabled.' + ELSE s.title || ' transparent data encryption disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_database AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id + AND s.name <> 'master'; Severity: The text does not provide information about a specific Azure Control to determine its suggested severity. Tags: category: @@ -29,5 +54,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: SQL databases transparent data encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_database_vulnerability_findings_resolved.yaml b/compliance/controls/azure/azure_sql_database_vulnerability_findings_resolved.yaml old mode 100755 new mode 100644 index 99ad1fb5d..376325287 --- a/compliance/controls/azure/azure_sql_database_vulnerability_findings_resolved.yaml +++ b/compliance/controls/azure/azure_sql_database_vulnerability_findings_resolved.yaml @@ -1,14 +1,51 @@ +Description: Monitor vulnerability assessment scan results and recommendations for how to remediate database vulnerabilities. ID: azure_sql_database_vulnerability_findings_resolved -Title: "SQL databases should have vulnerability findings resolved" -Description: "Monitor vulnerability assessment scan results and recommendations for how to remediate database vulnerabilities." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vulnerability_findings as (\n select\n db.id as database_id,\n scan ->> 'endTime' latest_scan_end_time,\n scan ->> 'numberOfFailedSecurityChecks' no_of_failed_sec_checks\n from\n azure_sql_database as db,\n jsonb_array_elements(vulnerability_assessment_scan_records) as scan\n where\n (scan ->> 'numberOfFailedSecurityChecks')::int = 0\n order by scan ->> 'endTime' desc nulls last\n limit 1\n)\nselect\n distinct a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when s.database_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when s.database_id is not null then a.name || ' vulnerability findings resolved.'\n else a.title || ' vulnerability findings not resolved.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_database as a\n left join vulnerability_findings as s on a.id = s.database_id,\n azure_subscription as sub\nwhere\n a.name <> 'master'\n and sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_sql_database ListOfTables: - azure_sql_database - azure_subscription Parameters: [] + PrimaryTable: azure_sql_database + QueryToExecute: | + WITH vulnerability_findings AS ( + SELECT + db.id AS database_id, + scan ->> 'endTime' AS latest_scan_end_time, + scan ->> 'numberOfFailedSecurityChecks' AS no_of_failed_sec_checks + FROM + azure_sql_database AS db, + jsonb_array_elements(vulnerability_assessment_scan_records) AS scan + WHERE + (scan ->> 'numberOfFailedSecurityChecks')::int = 0 + ORDER BY + scan ->> 'endTime' DESC NULLS LAST + LIMIT 1 + ) + SELECT + DISTINCT a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN s.database_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.database_id IS NOT NULL THEN a.name || ' vulnerability findings resolved.' + ELSE a.title || ' vulnerability findings not resolved.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_database AS a + LEFT JOIN + vulnerability_findings AS s ON a.id = s.database_id, + azure_subscription AS sub + WHERE + a.name <> 'master' + AND sub.subscription_id = a.subscription_id; Severity: high Tags: hipaa_hitrust_v92: @@ -19,5 +56,4 @@ Tags: - "true" service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: SQL databases should have vulnerability findings resolved \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_db_active_directory_admin_configured.yaml b/compliance/controls/azure/azure_sql_db_active_directory_admin_configured.yaml old mode 100755 new mode 100644 index b246713c0..82bf9fb49 --- a/compliance/controls/azure/azure_sql_db_active_directory_admin_configured.yaml +++ b/compliance/controls/azure/azure_sql_db_active_directory_admin_configured.yaml @@ -1,15 +1,35 @@ +Description: Use Azure Active Directory Authentication for authentication with SQL Database. ID: azure_sql_db_active_directory_admin_configured -Title: "Ensure that Azure Active Directory Admin is configured" -Description: "Use Azure Active Directory Authentication for authentication with SQL Database." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when server_azure_ad_administrator is null then 'alarm'\n else 'ok'\n end as status,\n case\n when server_azure_ad_administrator is null then name || ' Azure AD authentication not configured.'\n else name || ' Azure AD authentication configured.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server s,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_ad_administrator - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN server_azure_ad_administrator IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN server_azure_ad_administrator IS NULL THEN name || ' Azure AD authentication not configured.' + ELSE name || ' Azure AD authentication configured.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server s, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: category: @@ -30,5 +50,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Ensure that Azure Active Directory Admin is configured \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_db_public_network_access_disabled.yaml b/compliance/controls/azure/azure_sql_db_public_network_access_disabled.yaml old mode 100755 new mode 100644 index 525f0b00a..b3f99747f --- a/compliance/controls/azure/azure_sql_db_public_network_access_disabled.yaml +++ b/compliance/controls/azure/azure_sql_db_public_network_access_disabled.yaml @@ -1,19 +1,38 @@ +Description: Disabling the public network access property improves security by ensuring your Azure SQL Database can only be accessed from a private endpoint. This configuration denies all logins that match IP or virtual network based firewall rules. ID: azure_sql_db_public_network_access_disabled -Title: "Public network access on Azure SQL Database should be disabled" -Description: "Disabling the public network access property improves security by ensuring your Azure SQL Database can only be accessed from a private endpoint. This configuration denies all logins that match IP or virtual network based firewall rules." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when public_network_access = 'Enabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when public_network_access = 'Enabled' then name || ' public network access enabled.'\n else name || ' public network access disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN public_network_access = 'Enabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_network_access = 'Enabled' THEN name || ' public network access enabled.' + ELSE name || ' public network access disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Public network access on Azure SQL Database should be disabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_and_databases_va_enabled.yaml b/compliance/controls/azure/azure_sql_server_and_databases_va_enabled.yaml old mode 100755 new mode 100644 index 66355f6ad..fedf6e2c8 --- a/compliance/controls/azure/azure_sql_server_and_databases_va_enabled.yaml +++ b/compliance/controls/azure/azure_sql_server_and_databases_va_enabled.yaml @@ -3,7 +3,28 @@ Title: "Vulnerability assessment should be enabled on your SQL servers" Description: "Audit Azure SQL servers which do not have recurring vulnerability assessment scans enabled. Vulnerability assessment can discover, track, and help you remediate potential database vulnerabilities." Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then s.name || ' VA setting disabled.'\n else s.name || ' VA setting enabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN s.name || ' VA setting disabled.' + ELSE s.name || ' VA setting enabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server s, + JSONB_ARRAY_ELEMENTS(server_security_alert_policy) security, + JSONB_ARRAY_ELEMENTS(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server @@ -30,4 +51,4 @@ Tags: service: - Azure/SQL IntegrationType: - - azure_subscription + - azure_subscription \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_atp_enabled.yaml b/compliance/controls/azure/azure_sql_server_atp_enabled.yaml old mode 100755 new mode 100644 index 208cb5e13..f558f2eb4 --- a/compliance/controls/azure/azure_sql_server_atp_enabled.yaml +++ b/compliance/controls/azure/azure_sql_server_atp_enabled.yaml @@ -1,14 +1,35 @@ +Description: Enable "Azure Defender for SQL" on critical SQL Servers. ID: azure_sql_server_atp_enabled -Title: "Ensure that Microsoft Defender for SQL is set to 'On' for critical SQL Servers" -Description: "Enable \\\"Azure Defender for SQL\\\" on critical SQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then s.name || ' Azure defender disabled.'\n else s.name || ' Azure defender enabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN s.name || ' Azure defender disabled.' + ELSE s.name || ' Azure defender enabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: critical Tags: category: @@ -29,5 +50,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Ensure that Microsoft Defender for SQL is set to 'On' for critical SQL Servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_auditing_on.yaml b/compliance/controls/azure/azure_sql_server_auditing_on.yaml old mode 100755 new mode 100644 index 984b7f95f..75d0273d6 --- a/compliance/controls/azure/azure_sql_server_auditing_on.yaml +++ b/compliance/controls/azure/azure_sql_server_auditing_on.yaml @@ -1,14 +1,36 @@ +Description: Auditing on your SQL Server should be enabled to track database activities across all databases on the server and save them in an audit log. ID: azure_sql_server_auditing_on -Title: "Auditing on SQL server should be enabled" -Description: "Auditing on your SQL Server should be enabled to track database activities across all databases on the server and save them in an audit log." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then name || ' auditing disabled.'\n else name || ' auditing enabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' + THEN name || ' auditing disabled.' + ELSE name || ' auditing enabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Auditing on SQL server should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_auditing_retention_period_90.yaml b/compliance/controls/azure/azure_sql_server_auditing_retention_period_90.yaml old mode 100755 new mode 100644 index d668503c0..6e4513e46 --- a/compliance/controls/azure/azure_sql_server_auditing_retention_period_90.yaml +++ b/compliance/controls/azure/azure_sql_server_auditing_retention_period_90.yaml @@ -1,14 +1,37 @@ +Description: SQL Server Audit Retention should be configured to be greater than 90 days. ID: azure_sql_server_auditing_retention_period_90 -Title: "Ensure that 'Auditing' Retention is 'greater than 90 days'" -Description: "SQL Server Audit Retention should be configured to be greater than 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then 'ok'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then name || ' audit retention set to unlimited days.'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then name || ' audit retention greater than 90 days.'\n else name || ' audit retention less than 90 days.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN 'ok' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN name || ' audit retention set to unlimited days.' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN name || ' audit retention greater than 90 days.' + ELSE name || ' audit retention less than 90 days.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +52,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Ensure that 'Auditing' Retention is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_auditing_storage_account_destination_retention_90_days.yaml b/compliance/controls/azure/azure_sql_server_auditing_storage_account_destination_retention_90_days.yaml old mode 100755 new mode 100644 index 8ab3a4c26..e66d1e325 --- a/compliance/controls/azure/azure_sql_server_auditing_storage_account_destination_retention_90_days.yaml +++ b/compliance/controls/azure/azure_sql_server_auditing_storage_account_destination_retention_90_days.yaml @@ -1,19 +1,57 @@ +Description: For incident investigation purposes, we recommend setting the data retention for your SQL Server' auditing to storage account destination to at least 90 days. Confirm that you are meeting the necessary retention rules for the regions in which you are operating. This is sometimes required for compliance with regulatory standards. ID: azure_sql_server_auditing_storage_account_destination_retention_90_days -Title: "SQL servers with auditing to storage account destination should be configured with 90 days retention or higher" -Description: "For incident investigation purposes, we recommend setting the data retention for your SQL Server' auditing to storage account destination to at least 90 days. Confirm that you are meeting the necessary retention rules for the regions in which you are operating. This is sometimes required for compliance with regulatory standards." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with sql_server as(\n select\n id,\n name,\n subscription_id,\n resource_group,\n p -> 'properties' ->> 'retentionDays' as retentionDays\n from\n azure_sql_server,\n jsonb_array_elements(server_audit_policy) as p\n where\n p -> 'properties' ->> 'state' = 'Enabled'\n and p -> 'properties' ->> 'storageEndpoint' is not null\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when s.id is null then 'skip'\n -- The value in days of the retention period (0 is an indication for unlimited retention).\n when s.retentionDays::Integer = 0 then 'ok'\n when s.retentionDays::Integer >= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when s.id is null then a.name || ' auditing to storage account destination not enabled.'\n when s.retentionDays::Integer = 0 then a.name || ' auditing to storage account destination configured with unlimited retention days.'\n when s.retentionDays::Integer >= 90 then a.name || ' auditing to storage account destination configured with 90 days retention or higher.'\n else a.name || ' auditing to storage account destination not configured with 90 days retention or higher.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server as a\n left join sql_server as s on s.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + WITH sql_server AS ( + SELECT + id, + name, + subscription_id, + resource_group, + p -> 'properties' ->> 'retentionDays' AS retentionDays + FROM + azure_sql_server, + jsonb_array_elements(server_audit_policy) AS p + WHERE + p -> 'properties' ->> 'state' = 'Enabled' + AND p -> 'properties' ->> 'storageEndpoint' IS NOT NULL + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN s.id IS NULL THEN 'skip' + WHEN s.retentionDays::INTEGER = 0 THEN 'ok' + WHEN s.retentionDays::INTEGER >= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.id IS NULL THEN a.name || ' auditing to storage account destination not enabled.' + WHEN s.retentionDays::INTEGER = 0 THEN a.name || ' auditing to storage account destination configured with unlimited retention days.' + WHEN s.retentionDays::INTEGER >= 90 THEN a.name || ' auditing to storage account destination configured with 90 days retention or higher.' + ELSE a.name || ' auditing to storage account destination not configured with 90 days retention or higher.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS a + LEFT JOIN sql_server AS s ON s.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: SQL servers with auditing to storage account destination should be configured with 90 days retention or higher \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_azure_ad_authentication_enabled.yaml b/compliance/controls/azure/azure_sql_server_azure_ad_authentication_enabled.yaml old mode 100755 new mode 100644 index 464786066..1ae021af6 --- a/compliance/controls/azure/azure_sql_server_azure_ad_authentication_enabled.yaml +++ b/compliance/controls/azure/azure_sql_server_azure_ad_authentication_enabled.yaml @@ -1,15 +1,45 @@ +Description: Audit provisioning of an Azure Active Directory administrator for your SQL server to enable Azure AD authentication. Azure AD authentication enables simplified permission management and centralized identity management of database users and other Microsoft services. ID: azure_sql_server_azure_ad_authentication_enabled -Title: "An Azure Active Directory administrator should be provisioned for SQL servers" -Description: "Audit provisioning of an Azure Active Directory administrator for your SQL server to enable Azure AD authentication. Azure AD authentication enables simplified permission management and centralized identity management of database users and other Microsoft services." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with sever_with_ad_admin as (\n select\n distinct a.id\n from\n azure_sql_server as a,\n jsonb_array_elements(server_azure_ad_administrator) as ad_admin\n where\n ad_admin ->> 'type' = 'Microsoft.Sql/servers/administrators'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when s.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when s.id is not null then a.name || ' azure AD authentication enabled.'\n else a.name || ' azure AD authentication disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server as a\n left join sever_with_ad_admin as s on a.id = s.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_ad_administrator - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + WITH sever_with_ad_admin AS ( + SELECT + DISTINCT a.id + FROM + azure_sql_server AS a, + jsonb_array_elements(server_azure_ad_administrator) AS ad_admin + WHERE + ad_admin ->> 'type' = 'Microsoft.Sql/servers/administrators' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN s.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.id IS NOT NULL THEN a.name || ' azure AD authentication enabled.' + ELSE a.name || ' azure AD authentication disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS a + LEFT JOIN sever_with_ad_admin AS s ON a.id = s.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: @@ -18,5 +48,4 @@ Tags: - "true" service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: An Azure Active Directory administrator should be provisioned for SQL servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_azure_defender_enabled.yaml b/compliance/controls/azure/azure_sql_server_azure_defender_enabled.yaml old mode 100755 new mode 100644 index 9ca260528..eaafc4aeb --- a/compliance/controls/azure/azure_sql_server_azure_defender_enabled.yaml +++ b/compliance/controls/azure/azure_sql_server_azure_defender_enabled.yaml @@ -1,19 +1,51 @@ +Description: Audit SQL servers without Advanced Data Security. ID: azure_sql_server_azure_defender_enabled -Title: "Azure Defender for SQL should be enabled for unprotected Azure SQL servers" -Description: "Audit SQL servers without Advanced Data Security." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with sql_server_policy as (\n select\n distinct a.name\n from\n azure_sql_server as a,\n jsonb_array_elements(server_security_alert_policy) as policy\n where\n policy ->> 'name' = 'Default'\n and policy -> 'properties' ->> 'state' = 'Enabled'\n)\nselect\n distinct a.name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when kind like '%analytics%' then 'skip'\n when s.name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when kind like '%analytics%' then a.name || ' azure defender not applicable.'\n when s.name is null then a.name || 'sql azure defender disabled.'\n else a.name || ' sql azure defender enabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server as a\n left join sql_server_policy as s on a.name = s.name,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + WITH sql_server_policy AS ( + SELECT + DISTINCT a.name + FROM + azure_sql_server AS a, + jsonb_array_elements(server_security_alert_policy) AS policy + WHERE + policy ->> 'name' = 'Default' + AND policy -> 'properties' ->> 'state' = 'Enabled' + ) + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN kind LIKE '%analytics%' THEN 'skip' + WHEN s.name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kind LIKE '%analytics%' THEN a.name || ' azure defender not applicable.' + WHEN s.name IS NULL THEN a.name || ' sql azure defender disabled.' + ELSE a.name || ' sql azure defender enabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS a + LEFT JOIN sql_server_policy AS s ON a.name = s.name, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Azure Defender for SQL should be enabled for unprotected Azure SQL servers \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_tde_protector_cmk_encrypted.yaml b/compliance/controls/azure/azure_sql_server_tde_protector_cmk_encrypted.yaml old mode 100755 new mode 100644 index 1232720da..5da2f088f --- a/compliance/controls/azure/azure_sql_server_tde_protector_cmk_encrypted.yaml +++ b/compliance/controls/azure/azure_sql_server_tde_protector_cmk_encrypted.yaml @@ -1,14 +1,35 @@ +Description: Implementing Transparent Data Encryption (TDE) with your own key provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. This recommendation applies to organizations with a related compliance requirement. ID: azure_sql_server_tde_protector_cmk_encrypted -Title: "SQL servers should use customer-managed keys to encrypt data at rest" -Description: "Implementing Transparent Data Encryption (TDE) with your own key provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. This recommendation applies to organizations with a related compliance requirement." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when encryption ->> 'kind' = 'servicemanaged' then 'alarm'\n else 'ok'\n end as status,\n case\n when encryption ->> 'kind' = 'servicemanaged' then s.name || ' TDE protector not encrypted with CMK.'\n else s.name || ' TDE protector encrypted with CMK.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server s,\n jsonb_array_elements(encryption_protector) encryption,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN s.name || ' TDE protector not encrypted with CMK.' + ELSE s.name || ' TDE protector encrypted with CMK.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server s, + jsonb_array_elements(encryption_protector) encryption, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: category: @@ -29,5 +50,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: SQL servers should use customer-managed keys to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_threat_detection_all_enabled.yaml b/compliance/controls/azure/azure_sql_server_threat_detection_all_enabled.yaml old mode 100755 new mode 100644 index 3fc67ed60..1ba8b4232 --- a/compliance/controls/azure/azure_sql_server_threat_detection_all_enabled.yaml +++ b/compliance/controls/azure/azure_sql_server_threat_detection_all_enabled.yaml @@ -1,42 +1,42 @@ +Description: This control ensures that SQL server threat detection is enabled for all. ID: azure_sql_server_threat_detection_all_enabled -Title: "SQL server threat detection should be enabled for all" -Description: "This control ensures that SQL server threat detection is enabled for all." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with threat_detection_disabled as ( - select - distinct id - from + ListOfTables: + - azure_sql_server + - azure_subscription + Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + WITH threat_detection_disabled AS ( + SELECT + DISTINCT id + FROM azure_sql_server s, jsonb_array_elements(server_security_alert_policy) p - where - not (p -> 'properties' -> 'disabledAlerts' = '[""]') + WHERE + NOT (p -> 'properties' -> 'disabledAlerts' = '[""]') ) - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when t.id is null then 'ok' - else 'alarm' - end as status, - case - when t.id is null then name || ' threat detection enabled for all.' - else name || ' threat detection not enabled for all.' - end as reason - from + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN t.id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN t.id IS NULL THEN name || ' threat detection enabled for all.' + ELSE name || ' threat detection not enabled for all.' + END AS reason + FROM azure_sql_server s - left join threat_detection_disabled as t on t.id = s.id, + LEFT JOIN threat_detection_disabled AS t ON t.id = s.id, azure_subscription sub - where + WHERE sub.subscription_id = s.subscription_id; - PrimaryTable: azure_sql_server - ListOfTables: - - azure_sql_server - - azure_subscription - Parameters: [] Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: SQL server threat detection should be enabled for all \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_transparent_data_encryption_enabled.yaml b/compliance/controls/azure/azure_sql_server_transparent_data_encryption_enabled.yaml old mode 100755 new mode 100644 index 03fc77cfc..990ea7b22 --- a/compliance/controls/azure/azure_sql_server_transparent_data_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_sql_server_transparent_data_encryption_enabled.yaml @@ -1,19 +1,38 @@ +Description: Transparent data encryption should be enabled to protect data-at-rest and meet compliance requirements. ID: azure_sql_server_transparent_data_encryption_enabled -Title: "Transparent Data Encryption on SQL databases should be enabled" -Description: "Transparent data encryption should be enabled to protect data-at-rest and meet compliance requirements." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n db.id as resource,\n db.og_account_id as og_account_id,\n db.og_resource_id as og_resource_id,\n case\n when transparent_data_encryption ->> 'status' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when transparent_data_encryption ->> 'status' = 'Disabled' then db.name || ' transparent data encryption off.'\n else db.name || ' transparent data encryption on.'\n end as reason\n \n , db.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_database db,\n azure_subscription sub\nwhere\n sub.subscription_id = db.subscription_id;\n" - PrimaryTable: azure_sql_database ListOfTables: - azure_sql_database - azure_subscription Parameters: [] + PrimaryTable: azure_sql_database + QueryToExecute: | + SELECT + db.id AS resource, + db.og_account_id AS og_account_id, + db.og_resource_id AS og_resource_id, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Disabled' THEN db.name || ' transparent data encryption off.' + ELSE db.name || ' transparent data encryption on.' + END AS reason, + db.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_database db, + azure_subscription sub + WHERE + sub.subscription_id = db.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Transparent Data Encryption on SQL databases should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_use_virtual_service_endpoint.yaml b/compliance/controls/azure/azure_sql_server_use_virtual_service_endpoint.yaml old mode 100755 new mode 100644 index d2b4670c0..fffb830fe --- a/compliance/controls/azure/azure_sql_server_use_virtual_service_endpoint.yaml +++ b/compliance/controls/azure/azure_sql_server_use_virtual_service_endpoint.yaml @@ -1,19 +1,47 @@ +Description: This policy audits any SQL Server not configured to use a virtual network service endpoint. ID: azure_sql_server_use_virtual_service_endpoint -Title: "SQL Server should use a virtual network service endpoint" -Description: "This policy audits any SQL Server not configured to use a virtual network service endpoint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with sql_server_subnet as (\n select\n distinct a.name,\n rule -> 'properties' -> 'virtualNetworkSubnetId' as subnet_id\n from\n azure_sql_server as a,\n jsonb_array_elements(virtual_network_rules) as rule\n)\nselect\n distinct a.name as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when s.name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when s.name is null then a.name || ' not configured with virtual service endpoint.'\n else a.name || ' configured with virtual service endpoint.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server as a\n left join sql_server_subnet as s on a.name = s.name,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + WITH sql_server_subnet AS ( + SELECT + DISTINCT a.name, + rule -> 'properties' -> 'virtualNetworkSubnetId' AS subnet_id + FROM + azure_sql_server AS a, + jsonb_array_elements(virtual_network_rules) AS rule + ) + SELECT + DISTINCT a.name AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN s.name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.name IS NULL THEN a.name || ' not configured with virtual service endpoint.' + ELSE a.name || ' configured with virtual service endpoint.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS a + LEFT JOIN sql_server_subnet AS s ON a.name = s.name, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: SQL Server should use a virtual network service endpoint \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_uses_private_link.yaml b/compliance/controls/azure/azure_sql_server_uses_private_link.yaml old mode 100755 new mode 100644 index e1cfb2ed1..df6b0b0e3 --- a/compliance/controls/azure/azure_sql_server_uses_private_link.yaml +++ b/compliance/controls/azure/azure_sql_server_uses_private_link.yaml @@ -1,19 +1,50 @@ +Description: Private endpoint connections enforce secure communication by enabling private connectivity to Azure SQL Database. ID: azure_sql_server_uses_private_link -Title: "Private endpoint connections on Azure SQL Database should be enabled" -Description: "Private endpoint connections enforce secure communication by enabling private connectivity to Azure SQL Database." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with sql_server_private_connection as (\n select\n distinct a.id\n from\n azure_sql_server as a,\n jsonb_array_elements(private_endpoint_connections) as connection\n where\n connection ->> 'PrivateLinkServiceConnectionStateStatus' = 'Approved'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when c.id is null then a.name || ' not uses private link.'\n else a.name || ' uses private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server as a\n left join sql_server_private_connection as c on c.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + WITH sql_server_private_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_sql_server AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection ->> 'PrivateLinkServiceConnectionStateStatus' = 'Approved' + ) + + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS a + LEFT JOIN + sql_server_private_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Private endpoint connections on Azure SQL Database should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_va_setting_periodic_scan_enabled.yaml b/compliance/controls/azure/azure_sql_server_va_setting_periodic_scan_enabled.yaml old mode 100755 new mode 100644 index 441cdc82e..dfd72d5e8 --- a/compliance/controls/azure/azure_sql_server_va_setting_periodic_scan_enabled.yaml +++ b/compliance/controls/azure/azure_sql_server_va_setting_periodic_scan_enabled.yaml @@ -1,14 +1,52 @@ +Description: Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases. ID: azure_sql_server_va_setting_periodic_scan_enabled -Title: "Ensure that VA setting Periodic Recurring Scans is enabled on a SQL server" -Description: "Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false'\n )\n then s.name || ' VA setting periodic recurring scans disabled.'\n else s.name || ' VA setting periodic recurring scans enabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false' + ) + THEN s.name || ' VA setting periodic recurring scans disabled.' + ELSE s.name || ' VA setting periodic recurring scans enabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: category: @@ -29,5 +67,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Ensure that VA setting Periodic Recurring Scans is enabled on a SQL server \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_va_setting_reports_notify_admins.yaml b/compliance/controls/azure/azure_sql_server_va_setting_reports_notify_admins.yaml old mode 100755 new mode 100644 index 2aaa28aa6..9a5760667 --- a/compliance/controls/azure/azure_sql_server_va_setting_reports_notify_admins.yaml +++ b/compliance/controls/azure/azure_sql_server_va_setting_reports_notify_admins.yaml @@ -1,14 +1,52 @@ +Description: Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'. ID: azure_sql_server_va_setting_reports_notify_admins -Title: "Ensure that Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners' is set for each SQL Server" -Description: "Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false'\n )\n then s.name || ' VA setting not configured to send email notifications to subscription admins and owners.'\n else s.name || ' VA setting configured to send email notifications to subscription admins and owners.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false' + ) + THEN s.name || ' VA setting not configured to send email notifications to subscription admins and owners.' + ELSE s.name || ' VA setting configured to send email notifications to subscription admins and owners.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +67,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Ensure that Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners' is set for each SQL Server \ No newline at end of file diff --git a/compliance/controls/azure/azure_sql_server_va_setting_scan_reports_configured.yaml b/compliance/controls/azure/azure_sql_server_va_setting_scan_reports_configured.yaml old mode 100755 new mode 100644 index d20f2b95a..701caefd1 --- a/compliance/controls/azure/azure_sql_server_va_setting_scan_reports_configured.yaml +++ b/compliance/controls/azure/azure_sql_server_va_setting_scan_reports_configured.yaml @@ -1,14 +1,52 @@ +Description: Configure 'Send scan reports to' with email ids of concerned data owners/stakeholders for a critical SQL servers. ID: azure_sql_server_va_setting_scan_reports_configured -Title: "Ensure that VA setting 'Send scan reports to' is configured for a SQL server" -Description: "Configure 'Send scan reports to' with email ids of concerned data owners/stakeholders for a critical SQL servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]'\n )\n then s.name || ' VA scan reports and alerts not configured send email.'\n else s.name || ' VA scan reports and alerts configured to send email.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]' + ) + THEN s.name || ' VA scan reports and alerts not configured send email.' + ELSE s.name || ' VA scan reports and alerts configured to send email.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: category: @@ -29,5 +67,4 @@ Tags: - azure service: - Azure/SQL -IntegrationType: - - azure_subscription +Title: Ensure that VA setting 'Send scan reports to' is configured for a SQL server \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_blob_containers_public_access_private.yaml b/compliance/controls/azure/azure_storage_account_blob_containers_public_access_private.yaml old mode 100755 new mode 100644 index 056414dde..233da7a8f --- a/compliance/controls/azure/azure_storage_account_blob_containers_public_access_private.yaml +++ b/compliance/controls/azure/azure_storage_account_blob_containers_public_access_private.yaml @@ -1,15 +1,35 @@ +Description: Disable anonymous access to blob containers and disallow blob public access on storage account. ID: azure_storage_account_blob_containers_public_access_private -Title: "Ensure that 'Public access level' is set to Private for blob containers" -Description: "Disable anonymous access to blob containers and disallow blob public access on storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n container.id as resource,\n container.og_account_id as og_account_id,\n container.og_resource_id as og_resource_id,\n case\n when not account.allow_blob_public_access and container.public_access = 'None' then 'ok'\n else 'alarm'\n end as status,\n case\n when not account.allow_blob_public_access and container.public_access = 'None'\n then account.name || ' container ' || container.name || ' doesn''t allow anonymous access.'\n else account.name || ' container ' || container.name || ' allows anonymous access.'\n end as reason\n \n , container.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_container container\n join azure_storage_account account on container.account_name = account.name\n join azure_subscription sub on sub.subscription_id = account.subscription_id;\n" - PrimaryTable: azure_storage_container ListOfTables: - azure_storage_account - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_container + QueryToExecute: | + SELECT + container.id AS resource, + container.og_account_id AS og_account_id, + container.og_resource_id AS og_resource_id, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' + THEN account.name || ' container ' || container.name || ' doesn''t allow anonymous access.' + ELSE account.name || ' container ' || container.name || ' allows anonymous access.' + END AS reason, + container.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_container container + JOIN azure_storage_account account ON container.account_name = account.name + JOIN azure_subscription sub ON sub.subscription_id = account.subscription_id; Severity: high Tags: category: @@ -30,5 +50,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Ensure that 'Public access level' is set to Private for blob containers \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_blob_service_logging_enabled.yaml b/compliance/controls/azure/azure_storage_account_blob_service_logging_enabled.yaml old mode 100755 new mode 100644 index 291a7398f..ec18889bf --- a/compliance/controls/azure/azure_storage_account_blob_service_logging_enabled.yaml +++ b/compliance/controls/azure/azure_storage_account_blob_service_logging_enabled.yaml @@ -1,14 +1,43 @@ +Description: 'The Storage Blob service provides scalable, cost-efficient objective storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information, and the sizes of the request and response messages.' ID: azure_storage_account_blob_service_logging_enabled -Title: "Ensure Storage logging is enabled for Blob service for read, write, and delete requests" -Description: "The Storage Blob service provides scalable, cost-efficient objective storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information, and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when not (sa.blob_service_logging ->> 'Read') :: boolean\n or not (sa.blob_service_logging ->> 'Write') :: boolean\n or not (sa.blob_service_logging ->> 'Delete') :: boolean then 'alarm'\n else 'ok'\n end as status,\n case\n when not (sa.blob_service_logging ->> 'Read') :: boolean\n or not (sa.blob_service_logging ->> 'Write') :: boolean\n or not (sa.blob_service_logging ->> 'Delete') :: boolean then name || ' blob service logging not enabled for ' ||\n concat_ws(', ',\n case when not (sa.blob_service_logging ->> 'Write') :: boolean then 'write' end,\n case when not (sa.blob_service_logging ->> 'Read') :: boolean then 'read' end,\n case when not (sa.blob_service_logging ->> 'Delete') :: boolean then 'delete' end\n ) || ' requests.'\n else name || ' blob service logging enabled for read, write, delete requests.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN name || ' blob service logging not enabled for ' || + CONCAT_WS(', ', + CASE WHEN NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN THEN 'write' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN THEN 'read' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN 'delete' END + ) || ' requests.' + ELSE name || ' blob service logging enabled for read, write, delete requests.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: medium Tags: category: @@ -29,5 +58,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Ensure Storage logging is enabled for Blob service for read, write, and delete requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_blobs_logging_enabled.yaml b/compliance/controls/azure/azure_storage_account_blobs_logging_enabled.yaml old mode 100755 new mode 100644 index 68f643ea8..3c089cdd9 --- a/compliance/controls/azure/azure_storage_account_blobs_logging_enabled.yaml +++ b/compliance/controls/azure/azure_storage_account_blobs_logging_enabled.yaml @@ -1,43 +1,43 @@ +Description: Storage Logging records details of requests (read, write, and delete operations) against your Azure blobs. This policy identifies Azure storage accounts that do not have logging enabled for blobs. As a best practice, enable logging for read, write, and delete request types on blobs. ID: azure_storage_account_blobs_logging_enabled -Title: "Storage account logging (Classic Diagnostic Setting) for blobs should be enabled" -Description: "Storage Logging records details of requests (read, write, and delete operations) against your Azure blobs. This policy identifies Azure storage accounts that do not have logging enabled for blobs. As a best practice, enable logging for read, write, and delete request types on blobs." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when lower(sa.sku_tier) = 'standard' - and (not (sa.blob_service_logging ->> 'Read') :: boolean - or not (sa.blob_service_logging ->> 'Write') :: boolean - or not (sa.blob_service_logging ->> 'Delete') :: boolean) then 'alarm' - else 'ok' - end as status, - case - when lower(sa.sku_tier) = 'standard' - and (not (sa.blob_service_logging ->> 'Read') :: boolean - or not (sa.blob_service_logging ->> 'Write') :: boolean - or not (sa.blob_service_logging ->> 'Delete') :: boolean) then name || ' storage account logging for blobs is disabled for' || - concat_ws(', ', - case when not (sa.blob_service_logging ->> 'Write') :: boolean then 'write' end, - case when not (sa.blob_service_logging ->> 'Read') :: boolean then 'read' end, - case when not (sa.blob_service_logging ->> 'Delete') :: boolean then 'delete' end - ) || ' requests.' - else name || ' storage account logging for blobs is enabled.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(sa.sku_tier) = 'standard' + AND (NOT (sa.blob_service_logging ->> 'Read')::boolean + OR NOT (sa.blob_service_logging ->> 'Write')::boolean + OR NOT (sa.blob_service_logging ->> 'Delete')::boolean) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(sa.sku_tier) = 'standard' + AND (NOT (sa.blob_service_logging ->> 'Read')::boolean + OR NOT (sa.blob_service_logging ->> 'Write')::boolean + OR NOT (sa.blob_service_logging ->> 'Delete')::boolean) THEN name || ' storage account logging for blobs is disabled for' + || CONCAT_WS(', ', + CASE WHEN NOT (sa.blob_service_logging ->> 'Write')::boolean THEN 'write' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Read')::boolean THEN 'read' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Delete')::boolean THEN 'delete' END + ) || ' requests.' + ELSE name || ' storage account logging for blobs is enabled.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Storage account logging (Classic Diagnostic Setting) for blobs should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_block_public_access.yaml b/compliance/controls/azure/azure_storage_account_block_public_access.yaml old mode 100755 new mode 100644 index 5b6908197..aa3446b05 --- a/compliance/controls/azure/azure_storage_account_block_public_access.yaml +++ b/compliance/controls/azure/azure_storage_account_block_public_access.yaml @@ -1,19 +1,44 @@ +Description: Anonymous public read access to containers and blobs in Azure Storage is a convenient way to share data but might present security risks. To prevent data breaches caused by undesired anonymous access, Microsoft recommends preventing public access to a storage account unless your scenario requires it. ID: azure_storage_account_block_public_access -Title: "Storage account public access should be disallowed" -Description: "Anonymous public read access to containers and blobs in Azure Storage is a convenient way to share data but might present security risks. To prevent data breaches caused by undesired anonymous access, Microsoft recommends preventing public access to a storage account unless your scenario requires it." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when sa.id not like '%/resourceGroups/aro-%'\n and (sa.name not like 'cluster%' or sa.name not like 'imageregistry%')\n and sa.allow_blob_public_access = 'false'\n then 'ok'\n else 'alarm'\n end as status,\n case\n when sa.id not like '%/resourceGroups/aro-%'\n and (sa.name not like 'cluster%' or sa.name not like 'imageregistry%')\n and sa.allow_blob_public_access = 'false'\n then sa.name || ' not publicy accessible.'\n else sa.name || ' publicy accessible.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.id NOT LIKE '%/resourceGroups/aro-%' + AND (sa.name NOT LIKE 'cluster%' OR sa.name NOT LIKE 'imageregistry%') + AND sa.allow_blob_public_access = 'false' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sa.id NOT LIKE '%/resourceGroups/aro-%' + AND (sa.name NOT LIKE 'cluster%' OR sa.name NOT LIKE 'imageregistry%') + AND sa.allow_blob_public_access = 'false' + THEN sa.name || ' not publicy accessible.' + ELSE sa.name || ' publicy accessible.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Storage account public access should be disallowed \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_default_network_access_rule_denied.yaml b/compliance/controls/azure/azure_storage_account_default_network_access_rule_denied.yaml old mode 100755 new mode 100644 index ccf5ea49c..020f46be0 --- a/compliance/controls/azure/azure_storage_account_default_network_access_rule_denied.yaml +++ b/compliance/controls/azure/azure_storage_account_default_network_access_rule_denied.yaml @@ -1,14 +1,34 @@ +Description: Network access to storage accounts should be restricted. Configure network rules so only applications from allowed networks can access the storage account. To allow connections from specific internet or on-premises clients, access can be granted to traffic from specific Azure virtual networks or to public internet IP address ranges. ID: azure_storage_account_default_network_access_rule_denied -Title: "Storage accounts should restrict network access" -Description: "Network access to storage accounts should be restricted. Configure network rules so only applications from allowed networks can access the storage account. To allow connections from specific internet or on-premises clients, access can be granted to traffic from specific Azure virtual networks or to public internet IP address ranges." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when sa.network_rule_default_action = 'Allow' then 'alarm'\n else 'ok'\n end as status,\n case\n when sa.network_rule_default_action = 'Allow' then name || ' allows traffic from all networks.'\n else name || ' allows traffic from specific networks.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.network_rule_default_action = 'Allow' THEN name || ' allows traffic from all networks.' + ELSE name || ' allows traffic from specific networks.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: high Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Storage accounts should restrict network access \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_encryption_at_rest_using_cmk.yaml b/compliance/controls/azure/azure_storage_account_encryption_at_rest_using_cmk.yaml old mode 100755 new mode 100644 index b69d59761..f5078778f --- a/compliance/controls/azure/azure_storage_account_encryption_at_rest_using_cmk.yaml +++ b/compliance/controls/azure/azure_storage_account_encryption_at_rest_using_cmk.yaml @@ -1,14 +1,34 @@ +Description: Secure your storage account with greater flexibility using customer-managed keys. When you specify a customer-managed key, that key is used to protect and control access to the key that encrypts your data. Using customer-managed keys provides additional capabilities to control rotation of the key encryption key or cryptographically erase data. ID: azure_storage_account_encryption_at_rest_using_cmk -Title: "Storage accounts should use customer-managed key for encryption" -Description: "Secure your storage account with greater flexibility using customer-managed keys. When you specify a customer-managed key, that key is used to protect and control access to the key that encrypts your data. Using customer-managed keys provides additional capabilities to control rotation of the key encryption key or cryptographically erase data." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when sa.encryption_key_source = 'Microsoft.Storage' then 'alarm'\n else 'ok'\n end as status,\n case\n when sa.encryption_key_source = 'Microsoft.Storage' then sa.name || ' not encrypted with CMK.'\n else sa.name || ' encrypted with CMK.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' THEN sa.name || ' not encrypted with CMK.' + ELSE sa.name || ' encrypted with CMK.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: high Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Storage accounts should use customer-managed key for encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_encryption_scopes_encrypted_at_rest_with_cmk.yaml b/compliance/controls/azure/azure_storage_account_encryption_scopes_encrypted_at_rest_with_cmk.yaml old mode 100755 new mode 100644 index 5d71c43ef..3dd964c82 --- a/compliance/controls/azure/azure_storage_account_encryption_scopes_encrypted_at_rest_with_cmk.yaml +++ b/compliance/controls/azure/azure_storage_account_encryption_scopes_encrypted_at_rest_with_cmk.yaml @@ -1,53 +1,53 @@ +Description: Use customer-managed keys to manage the encryption at rest of your storage account encryption scopes. Customer-managed keys enable the data to be encrypted with an Azure key-vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management. ID: azure_storage_account_encryption_scopes_encrypted_at_rest_with_cmk -Title: "Storage account encryption scopes should use customer-managed keys to encrypt data at rest" -Description: "Use customer-managed keys to manage the encryption at rest of your storage account encryption scopes. Customer-managed keys enable the data to be encrypted with an Azure key-vault key created and owned by you. You have full control and responsibility for the key lifecycle, including rotation and management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azure_storage_account + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_account QueryToExecute: | - with storage_account_encryption_scope as( - select - e ->> 'Id' as id, - e ->> 'Name' as name, - e ->> 'Source' as source, + WITH storage_account_encryption_scope AS ( + SELECT + e ->> 'Id' AS id, + e ->> 'Name' AS name, + e ->> 'Source' AS source, subscription_id, - og_account_id as og_account_id, - og_resource_id as og_resource_id, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, _ctx, region, resource_group - from + FROM azure_storage_account, - jsonb_array_elements(encryption_scope) as e + jsonb_array_elements(encryption_scope) AS e ) - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when source = 'Microsoft.Keyvault' then 'ok' - else 'alarm' - end as status, - case - when source = 'Microsoft.Keyvault' then s.name || ' uses customer-managed keys to encrypt data at rest.' - else s.name || ' not uses customer-managed keys to encrypt data at rest.' - end as reason - , s.resource_group as resource_group - , sub.display_name as subscription - from - storage_account_encryption_scope as s, - azure_subscription as sub - where + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN source = 'Microsoft.Keyvault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN source = 'Microsoft.Keyvault' THEN s.name || ' uses customer-managed keys to encrypt data at rest.' + ELSE s.name || ' does not use customer-managed keys to encrypt data at rest.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + storage_account_encryption_scope AS s, + azure_subscription AS sub + WHERE sub.subscription_id = s.subscription_id; - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - - azure_subscription - Parameters: [] Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Storage account encryption scopes should use customer-managed keys to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_geo_redundant_enabled.yaml b/compliance/controls/azure/azure_storage_account_geo_redundant_enabled.yaml old mode 100755 new mode 100644 index 1612482e9..b14632cd4 --- a/compliance/controls/azure/azure_storage_account_geo_redundant_enabled.yaml +++ b/compliance/controls/azure/azure_storage_account_geo_redundant_enabled.yaml @@ -1,19 +1,38 @@ +Description: Use geo-redundancy to create highly available applications. ID: azure_storage_account_geo_redundant_enabled -Title: "Geo-redundant storage should be enabled for Storage Accounts" -Description: "Use geo-redundancy to create highly available applications." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when sku_name = any(ARRAY ['Standard_GRS', 'Standard_RAGRS', 'Standard_GZRS', 'Standard_RAGZRS']) then 'ok'\n else 'alarm'\n end as status,\n case\n when sku_name = any(ARRAY ['Standard_GRS', 'Standard_RAGRS', 'Standard_GZRS', 'Standard_RAGZRS']) then name || ' geo-redundant enabled.'\n else name || ' geo-redundant disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN sku_name = ANY(ARRAY ['Standard_GRS', 'Standard_RAGRS', 'Standard_GZRS', 'Standard_RAGZRS']) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_name = ANY(ARRAY ['Standard_GRS', 'Standard_RAGRS', 'Standard_GZRS', 'Standard_RAGZRS']) THEN name || ' geo-redundant enabled.' + ELSE name || ' geo-redundant disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Geo-redundant storage should be enabled for Storage Accounts \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_infrastructure_encryption_enabled.yaml b/compliance/controls/azure/azure_storage_account_infrastructure_encryption_enabled.yaml old mode 100755 new mode 100644 index 718042d95..8d1007420 --- a/compliance/controls/azure/azure_storage_account_infrastructure_encryption_enabled.yaml +++ b/compliance/controls/azure/azure_storage_account_infrastructure_encryption_enabled.yaml @@ -1,14 +1,34 @@ +Description: Enable infrastructure encryption for higher level of assurance that the data is secure. When infrastructure encryption is enabled, data in a storage account is encrypted twice. ID: azure_storage_account_infrastructure_encryption_enabled -Title: "Storage accounts should have infrastructure encryption" -Description: "Enable infrastructure encryption for higher level of assurance that the data is secure. When infrastructure encryption is enabled, data in a storage account is encrypted twice." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when require_infrastructure_encryption then 'ok'\n else 'alarm'\n end as status,\n case\n when require_infrastructure_encryption then name || ' infrastructure encryption enabled.'\n else name || ' infrastructure encryption disabled.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN require_infrastructure_encryption THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN require_infrastructure_encryption THEN name || ' infrastructure encryption enabled.' + ELSE name || ' infrastructure encryption disabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Storage accounts should have infrastructure encryption \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_min_tls_1_2.yaml b/compliance/controls/azure/azure_storage_account_min_tls_1_2.yaml old mode 100755 new mode 100644 index 918ec446a..ffc7766af --- a/compliance/controls/azure/azure_storage_account_min_tls_1_2.yaml +++ b/compliance/controls/azure/azure_storage_account_min_tls_1_2.yaml @@ -1,14 +1,36 @@ +Description: In some cases, Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2. ID: azure_storage_account_min_tls_1_2 -Title: "Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2'" -Description: "In some cases, Azure Storage sets the minimum TLS version to be version 1.0 by default. TLS 1.0 is a legacy version and has known vulnerabilities. This minimum TLS version can be configured to be later protocols such as TLS 1.2." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when minimum_tls_version = 'TLSEnforcementDisabled' then 'alarm'\n when minimum_tls_version = 'TLS1_2' then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_tls_version = 'TLSEnforcementDisabled' then sa.name || ' TLS enforcement is disabled.'\n when minimum_tls_version = 'TLS1_2' then sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.'\n else sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN minimum_tls_version = 'TLSEnforcementDisabled' THEN 'alarm' + WHEN minimum_tls_version = 'TLS1_2' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_tls_version = 'TLSEnforcementDisabled' THEN sa.name || ' TLS enforcement is disabled.' + WHEN minimum_tls_version = 'TLS1_2' THEN sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + ELSE sa.name || ' minimum TLS version set to ' || minimum_tls_version || '.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: high Tags: category: @@ -29,5 +51,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Ensure the 'Minimum TLS version' for storage accounts is set to 'Version 1.2' \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_queue_services_logging_enabled.yaml b/compliance/controls/azure/azure_storage_account_queue_services_logging_enabled.yaml old mode 100755 new mode 100644 index b6f29bce0..825fdab36 --- a/compliance/controls/azure/azure_storage_account_queue_services_logging_enabled.yaml +++ b/compliance/controls/azure/azure_storage_account_queue_services_logging_enabled.yaml @@ -1,14 +1,40 @@ +Description: 'The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information, and the sizes of the request and response messages.' ID: azure_storage_account_queue_services_logging_enabled -Title: "Ensure Storage logging is enabled for Queue service for read, write, and delete requests" -Description: "The Storage Queue service stores messages that may be read by any client who has access to the storage account. A queue can contain an unlimited number of messages, each of which can be up to 64KB in size using version 2011-08-18 or newer. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the queues. Storage Logging log entries contain the following information about individual requests: Timing information such as start time, end-to-end latency, and server latency, authentication details, concurrency information, and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when queue_logging_read and queue_logging_write and queue_logging_delete then 'ok'\n else 'alarm'\n end as status,\n case\n when queue_logging_read and queue_logging_write and queue_logging_delete\n then sa.name || ' queue service logging enabled for read, write, delete requests.'\n else sa.name || ' queue service logging not enabled for: ' ||\n concat_ws(', ',\n case when not queue_logging_write then 'write' end,\n case when not queue_logging_read then 'read' end,\n case when not queue_logging_delete then 'delete' end\n ) || ' requests.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN queue_logging_read AND queue_logging_write AND queue_logging_delete + THEN sa.name || ' queue service logging enabled for read, write, delete requests.' + ELSE sa.name || ' queue service logging not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT queue_logging_write THEN 'write' END, + CASE WHEN NOT queue_logging_read THEN 'read' END, + CASE WHEN NOT queue_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: medium Tags: category: @@ -29,5 +55,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Ensure Storage logging is enabled for Queue service for read, write, and delete requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_restrict_network_access.yaml b/compliance/controls/azure/azure_storage_account_restrict_network_access.yaml old mode 100755 new mode 100644 index 2ca23319d..2a065d260 --- a/compliance/controls/azure/azure_storage_account_restrict_network_access.yaml +++ b/compliance/controls/azure/azure_storage_account_restrict_network_access.yaml @@ -1,14 +1,34 @@ +Description: Protect your storage accounts from potential threats using virtual network rules as a preferred method instead of IP-based filtering. Disabling IP-based filtering prevents public IPs from accessing your storage accounts. ID: azure_storage_account_restrict_network_access -Title: "Storage accounts should restrict network access using virtual network rules" -Description: "Protect your storage accounts from potential threats using virtual network rules as a preferred method instead of IP-based filtering. Disabling IP-based filtering prevents public IPs from accessing your storage accounts." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when network_rule_default_action = 'Deny' then 'ok'\n else 'alarm'\n end as status,\n case\n when network_rule_default_action = 'Deny' then sa.name || ' blocks network access.'\n else sa.name || ' allows network access.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN network_rule_default_action = 'Deny' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN network_rule_default_action = 'Deny' THEN sa.name || ' blocks network access.' + ELSE sa.name || ' allows network access.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: @@ -17,5 +37,4 @@ Tags: - "true" service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Storage accounts should restrict network access using virtual network rules \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_secure_transfer_required_enabled.yaml b/compliance/controls/azure/azure_storage_account_secure_transfer_required_enabled.yaml old mode 100755 new mode 100644 index ba0d92841..f95635480 --- a/compliance/controls/azure/azure_storage_account_secure_transfer_required_enabled.yaml +++ b/compliance/controls/azure/azure_storage_account_secure_transfer_required_enabled.yaml @@ -1,14 +1,34 @@ +Description: Audit requirement of Secure transfer in your storage account. Secure transfer is an option that forces your storage account to accept requests only from secure connections (HTTPS). Use of HTTPS ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking. ID: azure_storage_account_secure_transfer_required_enabled -Title: "Secure transfer to storage accounts should be enabled" -Description: "Audit requirement of Secure transfer in your storage account. Secure transfer is an option that forces your storage account to accept requests only from secure connections (HTTPS). Use of HTTPS ensures authentication between the server and the service and protects data in transit from network layer attacks such as man-in-the-middle, eavesdropping, and session-hijacking." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when not enable_https_traffic_only then 'alarm'\n else 'ok'\n end as status,\n case\n when not enable_https_traffic_only then sa.name || ' encryption in transit not enabled.'\n else sa.name || ' encryption in transit enabled.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT enable_https_traffic_only THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT enable_https_traffic_only THEN sa.name || ' encryption in transit not enabled.' + ELSE sa.name || ' encryption in transit enabled.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: high Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Secure transfer to storage accounts should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_soft_delete_enabled.yaml b/compliance/controls/azure/azure_storage_account_soft_delete_enabled.yaml old mode 100755 new mode 100644 index eca9718f1..53916c2d8 --- a/compliance/controls/azure/azure_storage_account_soft_delete_enabled.yaml +++ b/compliance/controls/azure/azure_storage_account_soft_delete_enabled.yaml @@ -1,14 +1,34 @@ +Description: The Azure Storage blobs contain data like ePHI, Financial, secret or personal. Erroneously modified or deleted accidentally by an application or other storage account user cause data loss or data unavailability. It is recommended the Azure Storage be made recoverable by enabling soft delete configuration. This is to save and recover data when blobs or blob snapshots are deleted. ID: azure_storage_account_soft_delete_enabled -Title: "Ensure soft delete is enabled for Azure Storage" -Description: "The Azure Storage blobs contain data like ePHI, Financial, secret or personal. Erroneously modified or deleted accidentally by an application or other storage account user cause data loss or data unavailability. It is recommended the Azure Storage be made recoverable by enabling soft delete configuration. This is to save and recover data when blobs or blob snapshots are deleted." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when not blob_soft_delete_enabled then 'alarm'\n else 'ok'\n end as status,\n case\n when not blob_soft_delete_enabled then sa.name || ' blobs soft delete disabled.'\n else sa.name || ' blobs soft delete enabled.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN NOT blob_soft_delete_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT blob_soft_delete_enabled THEN sa.name || ' blobs soft delete disabled.' + ELSE sa.name || ' blobs soft delete enabled.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: high Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Ensure soft delete is enabled for Azure Storage \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_table_service_logging_enabled.yaml b/compliance/controls/azure/azure_storage_account_table_service_logging_enabled.yaml old mode 100755 new mode 100644 index 3547fdf05..ca3a63969 --- a/compliance/controls/azure/azure_storage_account_table_service_logging_enabled.yaml +++ b/compliance/controls/azure/azure_storage_account_table_service_logging_enabled.yaml @@ -1,14 +1,40 @@ +Description: 'Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.' ID: azure_storage_account_table_service_logging_enabled -Title: "Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' requests" -Description: "Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schema-less design. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the tables. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when table_logging_write and table_logging_read and table_logging_delete then 'ok'\n else 'alarm'\n end as status,\n case\n when table_logging_write and table_logging_read and table_logging_delete\n then sa.name || ' table service logging enabled for read, write, delete requests.'\n else sa.name || ' table service logging not enabled for: ' ||\n concat_ws(', ',\n case when not table_logging_write then 'write' end,\n case when not table_logging_read then 'read' end,\n case when not table_logging_delete then 'delete' end\n ) || ' requests.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account as sa,\n azure_subscription as sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN table_logging_write AND table_logging_read AND table_logging_delete THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN table_logging_write AND table_logging_read AND table_logging_delete + THEN sa.name || ' table service logging enabled for read, write, delete requests.' + ELSE sa.name || ' table service logging not enabled for: ' || + concat_ws(', ', + CASE WHEN NOT table_logging_write THEN 'write' END, + CASE WHEN NOT table_logging_read THEN 'read' END, + CASE WHEN NOT table_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: medium Tags: category: @@ -29,5 +55,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Ensure Storage Logging is Enabled for Table Service for 'Read', 'Write', and 'Delete' requests \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_tables_logging_enabled.yaml b/compliance/controls/azure/azure_storage_account_tables_logging_enabled.yaml old mode 100755 new mode 100644 index 6c39a5159..a10a186da --- a/compliance/controls/azure/azure_storage_account_tables_logging_enabled.yaml +++ b/compliance/controls/azure/azure_storage_account_tables_logging_enabled.yaml @@ -1,40 +1,40 @@ +Description: Storage Logging records details of requests (read, write, and delete operations) against your Azure tables. This policy identifies Azure storage accounts that do not have logging enabled for tables. As a best practice, enable logging for read, write, and delete request types on tables. ID: azure_storage_account_tables_logging_enabled -Title: "Storage account logging (Classic Diagnostic Setting) for tables should be enabled" -Description: "Storage Logging records details of requests (read, write, and delete operations) against your Azure tables. This policy identifies Azure storage accounts that do not have logging enabled for tables. As a best practice, enable logging for read, write, and delete request types on tables." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - sa.id as resource, - sa.og_account_id as og_account_id, - sa.og_resource_id as og_resource_id, - case - when lower(sa.sku_tier) = 'standard' - and (table_logging_write and table_logging_read and table_logging_delete) then 'ok' - else 'alarm' - end as status, - case - when lower(sa.sku_tier) = 'standard' - and (table_logging_write and table_logging_read and table_logging_delete) - then sa.name || ' storage account logging for tables is enabled.' - else sa.name || ' storage account logging for tables is disabled for ' || - concat_ws(', ', - case when not table_logging_write then 'write' end, - case when not table_logging_read then 'read' end, - case when not table_logging_delete then 'delete' end - ) || ' requests.' - end as reason - from - azure_storage_account sa, - azure_subscription sub - where - sub.subscription_id = sa.subscription_id; - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN LOWER(sa.sku_tier) = 'standard' + AND (table_logging_write AND table_logging_read AND table_logging_delete) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN LOWER(sa.sku_tier) = 'standard' + AND (table_logging_write AND table_logging_read AND table_logging_delete) + THEN sa.name || ' storage account logging for tables is enabled.' + ELSE sa.name || ' storage account logging for tables is disabled for ' || + CONCAT_WS(', ', + CASE WHEN NOT table_logging_write THEN 'write' END, + CASE WHEN NOT table_logging_read THEN 'read' END, + CASE WHEN NOT table_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Storage account logging (Classic Diagnostic Setting) for tables should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_trusted_microsoft_services_enabled.yaml b/compliance/controls/azure/azure_storage_account_trusted_microsoft_services_enabled.yaml old mode 100755 new mode 100644 index ec288f2eb..e2ce60622 --- a/compliance/controls/azure/azure_storage_account_trusted_microsoft_services_enabled.yaml +++ b/compliance/controls/azure/azure_storage_account_trusted_microsoft_services_enabled.yaml @@ -1,14 +1,34 @@ +Description: Some Azure services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account. ID: azure_storage_account_trusted_microsoft_services_enabled -Title: "Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access" -Description: "Some Azure services that interact with storage accounts operate from networks that can't be granted access through network rules. To help this type of service work as intended, allow the set of trusted Azure services to bypass the network rules. These services will then use strong authentication to access the storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n sa.og_account_id as og_account_id,\n sa.og_resource_id as og_resource_id,\n case\n when network_rule_bypass not like '%AzureServices%' then 'alarm'\n else 'ok'\n end as status,\n case\n when network_rule_bypass not like '%AzureServices%' then sa.name || ' trusted Microsoft services not enabled.'\n else sa.name || ' trusted Microsoft services enabled.'\n end as reason\n \n , sa.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id AS og_account_id, + sa.og_resource_id AS og_resource_id, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_rule_bypass NOT LIKE '%AzureServices%' THEN sa.name || ' trusted Microsoft services not enabled.' + ELSE sa.name || ' trusted Microsoft services enabled.' + END AS reason, + sa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: medium Tags: category: @@ -29,5 +49,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Ensure 'Allow Azure services on the trusted services list to access this storage account' is Enabled for Storage Account Access \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_use_virtual_service_endpoint.yaml b/compliance/controls/azure/azure_storage_account_use_virtual_service_endpoint.yaml old mode 100755 new mode 100644 index 9a76e0dae..eef19c27d --- a/compliance/controls/azure/azure_storage_account_use_virtual_service_endpoint.yaml +++ b/compliance/controls/azure/azure_storage_account_use_virtual_service_endpoint.yaml @@ -1,20 +1,54 @@ +Description: This policy audits any Storage Account not configured to use a virtual network service endpoint. ID: azure_storage_account_use_virtual_service_endpoint -Title: "Storage Accounts should use a virtual network service endpoint" -Description: "This policy audits any Storage Account not configured to use a virtual network service endpoint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with storage_account_subnet as (\n select\n distinct a.id as storage_account_id,\n rule ->> 'id' as id\n from\n azure_storage_account as a,\n jsonb_array_elements(virtual_network_rules) as rule,\n azure_subnet as subnet,\n jsonb_array_elements(service_endpoints) as endpoints\n where\n endpoints ->> 'service' like '%Microsoft.Storage%'\n)\nselect\n distinct a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when network_rule_default_action <> 'Deny' then 'alarm'\n when s.storage_account_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when network_rule_default_action <> 'Deny' then a.name || ' not configured with virtual service endpoint.'\n when s.storage_account_id is null then a.name || ' not configured with virtual service endpoint.'\n else a.name || ' configured with virtual service endpoint.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account as a\n left join storage_account_subnet as s on a.id = s.storage_account_id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subnet - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + WITH storage_account_subnet AS ( + SELECT DISTINCT + a.id AS storage_account_id, + rule ->> 'id' AS id + FROM + azure_storage_account AS a, + jsonb_array_elements(virtual_network_rules) AS rule, + azure_subnet AS subnet, + jsonb_array_elements(service_endpoints) AS endpoints + WHERE + endpoints ->> 'service' LIKE '%Microsoft.Storage%' + ) + SELECT DISTINCT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN network_rule_default_action <> 'Deny' THEN 'alarm' + WHEN s.storage_account_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_rule_default_action <> 'Deny' THEN a.name || ' not configured with virtual service endpoint.' + WHEN s.storage_account_id IS NULL THEN a.name || ' not configured with virtual service endpoint.' + ELSE a.name || ' configured with virtual service endpoint.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS a + LEFT JOIN storage_account_subnet AS s ON a.id = s.storage_account_id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: - "true" service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Storage Accounts should use a virtual network service endpoint \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_uses_azure_resource_manager.yaml b/compliance/controls/azure/azure_storage_account_uses_azure_resource_manager.yaml old mode 100755 new mode 100644 index 9e41faaa4..e5ad1e673 --- a/compliance/controls/azure/azure_storage_account_uses_azure_resource_manager.yaml +++ b/compliance/controls/azure/azure_storage_account_uses_azure_resource_manager.yaml @@ -1,14 +1,34 @@ +Description: 'Use new Azure Resource Manager for your storage accounts to provide security enhancements such as: stronger access control (RBAC), better auditing, Azure Resource Manager based deployment and governance, access to managed identities, access to key vault for secrets, Azure AD-based authentication and support for tags and resource groups for easier security management.' ID: azure_storage_account_uses_azure_resource_manager -Title: "Storage accounts should be migrated to new Azure Resource Manager resources" -Description: "Use new Azure Resource Manager for your storage accounts to provide security enhancements such as: stronger access control (RBAC), better auditing, Azure Resource Manager based deployment and governance, access to managed identities, access to key vault for secrets, Azure AD-based authentication and support for tags and resource groups for easier security management." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when resource_group is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when resource_group is not null then s.title || ' uses azure resource manager.'\n else s.title || ' not uses azure resource manager.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN resource_group IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN resource_group IS NOT NULL THEN s.title || ' uses azure resource manager.' + ELSE s.title || ' not uses azure resource manager.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: @@ -17,5 +37,4 @@ Tags: - "true" service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Storage accounts should be migrated to new Azure Resource Manager resources \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_account_uses_private_link.yaml b/compliance/controls/azure/azure_storage_account_uses_private_link.yaml old mode 100755 new mode 100644 index af9ea0dc9..359a6202f --- a/compliance/controls/azure/azure_storage_account_uses_private_link.yaml +++ b/compliance/controls/azure/azure_storage_account_uses_private_link.yaml @@ -1,14 +1,44 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your storage account, data leakage risks are reduced. ID: azure_storage_account_uses_private_link -Title: "Storage accounts should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your storage account, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with storage_account_connection as (\n select\n distinct a.id\n from\n azure_storage_account as a,\n jsonb_array_elements(private_endpoint_connections) as connection\n where\n connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved'\n)\nselect\n distinct a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when s.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when s.id is null then a.name || ' not uses private link.'\n else a.name || ' uses private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_account as a\n left join storage_account_connection as s on a.id = s.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + WITH storage_account_connection AS ( + SELECT + DISTINCT a.id + FROM + azure_storage_account AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE + connection -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT + DISTINCT a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN s.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS a + LEFT JOIN storage_account_connection AS s ON a.id = s.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: category: @@ -29,5 +59,4 @@ Tags: - azure service: - Azure/Storage -IntegrationType: - - azure_subscription +Title: Storage accounts should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_storage_sync_private_link_used.yaml b/compliance/controls/azure/azure_storage_sync_private_link_used.yaml old mode 100755 new mode 100644 index 2854d5a04..891fb9657 --- a/compliance/controls/azure/azure_storage_sync_private_link_used.yaml +++ b/compliance/controls/azure/azure_storage_sync_private_link_used.yaml @@ -1,19 +1,44 @@ +Description: Creating a private endpoint for the indicated Storage Sync Service resource allows you to address your Storage Sync Service resource from within the private IP address space of your organization's network, rather than through the internet-accessible public endpoint. Creating a private endpoint by itself does not disable the public endpoint. ID: azure_storage_sync_private_link_used -Title: "Azure File Sync should use private link" -Description: "Creating a private endpoint for the indicated Storage Sync Service resource allows you to address your Storage Sync Service resource from within the private IP address space of your organization's network, rather than through the internet-accessible public endpoint. Creating a private endpoint by itself does not disable the public endpoint." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with storagesync_service_connection as (\n select\n distinct a.id\n from\n azure_storage_sync as a,\n jsonb_array_elements(private_endpoint_connections) as connection\n where\n connection -> 'PrivateLinkServiceConnectionState' ->> 'status' = 'Approved'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when incoming_traffic_policy = 'AllowAllTraffic' then 'alarm'\n when c.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when incoming_traffic_policy = 'AllowAllTraffic' then a.name || ' using public networks.'\n when c.id is null then a.name || ' not uses private link.'\n else a.name || ' uses private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_storage_sync as a\n left join storagesync_service_connection as c on c.id = a.id,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_storage_sync ListOfTables: - azure_storage_sync - azure_subscription Parameters: [] + PrimaryTable: azure_storage_sync + QueryToExecute: | + WITH storagesync_service_connection AS ( + SELECT DISTINCT a.id + FROM azure_storage_sync AS a, + jsonb_array_elements(private_endpoint_connections) AS connection + WHERE connection -> 'PrivateLinkServiceConnectionState' ->> 'status' = 'Approved' + ) + SELECT a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN incoming_traffic_policy = 'AllowAllTraffic' THEN 'alarm' + WHEN c.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN incoming_traffic_policy = 'AllowAllTraffic' THEN a.name || ' using public networks.' + WHEN c.id IS NULL THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM azure_storage_sync AS a + LEFT JOIN storagesync_service_connection AS c ON c.id = a.id, + azure_subscription AS sub + WHERE sub.subscription_id = a.subscription_id; Severity: medium Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/FileSync -IntegrationType: - - azure_subscription +Title: Azure File Sync should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_stream_analytics_job_encrypted_with_cmk.yaml b/compliance/controls/azure/azure_stream_analytics_job_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 4d0046398..00d63b3f1 --- a/compliance/controls/azure/azure_stream_analytics_job_encrypted_with_cmk.yaml +++ b/compliance/controls/azure/azure_stream_analytics_job_encrypted_with_cmk.yaml @@ -1,24 +1,24 @@ +Description: Use customer-managed keys when you want to securely store any metadata and private data assets of your Stream Analytics jobs in your storage account. This gives you total control over how your Stream Analytics data is encrypted. ID: azure_stream_analytics_job_encrypted_with_cmk -Title: "Azure Stream Analytics jobs should use customer-managed keys to encrypt data" -Description: "Use customer-managed keys when you want to securely store any metadata and private data assets of your Stream Analytics jobs in your storage account. This gives you total control over how your Stream Analytics data is encrypted." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Azure Stream Analytics jobs should use customer-managed keys to encrypt data \ No newline at end of file diff --git a/compliance/controls/azure/azure_stream_analytics_job_logging_enabled.yaml b/compliance/controls/azure/azure_stream_analytics_job_logging_enabled.yaml old mode 100755 new mode 100644 index 904c70377..929bed33b --- a/compliance/controls/azure/azure_stream_analytics_job_logging_enabled.yaml +++ b/compliance/controls/azure/azure_stream_analytics_job_logging_enabled.yaml @@ -1,14 +1,62 @@ +Description: Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised. ID: azure_stream_analytics_job_logging_enabled -Title: "Resource logs in Azure Stream Analytics should be enabled" -Description: "Audit enabling of resource logs. This enables you to recreate activity trails to use for investigation purposes; when a security incident occurs or when your network is compromised." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with logging_details as (\n select\n distinct name as job_name\n from\n azure_stream_analytics_job,\n jsonb_array_elements(diagnostic_settings) setting,\n jsonb_array_elements(setting -> 'properties' -> 'logs') log\n where\n diagnostic_settings is not null\n and (\n (\n (log ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy' ->> 'enabled') :: boolean\n and (log -> 'retentionPolicy') :: JSONB ? 'days'\n )\n or\n (\n (log ->> 'enabled') :: boolean\n and (\n log -> 'retentionPolicy' ->> 'enabled' <> 'true'\n or setting -> 'properties' ->> 'storageAccountId' = ''\n )\n )\n )\n)\nselect\n v.job_id as resource,\n v.og_account_id as og_account_id,\n v.og_resource_id as og_resource_id,\n case\n when v.diagnostic_settings is null then 'alarm'\n when l.job_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when v.diagnostic_settings is null then v.name || ' logging not enabled.'\n when l.job_name is null then v.name || ' logging not enabled.'\n else v.name || ' logging enabled.'\n end as reason\n \n , v.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_stream_analytics_job as v\n left join logging_details as l on v.name = l.job_name,\n azure_subscription as sub\nwhere\n sub.subscription_id = v.subscription_id;\n" - PrimaryTable: azure_stream_analytics_job ListOfTables: - azure_stream_analytics_job - azure_subscription Parameters: [] + PrimaryTable: azure_stream_analytics_job + QueryToExecute: | + WITH logging_details AS ( + SELECT + DISTINCT name AS job_name + FROM + azure_stream_analytics_job, + jsonb_array_elements(diagnostic_settings) setting, + jsonb_array_elements(setting -> 'properties' -> 'logs') log + WHERE + diagnostic_settings IS NOT NULL + AND ( + ( + (log ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy' ->> 'enabled')::BOOLEAN + AND (log -> 'retentionPolicy')::JSONB ? 'days' + ) + OR + ( + (log ->> 'enabled')::BOOLEAN + AND ( + log -> 'retentionPolicy' ->> 'enabled' <> 'true' + OR setting -> 'properties' ->> 'storageAccountId' = '' + ) + ) + ) + ) + SELECT + v.job_id AS resource, + v.og_account_id AS og_account_id, + v.og_resource_id AS og_resource_id, + CASE + WHEN v.diagnostic_settings IS NULL THEN 'alarm' + WHEN l.job_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.diagnostic_settings IS NULL THEN v.name || ' logging not enabled.' + WHEN l.job_name IS NULL THEN v.name || ' logging not enabled.' + ELSE v.name || ' logging enabled.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_stream_analytics_job AS v + LEFT JOIN logging_details AS l ON v.name = l.job_name, + azure_subscription AS sub + WHERE + sub.subscription_id = v.subscription_id; Severity: medium Tags: hipaa_hitrust_v92: @@ -17,5 +65,4 @@ Tags: - "true" service: - Azure/StreamAnalytics -IntegrationType: - - azure_subscription +Title: Resource logs in Azure Stream Analytics should be enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_synapse_workspace_data_exfiltration_protection_enabled.yaml b/compliance/controls/azure/azure_synapse_workspace_data_exfiltration_protection_enabled.yaml old mode 100755 new mode 100644 index d48db4e98..85346a3e3 --- a/compliance/controls/azure/azure_synapse_workspace_data_exfiltration_protection_enabled.yaml +++ b/compliance/controls/azure/azure_synapse_workspace_data_exfiltration_protection_enabled.yaml @@ -1,32 +1,32 @@ +Description: This control checks whether Synapse workspace has data exfiltration protection enabled. ID: azure_synapse_workspace_data_exfiltration_protection_enabled -Title: "Synapse workspaces should have data exfiltration protection enabled" -Description: "This control checks whether Synapse workspace has data exfiltration protection enabled." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - s.id as resource, - s.og_account_id as og_account_id, - s.og_resource_id as og_resource_id, - case - when managed_virtual_network_settings ->> 'preventDataExfiltration' = 'true' then 'ok' - else 'alarm' - end as status, - case - when managed_virtual_network_settings ->> 'preventDataExfiltration' = 'true' then s.title || ' data exfiltration protection enabled.' - else s.title || ' data exfiltration protection disabled.' - end as reason - from - azure_synapse_workspace as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_synapse_workspace ListOfTables: - azure_synapse_workspace - azure_subscription Parameters: [] + PrimaryTable: azure_synapse_workspace + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN managed_virtual_network_settings ->> 'preventDataExfiltration' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN managed_virtual_network_settings ->> 'preventDataExfiltration' = 'true' THEN s.title || ' data exfiltration protection enabled.' + ELSE s.title || ' data exfiltration protection disabled.' + END AS reason + FROM + azure_synapse_workspace AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Synapse workspaces should have data exfiltration protection enabled \ No newline at end of file diff --git a/compliance/controls/azure/azure_synapse_workspace_encryption_at_rest_using_cmk.yaml b/compliance/controls/azure/azure_synapse_workspace_encryption_at_rest_using_cmk.yaml old mode 100755 new mode 100644 index c528a3ffc..38cc298c7 --- a/compliance/controls/azure/azure_synapse_workspace_encryption_at_rest_using_cmk.yaml +++ b/compliance/controls/azure/azure_synapse_workspace_encryption_at_rest_using_cmk.yaml @@ -1,19 +1,38 @@ +Description: Use customer-managed keys to control the encryption at rest of the data stored in Azure Synapse workspaces. Customer-managed keys deliver double encryption by adding a second layer of encryption on top of the default encryption with service-managed keys. ID: azure_synapse_workspace_encryption_at_rest_using_cmk -Title: "Azure Synapse workspaces should use customer-managed keys to encrypt data at rest" -Description: "Use customer-managed keys to control the encryption at rest of the data stored in Azure Synapse workspaces. Customer-managed keys deliver double encryption by adding a second layer of encryption on top of the default encryption with service-managed keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n s.og_account_id as og_account_id,\n s.og_resource_id as og_resource_id,\n case\n when encryption -> 'CmkKey' ->> 'name' is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when encryption -> 'CmkKey' ->> 'name' is not null then s.title || ' encrypted with CMK.'\n else s.title || ' not encrypted with CMK.'\n end as reason\n \n , s.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_synapse_workspace as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: azure_synapse_workspace ListOfTables: - azure_subscription - azure_synapse_workspace Parameters: [] + PrimaryTable: azure_synapse_workspace + QueryToExecute: | + SELECT + s.id AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN encryption -> 'CmkKey' ->> 'name' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption -> 'CmkKey' ->> 'name' IS NOT NULL THEN s.title || ' encrypted with CMK.' + ELSE s.title || ' not encrypted with CMK.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_synapse_workspace AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SynapseAnalytics -IntegrationType: - - azure_subscription +Title: Azure Synapse workspaces should use customer-managed keys to encrypt data at rest \ No newline at end of file diff --git a/compliance/controls/azure/azure_synapse_workspace_private_link_used.yaml b/compliance/controls/azure/azure_synapse_workspace_private_link_used.yaml old mode 100755 new mode 100644 index 95cc35180..9463b67a9 --- a/compliance/controls/azure/azure_synapse_workspace_private_link_used.yaml +++ b/compliance/controls/azure/azure_synapse_workspace_private_link_used.yaml @@ -1,19 +1,38 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Synapse workspace, data leakage risks are reduced. ID: azure_synapse_workspace_private_link_used -Title: "Azure Synapse workspaces should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to Azure Synapse workspace, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]' then a.name || ' uses private link.'\n else a.name || ' not uses private link.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\n azure_synapse_workspace as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_synapse_workspace ListOfTables: - azure_subscription - azure_synapse_workspace Parameters: [] + PrimaryTable: azure_synapse_workspace + QueryToExecute: | + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]' THEN a.name || ' uses private link.' + ELSE a.name || ' not uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_synapse_workspace AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SynapseAnalytics -IntegrationType: - - azure_subscription +Title: Azure Synapse workspaces should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azure_synapse_workspace_vulnerability_assessment_enabled.yaml b/compliance/controls/azure/azure_synapse_workspace_vulnerability_assessment_enabled.yaml old mode 100755 new mode 100644 index a576ef325..35be9b206 --- a/compliance/controls/azure/azure_synapse_workspace_vulnerability_assessment_enabled.yaml +++ b/compliance/controls/azure/azure_synapse_workspace_vulnerability_assessment_enabled.yaml @@ -1,19 +1,51 @@ +Description: Discover, track, and remediate potential vulnerabilities by configuring recurring SQL vulnerability assessment scans on your Synapse workspaces. ID: azure_synapse_workspace_vulnerability_assessment_enabled -Title: "Vulnerability assessment should be enabled on your Synapse workspaces" -Description: "Discover, track, and remediate potential vulnerabilities by configuring recurring SQL vulnerability assessment scans on your Synapse workspaces." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with synapse_workspace as(\n select\n id,\n name,\n subscription_id,\n resource_group\n from\n azure_synapse_workspace,\n jsonb_array_elements(workspace_managed_sql_server_vulnerability_assessments) as w\n where\n w -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'true'\n)\nselect\n a.id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when s.id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when s.id is not null then a.name || ' vulnerability assessment enabled.'\n else a.name || ' vulnerability assessment disabled.'\n end as reason\n \n , a.resource_group as resource_group\n , sub.display_name as subscription\nfrom\nazure_synapse_workspace as a\nleft join synapse_workspace as s on s.id = a.id,\nazure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: azure_synapse_workspace ListOfTables: - azure_subscription - azure_synapse_workspace Parameters: [] + PrimaryTable: azure_synapse_workspace + QueryToExecute: | + WITH synapse_workspace AS ( + SELECT + id, + name, + subscription_id, + resource_group + FROM + azure_synapse_workspace, + jsonb_array_elements(workspace_managed_sql_server_vulnerability_assessments) AS w + WHERE + w -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'true' + ) + SELECT + a.id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN s.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.id IS NOT NULL THEN a.name || ' vulnerability assessment enabled.' + ELSE a.name || ' vulnerability assessment disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_synapse_workspace AS a + LEFT JOIN synapse_workspace AS s ON s.id = a.id, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: nist_sp_800_53_rev_5: - "true" service: - Azure/SynapseAnalytics -IntegrationType: - - azure_subscription +Title: Vulnerability assessment should be enabled on your Synapse workspaces \ No newline at end of file diff --git a/compliance/controls/azure/azure_web_pub_sub_private_link_used.yaml b/compliance/controls/azure/azure_web_pub_sub_private_link_used.yaml old mode 100755 new mode 100644 index a074c439f..9bbae5820 --- a/compliance/controls/azure/azure_web_pub_sub_private_link_used.yaml +++ b/compliance/controls/azure/azure_web_pub_sub_private_link_used.yaml @@ -1,24 +1,24 @@ +Description: 'Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Azure Web PubSub Service, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/awps/privatelink.' ID: azure_web_pub_sub_private_link_used -Title: "Azure Web PubSub Service should use private link" -Description: "Azure Private Link lets you connect your virtual networks to Azure services without a public IP address at the source or destination. The private link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to your Azure Web PubSub Service, you can reduce data leakage risks. Learn more about private links at: https://aka.ms/awps/privatelink." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - select - id as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - 'info' as status, - 'Manual verification required.' as reason, - display_name as subscription - from - azure_subscription; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + 'info' AS status, + 'Manual verification required.' AS reason, + display_name AS subscription + FROM + azure_subscription; Severity: low Tags: manual-verification: - "true" -IntegrationType: - - azure_subscription +Title: Azure Web PubSub Service should use private link \ No newline at end of file diff --git a/compliance/controls/azure/azuread_spn_with_more_than_one_active_client_secret_created_x_days_ago.yaml b/compliance/controls/azure/azuread_spn_with_more_than_one_active_client_secret_created_x_days_ago.yaml old mode 100755 new mode 100644 index a48e32802..39ebeaf69 --- a/compliance/controls/azure/azuread_spn_with_more_than_one_active_client_secret_created_x_days_ago.yaml +++ b/compliance/controls/azure/azuread_spn_with_more_than_one_active_client_secret_created_x_days_ago.yaml @@ -1,56 +1,56 @@ +Description: SPNs in AzureAD should not have more than one active Client Secret created X days ago ID: azuread_spn_with_active_client_secret_created_x_days_ago -Title: "Service Principal Keys in AzureAD need to comply with Key Rotation Policy" -Description: "SPNs in AzureAD should not have more than one active Client Secret created X days ago" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - azuread_service_principal + - azuread_spn + Parameters: + - Key: azureadClientSecretExpireDays + Required: true + PrimaryTable: azuread_service_principal QueryToExecute: | - with azuread_spn as ( - select + WITH azuread_spn AS ( + SELECT id, display_name, og_account_id, og_resource_id, subscription_id, ( - select count(*) - from jsonb_array_elements(password_credentials) as pc - where (value ->> 'EndDateTime')::timestamp > now() AND - now() - (pc ->> 'StartDateTime')::timestamp > '{{.azureadClientSecretExpireDays}} days'::interval - ) as active_client_secret_count, + SELECT COUNT(*) + FROM jsonb_array_elements(password_credentials) AS pc + WHERE (pc ->> 'EndDateTime')::timestamp > NOW() AND + NOW() - (pc ->> 'StartDateTime')::timestamp > '{{.azureadClientSecretExpireDays}} days'::interval + ) AS active_client_secret_count, ( - select STRING_AGG(pc ->> 'DisplayName', ', ') - from jsonb_array_elements(password_credentials) as pc - where (value ->> 'EndDateTime')::timestamp > now() AND - now() - (pc ->> 'StartDateTime')::timestamp > '{{.azureadClientSecretExpireDays}} days'::interval - ) as Ids - from + SELECT STRING_AGG(pc ->> 'DisplayName', ', ') + FROM jsonb_array_elements(password_credentials) AS pc + WHERE (pc ->> 'EndDateTime')::timestamp > NOW() AND + NOW() - (pc ->> 'StartDateTime')::timestamp > '{{.azureadClientSecretExpireDays}} days'::interval + ) AS Ids + FROM azuread_service_principal ) - select - id as resource, - case - when active_client_secret_count > 1 then 'alarm' - else 'ok' - end as status, - case - when active_client_secret_count > 0 then display_name || ' has ' || active_client_secret_count || ' active client secrets created {{.azureadClientSecretExpireDays}} days ago: [' || Ids || ']' - else display_name || ' has no active client secrets created {{.azureadClientSecretExpireDays}} days ago' - end as reason, + SELECT + id AS resource, + CASE + WHEN active_client_secret_count > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN active_client_secret_count > 0 THEN display_name || ' has ' || active_client_secret_count || ' active client secrets created {{.azureadClientSecretExpireDays}} days ago: [' || Ids || ']' + ELSE display_name || ' has no active client secrets created {{.azureadClientSecretExpireDays}} days ago' + END AS reason, og_account_id, og_resource_id, subscription_id - from + FROM azuread_spn - PrimaryTable: azuread_service_principal - ListOfTables: - - azuread_service_principal - - azuread_spn - Parameters: - - Key: azureadClientSecretExpireDays - Required: true Severity: high Tags: score_service_name: - Azure Active Directory (Azure AD) -IntegrationType: - - azure_subscription +Title: Service Principal Keys in AzureAD need to comply with Key Rotation Policy \ No newline at end of file diff --git a/compliance/controls/azure/azuread_user_should_have_mfa_enabled_with_azure_subscription_role_assignment.yaml b/compliance/controls/azure/azuread_user_should_have_mfa_enabled_with_azure_subscription_role_assignment.yaml old mode 100755 new mode 100644 index 3ee993228..c86fc0061 --- a/compliance/controls/azure/azuread_user_should_have_mfa_enabled_with_azure_subscription_role_assignment.yaml +++ b/compliance/controls/azure/azuread_user_should_have_mfa_enabled_with_azure_subscription_role_assignment.yaml @@ -1,10 +1,9 @@ +Description: AzureAD Users should have MFA Enabled with Azure subscription role assignment ID: azuread_user_should_have_mfa_enabled_with_azure_subscription_role_assignment -Title: "AzureAD Users should have MFA Enabled with Azure subscription role assignment" -Description: "AzureAD Users should have MFA Enabled with Azure subscription role assignment" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with users_with_roles as (\n SELECT distinct u.id as id, \n u.og_account_id as og_account_id, \n u.og_resource_id as og_resource_id, \n u.display_name as display_name, \n u.subscription_id as subscription_id,\n u.account_enabled as account_enabled,\n u.tenant_id as tenant_id\n FROM (azuread_user AS u JOIN azure_user_effective_access AS ea ON u.id = ea.principal_id)\n)\nselect \n u.id as resource, \n u.og_account_id as og_account_id,\n u.og_resource_id as og_resource_id,\n case\n when COALESCE(NULLIF('{{.azureadAccountStatusInclude}}',''), 'true,false,null') not like ('%' || COALESCE(u.account_enabled::text,'null') || '%') then 'skip'\n when rd.is_mfa_registered::bool = false or rd.is_mfa_registered::bool is null then 'alarm'\n else 'ok'\n end as status,\n case\n when COALESCE(NULLIF('{{.azureadAccountStatusInclude}}',''), 'true,false,null') not like ('%' || COALESCE(u.account_enabled::text,'null') || '%') then 'User is not included'\n when rd.is_mfa_registered::bool = false or rd.is_mfa_registered::bool is null then u.display_name || ' does not have MFA enbabled'\n else u.display_name || ' has MFA'\n end as reason, \n u.tenant_id\nfrom \n users_with_roles as u \n left join azuread_user_registration_details as rd on u.id = rd.id\nwhere exists (select 1 from azure_user_effective_access AS ea where u.id = ea.principal_id)\n" - PrimaryTable: azuread_user ListOfTables: - azure_user_effective_access - azuread_user @@ -12,9 +11,41 @@ Query: Parameters: - Key: azureadAccountStatusInclude Required: false + PrimaryTable: azuread_user + QueryToExecute: | + WITH users_with_roles AS ( + SELECT DISTINCT + u.id AS id, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + u.display_name AS display_name, + u.subscription_id AS subscription_id, + u.account_enabled AS account_enabled, + u.tenant_id AS tenant_id + FROM azuread_user AS u + JOIN azure_user_effective_access AS ea ON u.id = ea.principal_id + ) + SELECT + u.id AS resource, + u.og_account_id AS og_account_id, + u.og_resource_id AS og_resource_id, + CASE + WHEN COALESCE(NULLIF('{{.azureadAccountStatusInclude}}', ''), 'true,false,null') NOT LIKE ('%' || COALESCE(u.account_enabled::text, 'null') || '%') THEN 'skip' + WHEN rd.is_mfa_registered::bool = false OR rd.is_mfa_registered::bool IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COALESCE(NULLIF('{{.azureadAccountStatusInclude}}', ''), 'true,false,null') NOT LIKE ('%' || COALESCE(u.account_enabled::text, 'null') || '%') THEN 'User is not included' + WHEN rd.is_mfa_registered::bool = false OR rd.is_mfa_registered::bool IS NULL THEN u.display_name || ' does not have MFA enabled' + ELSE u.display_name || ' has MFA' + END AS reason, + u.tenant_id + FROM + users_with_roles AS u + LEFT JOIN azuread_user_registration_details AS rd ON u.id = rd.id + WHERE EXISTS (SELECT 1 FROM azure_user_effective_access AS ea WHERE u.id = ea.principal_id) Severity: high Tags: score_service_name: - Azure Active Directory (Azure AD) -IntegrationType: - - azure_subscription +Title: AzureAD Users should have MFA Enabled with Azure subscription role assignment \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_access_keys_during_initial_iam_user_setup.yaml b/compliance/controls/baseline/aws/IAM/aws_access_keys_during_initial_iam_user_setup.yaml old mode 100755 new mode 100644 index 12d2bc161..552c3d932 --- a/compliance/controls/baseline/aws/IAM/aws_access_keys_during_initial_iam_user_setup.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_access_keys_during_initial_iam_user_setup.yaml @@ -1,13 +1,33 @@ +Description: Ensure no access keys are created during IAM user initial setup with AWS Management Console. ID: aws_access_keys_during_initial_iam_user_setup -Title: "Access Keys During Initial IAM User Setup" -Description: "Ensure no access keys are created during IAM user initial setup with AWS Management Console." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n user_name as resource,\n og_account_id,\n og_resource_id,\n case\n when (access_key_1_last_rotated - user_creation_time < '5 second'::interval) and (access_key_1_last_used_date is null) then 'alarm'\n else 'ok'\n end as status,\n case\n when (access_key_1_last_rotated - user_creation_time < '5 second'::interval) and (access_key_1_last_used_date is null) then 'access key 1 is considered as unused and is better to be removed'\n when (access_key_1_last_rotated is null) then 'access key 1 is not defined'\n else 'access key 1 is being used'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_credential_report\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_name AS resource, + og_account_id, + og_resource_id, + CASE + WHEN (access_key_1_last_rotated - user_creation_time < '5 second'::interval) + AND (access_key_1_last_used_date IS NULL) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (access_key_1_last_rotated - user_creation_time < '5 second'::interval) + AND (access_key_1_last_used_date IS NULL) THEN 'access key 1 is considered as unused and is better to be removed' + WHEN (access_key_1_last_rotated IS NULL) THEN 'access key 1 is not defined' + ELSE 'access key 1 is being used' + END AS reason, + region, + account_id + FROM + aws_iam_credential_report Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +38,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Insecure Keys -IntegrationType: - - aws_cloud_account +Title: Access Keys During Initial IAM User Setup \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_access_keys_rotated_45_days.yaml b/compliance/controls/baseline/aws/IAM/aws_access_keys_rotated_45_days.yaml old mode 100755 new mode 100644 index b11a646da..01d15c5ba --- a/compliance/controls/baseline/aws/IAM/aws_access_keys_rotated_45_days.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_access_keys_rotated_45_days.yaml @@ -1,13 +1,32 @@ +Description: Ensure AWS IAM access keys are rotated on a periodic basis as a security best practice (45 Days). ID: aws_access_keys_rotated_45_days -Title: "Access Keys Rotated 45 Days" -Description: "Ensure AWS IAM access keys are rotated on a periodic basis as a security best practice (45 Days)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n access_key_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when status <> 'Active' then 'skip'\n when create_date + '45 days'::interval < now() then 'alarm'\n else 'ok'\n end as status,\n case\n when status <> 'Active' then 'key is not activated'\n when create_date + '45 days'::interval < now() then 'key is too old'\n else 'key is not old yet'\n end as reason\n \n , region, account_id\nfrom\n aws_iam_access_key v\n" - PrimaryTable: aws_iam_access_key ListOfTables: - aws_iam_access_key Parameters: [] + PrimaryTable: aws_iam_access_key + QueryToExecute: | + SELECT + access_key_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN status <> 'Active' THEN 'skip' + WHEN create_date + '45 days'::interval < now() THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status <> 'Active' THEN 'key is not activated' + WHEN create_date + '45 days'::interval < now() THEN 'key is too old' + ELSE 'key is not old yet' + END AS reason, + region, + account_id + FROM + aws_iam_access_key v Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +37,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Insecure Keys -IntegrationType: - - aws_cloud_account +Title: Access Keys Rotated 45 Days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_access_keys_rotated_x_days.yaml b/compliance/controls/baseline/aws/IAM/aws_access_keys_rotated_x_days.yaml old mode 100755 new mode 100644 index 8663deafc..990ac7ce5 --- a/compliance/controls/baseline/aws/IAM/aws_access_keys_rotated_x_days.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_access_keys_rotated_x_days.yaml @@ -1,15 +1,34 @@ +Description: Ensure AWS IAM access keys are rotated on a periodic basis as a security best practice (X Days). ID: aws_access_keys_rotated_x_days -Title: "Access Keys Rotated X Days" -Description: "Ensure AWS IAM access keys are rotated on a periodic basis as a security best practice (X Days)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n access_key_id as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when status <> 'Active' then 'skip'\n when create_date + ('{{.awsIamAccessKeyAge}}' || ' days')::interval < now() then 'alarm'\n else 'ok'\n end as status,\n case\n when status <> 'Active' then 'key is not activated'\n when create_date + ('{{.awsIamAccessKeyAge}}' || ' days')::interval < now() then 'key is too old'\n else 'key is not old yet'\n end as reason\n \n , region, account_id\nfrom\n aws_iam_access_key v\n" - PrimaryTable: aws_iam_access_key ListOfTables: - aws_iam_access_key Parameters: - Key: awsIamAccessKeyAge Required: true + PrimaryTable: aws_iam_access_key + QueryToExecute: | + SELECT + access_key_id AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN status <> 'Active' THEN 'skip' + WHEN create_date + ('{{.awsIamAccessKeyAge}}' || ' days')::interval < NOW() THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status <> 'Active' THEN 'key is not activated' + WHEN create_date + ('{{.awsIamAccessKeyAge}}' || ' days')::interval < NOW() THEN 'key is too old' + ELSE 'key is not old yet' + END AS reason, + region, + account_id + FROM + aws_iam_access_key v Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +39,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Insecure Keys -IntegrationType: - - aws_cloud_account +Title: Access Keys Rotated X Days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_account_alternate_contacts.yaml b/compliance/controls/baseline/aws/IAM/aws_account_alternate_contacts.yaml old mode 100755 new mode 100644 index 19861f6d1..dccec04c5 --- a/compliance/controls/baseline/aws/IAM/aws_account_alternate_contacts.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_account_alternate_contacts.yaml @@ -1,14 +1,32 @@ +Description: Ensure alternate contacts are set to improve the security of your AWS account. ID: aws_account_alternate_contacts -Title: "Account Alternate Contacts" -Description: "Ensure alternate contacts are set to improve the security of your AWS account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.account_id as resource,\n a.og_account_id,\n a.og_resource_id,\n case\n when c.name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when c.name is null then 'account does not have any alternate contact'\n else 'account has an alternate contact'\n end as reason,\n a.region, \n a.account_id\nfrom\n aws_account as a\n left join aws_account_alternate_contact as c on a.account_id = c.account_id\n" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_account_alternate_contact Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + a.account_id AS resource, + a.og_account_id, + a.og_resource_id, + CASE + WHEN c.name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.name IS NULL THEN 'account does not have any alternate contact' + ELSE 'account has an alternate contact' + END AS reason, + a.region, + a.account_id + FROM aws_account AS a + LEFT JOIN aws_account_alternate_contact AS c + ON a.account_id = c.account_id Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +37,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Account Alternate Contacts \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_allow_iam_users_to_change_their_own_password.yaml b/compliance/controls/baseline/aws/IAM/aws_allow_iam_users_to_change_their_own_password.yaml old mode 100755 new mode 100644 index 5f3be8b9b..e2e664fde --- a/compliance/controls/baseline/aws/IAM/aws_allow_iam_users_to_change_their_own_password.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_allow_iam_users_to_change_their_own_password.yaml @@ -1,13 +1,30 @@ +Description: Ensure that all IAM users are allowed to change their own console password. ID: aws_allow_iam_users_to_change_their_own_password -Title: "Allow IAM Users to Change Their Own Password" -Description: "Ensure that all IAM users are allowed to change their own console password." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when attached_policy_arns::text LIKE '%arn:aws:iam::aws:policy/IAMUserChangePassword%' then 'ok'\n else 'alarm'\n end as status,\n case\n when attached_policy_arns::text LIKE '%arn:aws:iam::aws:policy/IAMUserChangePassword%' then 'user is able to change its own password'\n else 'user is not able to change its own password'\n end as reason\n \n , region, account_id\nfrom\n aws_iam_user v\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN attached_policy_arns::text LIKE '%arn:aws:iam::aws:policy/IAMUserChangePassword%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN attached_policy_arns::text LIKE '%arn:aws:iam::aws:policy/IAMUserChangePassword%' THEN 'user is able to change its own password' + ELSE 'user is not able to change its own password' + END AS reason, + region, + account_id + FROM + aws_iam_user v Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Allow IAM Users to Change Their Own Password \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_approved_ecs_execute_command_access.yaml b/compliance/controls/baseline/aws/IAM/aws_approved_ecs_execute_command_access.yaml old mode 100755 new mode 100644 index 28c7a507c..51a3dba25 --- a/compliance/controls/baseline/aws/IAM/aws_approved_ecs_execute_command_access.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_approved_ecs_execute_command_access.yaml @@ -1,10 +1,9 @@ +Description: Ensure that all access to the ECS Execute Command action is approved ID: aws_approved_ecs_execute_command_access -Title: "Approved ECS Execute Command Access" -Description: "Ensure that all access to the ECS Execute Command action is approved" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT\n name AS resource,\n og_account_id,\n og_resource_id,\n 'aws_iam_user' as og_table_name,\n CASE\n WHEN (inline_policies_std::text like '%ecs:ExecuteCommand%') and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'alarm'\n WHEN exists(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as ap left join aws_iam_policy as p on p.arn = ap\n where p.policy::text like '%ecs:ExecuteCommand%'\n ) and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN (inline_policies_std::text like '%ecs:ExecuteCommand%') and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'user is not authorized to do this ecs action'\n WHEN exists(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as ap left join aws_iam_policy as p on p.arn = ap\n where p.policy::text like '%ecs:ExecuteCommand%'\n ) and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'user is not authorized to do this ecs action'\n ELSE 'ok'\n END AS reason,\n region, \n account_id\nFROM\n aws_iam_user\n\nUNION ALL\n\nSELECT\n name AS resource,\n og_account_id,\n og_resource_id,\n 'aws_iam_role' as og_table_name,\n CASE\n WHEN (inline_policies_std::text like '%ecs:ExecuteCommand%') and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'alarm'\n WHEN exists(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as ap left join aws_iam_policy as p on p.arn = ap\n where p.policy::text like '%ecs:ExecuteCommand%'\n ) and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN (inline_policies_std::text like '%ecs:ExecuteCommand%') and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'user is not authorized to do this ecs action'\n WHEN exists(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as ap left join aws_iam_policy as p on p.arn = ap\n where p.policy::text like '%ecs:ExecuteCommand%'\n ) and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'user is not authorized to do this ecs action'\n ELSE 'ok'\n END AS reason,\n region, \n account_id\nFROM\n aws_iam_role\n\nUNION ALL\n\nSELECT\n name AS resource,\n og_account_id,\n og_resource_id,\n 'aws_iam_group' as og_table_name,\n CASE\n WHEN (inline_policies_std::text like '%ecs:ExecuteCommand%') and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'alarm'\n WHEN exists(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as ap left join aws_iam_policy as p on p.arn = ap\n where p.policy::text like '%ecs:ExecuteCommand%'\n ) and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN (inline_policies_std::text like '%ecs:ExecuteCommand%') and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'user is not authorized to do this ecs action'\n WHEN exists(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as ap left join aws_iam_policy as p on p.arn = ap\n where p.policy::text like '%ecs:ExecuteCommand%'\n ) and\n ('{{.awsEcsExecuteCommandIamArns}}' not like '%' || arn || '%') THEN 'user is not authorized to do this ecs action'\n ELSE 'ok'\n END AS reason,\n region, \n account_id\nFROM\n aws_iam_group\n" - PrimaryTable: "" ListOfTables: - aws_iam_group - aws_iam_policy @@ -13,6 +12,125 @@ Query: Parameters: - Key: awsEcsExecuteCommandIamArns Required: true + PrimaryTable: "" + QueryToExecute: | + SELECT + name AS resource, + og_account_id, + og_resource_id, + 'aws_iam_user' AS og_table_name, + CASE + WHEN (inline_policies_std::text LIKE '%ecs:ExecuteCommand%') + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'alarm' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS ap + LEFT JOIN aws_iam_policy AS p ON p.arn = ap + WHERE p.policy::text LIKE '%ecs:ExecuteCommand%' + ) + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (inline_policies_std::text LIKE '%ecs:ExecuteCommand%') + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'user is not authorized to do this ecs action' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS ap + LEFT JOIN aws_iam_policy AS p ON p.arn = ap + WHERE p.policy::text LIKE '%ecs:ExecuteCommand%' + ) + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'user is not authorized to do this ecs action' + ELSE 'ok' + END AS reason, + region, + account_id + FROM + aws_iam_user + + UNION ALL + + SELECT + name AS resource, + og_account_id, + og_resource_id, + 'aws_iam_role' AS og_table_name, + CASE + WHEN (inline_policies_std::text LIKE '%ecs:ExecuteCommand%') + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'alarm' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS ap + LEFT JOIN aws_iam_policy AS p ON p.arn = ap + WHERE p.policy::text LIKE '%ecs:ExecuteCommand%' + ) + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (inline_policies_std::text LIKE '%ecs:ExecuteCommand%') + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'user is not authorized to do this ecs action' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS ap + LEFT JOIN aws_iam_policy AS p ON p.arn = ap + WHERE p.policy::text LIKE '%ecs:ExecuteCommand%' + ) + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'user is not authorized to do this ecs action' + ELSE 'ok' + END AS reason, + region, + account_id + FROM + aws_iam_role + + UNION ALL + + SELECT + name AS resource, + og_account_id, + og_resource_id, + 'aws_iam_group' AS og_table_name, + CASE + WHEN (inline_policies_std::text LIKE '%ecs:ExecuteCommand%') + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'alarm' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS ap + LEFT JOIN aws_iam_policy AS p ON p.arn = ap + WHERE p.policy::text LIKE '%ecs:ExecuteCommand%' + ) + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (inline_policies_std::text LIKE '%ecs:ExecuteCommand%') + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'user is not authorized to do this ecs action' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS ap + LEFT JOIN aws_iam_policy AS p ON p.arn = ap + WHERE p.policy::text LIKE '%ecs:ExecuteCommand%' + ) + AND ('{{.awsEcsExecuteCommandIamArns}}' NOT LIKE '%' || arn || '%') + THEN 'user is not authorized to do this ecs action' + ELSE 'ok' + END AS reason, + region, + account_id + FROM + aws_iam_group Severity: medium Tags: platform_score_cloud_service_name: @@ -23,5 +141,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Approved ECS Execute Command Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_attach_policy_to_iam_roles_associated_with_app_tier_ec2_instances.yaml b/compliance/controls/baseline/aws/IAM/aws_attach_policy_to_iam_roles_associated_with_app_tier_ec2_instances.yaml old mode 100755 new mode 100644 index 385abca0e..668724c85 --- a/compliance/controls/baseline/aws/IAM/aws_attach_policy_to_iam_roles_associated_with_app_tier_ec2_instances.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_attach_policy_to_iam_roles_associated_with_app_tier_ec2_instances.yaml @@ -1,16 +1,40 @@ +Description: Ensure IAM policy for EC2 IAM roles for app tier is configured. ID: aws_attach_policy_to_iam_roles_associated_with_app_tier_ec2_instances -Title: "Attach Policy to IAM Roles Associated with App-Tier EC2 Instances" -Description: "Ensure IAM policy for EC2 IAM roles for app tier is configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n instance_id as resource,\n i.og_account_id,\n i.og_resource_id,\n case\n when r.inline_policies is null and r.attached_policy_arns is null then 'alarm'\n else 'ok'\n end as status,\n case\n when i.iam_instance_profile_arn is null then instance_id || ' has no role attached'\n when r.inline_policies is null and r.attached_policy_arns is null then instance_id || ' role does not have any policy'\n else instance_id || ' role has policy'\n end as reason,\n i.region, \n i.account_id\nfrom\n aws_ec2_instance as i\n left join aws_iam_role as r on split_part(i.iam_instance_profile_arn, ':instance-profile/', 2) = r.name\nwhere\n i.tags::text like '%' || REPLACE(REPLACE((\n SELECT jsonb_object_agg(key, value)::text\n FROM jsonb_each_text('{{.awsAppTierTags}}'::jsonb)\n ), '{', ''), '}', '') || '%'\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance - aws_iam_role Parameters: - Key: awsAppTierTags Required: true + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + instance_id AS resource, + i.og_account_id, + i.og_resource_id, + CASE + WHEN r.inline_policies IS NULL AND r.attached_policy_arns IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.iam_instance_profile_arn IS NULL THEN instance_id || ' has no role attached' + WHEN r.inline_policies IS NULL AND r.attached_policy_arns IS NULL THEN instance_id || ' role does not have any policy' + ELSE instance_id || ' role has policy' + END AS reason, + i.region, + i.account_id + FROM + aws_ec2_instance AS i + LEFT JOIN aws_iam_role AS r ON split_part(i.iam_instance_profile_arn, ':instance-profile/', 2) = r.name + WHERE + i.tags::text LIKE '%' || REPLACE(REPLACE(( + SELECT jsonb_object_agg(key, value)::text + FROM jsonb_each_text('{{.awsAppTierTags}}'::jsonb) + ), '{', ''), '}', '') || '%' Severity: medium Tags: platform_score_cloud_service_name: @@ -21,5 +45,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Attach Policy to IAM Roles Associated with App-Tier EC2 Instances \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_canary_access_token.yaml b/compliance/controls/baseline/aws/IAM/aws_canary_access_token.yaml old mode 100755 new mode 100644 index d222dff1f..561932aa1 --- a/compliance/controls/baseline/aws/IAM/aws_canary_access_token.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_canary_access_token.yaml @@ -1,15 +1,46 @@ +Description: Detects when a canary token access key has been used ID: aws_canary_access_token -Title: "Canary Access Token" -Description: "Detects when a canary token access key has been used" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with users as (\n select\n user_id,\n u.account_id\n from\n aws_iam_user as u\n left join aws_iam_credential_report as r on r.user_arn = u.arn\n where\n u.inline_policies is null and u.attached_policy_arns is null and \n ((not r.password_enabled::bool) and (r.access_key_1_active or r.access_key_2_active))\n)\n\nselect\n account_id as resource,\n og_account_id,\n og_resource_id,\n case\n when exists(select 1 from users as u where u.account_id = a.account_id) then 'ok'\n else 'alarm'\n end as status,\n case\n when exists(select 1 from users as u where u.account_id = a.account_id) then 'Canary access tokens are used within your AWS account.'\n else ' anary access tokens are not currently used within your AWS account.'\n end as reason,\n region, \n account_id\nfrom\n aws_account as a\n" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_credential_report - aws_iam_user Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH users AS ( + SELECT + user_id, + u.account_id + FROM + aws_iam_user AS u + LEFT JOIN aws_iam_credential_report AS r ON r.user_arn = u.arn + WHERE + u.inline_policies IS NULL + AND u.attached_policy_arns IS NULL + AND ((NOT r.password_enabled::BOOL) + AND (r.access_key_1_active OR r.access_key_2_active)) + ) + + SELECT + account_id AS resource, + og_account_id, + og_resource_id, + CASE + WHEN EXISTS(SELECT 1 FROM users AS u WHERE u.account_id = a.account_id) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS(SELECT 1 FROM users AS u WHERE u.account_id = a.account_id) THEN 'Canary access tokens are used within your AWS account.' + ELSE 'Canary access tokens are not currently used within your AWS account.' + END AS reason, + region, + account_id + FROM + aws_account AS a Severity: critical Tags: platform_score_cloud_service_name: @@ -20,5 +51,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Insecure Keys -IntegrationType: - - aws_cloud_account +Title: Canary Access Token \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_check_for_iam_user_group_membership.yaml b/compliance/controls/baseline/aws/IAM/aws_check_for_iam_user_group_membership.yaml old mode 100755 new mode 100644 index 58bca8f0d..6cd70383a --- a/compliance/controls/baseline/aws/IAM/aws_check_for_iam_user_group_membership.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_check_for_iam_user_group_membership.yaml @@ -1,13 +1,30 @@ +Description: Ensure that all Amazon IAM users have group memberships. ID: aws_check_for_iam_user_group_membership -Title: "Check for IAM User Group Membership" -Description: "Ensure that all Amazon IAM users have group memberships." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN groups is null THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN groups is null THEN name || ' does not belong to any IAM group.' \n ELSE name || ' belongs to at least one IAM group.'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_user\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN groups IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN groups IS NULL THEN name || ' does not belong to any IAM group.' + ELSE name || ' belongs to at least one IAM group.' + END AS reason, + region, + account_id + FROM + aws_iam_user Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Check for IAM User Group Membership \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_check_for_individual_iam_users.yaml b/compliance/controls/baseline/aws/IAM/aws_check_for_individual_iam_users.yaml old mode 100755 new mode 100644 index 79c4c337c..2807385cc --- a/compliance/controls/baseline/aws/IAM/aws_check_for_individual_iam_users.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_check_for_individual_iam_users.yaml @@ -1,14 +1,33 @@ +Description: Ensure there is at least one IAM user used to access your AWS cloud account. ID: aws_check_for_individual_iam_users -Title: "Check for Individual IAM Users" -Description: "Ensure there is at least one IAM user used to access your AWS cloud account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.account_id as resource,\n a.og_account_id,\n a.og_resource_id,\n case\n when user_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when u.user_id is null then a.account_id || ' account has no user'\n else a.account_id || ' account has user'\n end as reason,\n a.region, \n a.account_id\nfrom\n aws_account as a\n left join aws_iam_user as u on a.account_id = u.account_id\n" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_user Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + a.account_id AS resource, + a.og_account_id, + a.og_resource_id, + CASE + WHEN user_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN u.user_id IS NULL THEN a.account_id || ' account has no user' + ELSE a.account_id || ' account has user' + END AS reason, + a.region, + a.account_id + FROM + aws_account AS a + LEFT JOIN aws_iam_user AS u + ON a.account_id = u.account_id Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +38,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Check for Individual IAM Users \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_check_for_overly_permissive_iam_group_policies.yaml b/compliance/controls/baseline/aws/IAM/aws_check_for_overly_permissive_iam_group_policies.yaml old mode 100755 new mode 100644 index 2a8277c7d..65ca2e551 --- a/compliance/controls/baseline/aws/IAM/aws_check_for_overly_permissive_iam_group_policies.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_check_for_overly_permissive_iam_group_policies.yaml @@ -1,14 +1,71 @@ +Description: Ensure that Amazon IAM policies attached to IAM groups aren't too permissive. ID: aws_check_for_overly_permissive_iam_group_policies -Title: "Check for Overly Permissive IAM Group Policies" -Description: "Ensure that Amazon IAM policies attached to IAM groups aren't too permissive." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH too_permissive_policies AS (\n SELECT\n arn\n FROM\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'Action') AS action\n WHERE\n action IN ('*', '*:*')\n AND s ->> 'Effect' = 'Allow'\n)\n\nSELECT\n name AS resource,\n og_account_id,\n og_resource_id,\n CASE\n WHEN EXISTS(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as parn\n LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn where tp.arn is not null\n ) THEN 'alarm'\n WHEN EXISTS(\n SELECT 1 \n FROM jsonb_array_elements(inline_policies_std) AS p, jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'Action') AS action\n WHERE\n action IN ('*', '*:*')\n AND s ->> 'Effect' = 'Allow'\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as parn\n LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn where tp.arn is not null\n ) THEN ' there is too permissive attached policy'\n WHEN EXISTS(\n SELECT 1 \n FROM jsonb_array_elements(inline_policies_std) AS p, jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'Action') AS action\n WHERE\n action IN ('*', '*:*')\n AND s ->> 'Effect' = 'Allow'\n ) THEN ' there is too permissive inline policy'\n ELSE 'there is no too permissive policy'\n END AS reason,\n region, \n account_id\nFROM\n aws_iam_group AS g\n" - PrimaryTable: aws_iam_group ListOfTables: - aws_iam_group - aws_iam_policy Parameters: [] + PrimaryTable: aws_iam_group + QueryToExecute: | + WITH too_permissive_policies AS ( + SELECT + arn + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + action IN ('*', '*:*') + AND s ->> 'Effect' = 'Allow' + ) + + SELECT + name AS resource, + og_account_id, + og_resource_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS parn + LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn + WHERE tp.arn IS NOT NULL + ) THEN 'alarm' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(inline_policies_std) AS p, + jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + action IN ('*', '*:*') + AND s ->> 'Effect' = 'Allow' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS parn + LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn + WHERE tp.arn IS NOT NULL + ) THEN 'there is too permissive attached policy' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(inline_policies_std) AS p, + jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + action IN ('*', '*:*') + AND s ->> 'Effect' = 'Allow' + ) THEN 'there is too permissive inline policy' + ELSE 'there is no too permissive policy' + END AS reason, + region, + account_id + FROM + aws_iam_group AS g Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +76,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Check for Overly Permissive IAM Group Policies \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_check_for_untrusted_cross_account_iam_roles.yaml b/compliance/controls/baseline/aws/IAM/aws_check_for_untrusted_cross_account_iam_roles.yaml old mode 100755 new mode 100644 index ed334ef58..f2a7ad447 --- a/compliance/controls/baseline/aws/IAM/aws_check_for_untrusted_cross_account_iam_roles.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_check_for_untrusted_cross_account_iam_roles.yaml @@ -3,7 +3,41 @@ Title: "Check for Untrusted Cross-Account IAM Roles" Description: "Ensure that AWS IAM roles cannot be used by untrusted accounts via cross-account access feature." Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(assume_role_policy::jsonb -> 'Statement') as s\n WHERE (s ->> 'Effect') = 'Allow' and ((s ->> 'Principal')::text = '\"*\"' or\n (s ->> 'Principal')::text = '{\"AWS\": \"*\"}')\n ) THEN 'alarm'\n WHEN '{{.awsTrustedAccounts}}' = '' THEN 'ok'\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(assume_role_policy::jsonb -> 'Statement') as s\n WHERE (s ->> 'Effect') = 'Allow' and not('{{.awsTrustedAccounts}}' LIKE ('%'||((s -> 'Principal' ->> 'AWS')::text) || '%'))\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(assume_role_policy::jsonb -> 'Statement') as s\n WHERE (s ->> 'Effect') = 'Allow' and ((s ->> 'Principal')::text = '\"*\"' or\n (s ->> 'Principal')::text = '{\"AWS\": \"*\"}')\n ) THEN name || ' is publicly accessible' \n WHEN '{{.awsTrustedAccounts}}' = '' THEN 'trusted AWS accounts are not defined'\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(assume_role_policy::jsonb -> 'Statement') as s\n WHERE (s ->> 'Effect') = 'Allow' and not('{{.awsTrustedAccounts}}' LIKE ('%'||((s -> 'Principal' ->> 'AWS')::text) || '%'))\n ) THEN name || ' is not configured to allow access only to trusted AWS accounts'\n ELSE name || ' is configured to allow access only to trusted AWS accounts'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_role\n" + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 FROM JSONB_ARRAY_ELEMENTS(assume_role_policy::jsonb -> 'Statement') AS s + WHERE (s ->> 'Effect') = 'Allow' AND ((s ->> 'Principal')::text = '\"*\"' OR + (s ->> 'Principal')::text = '{"AWS": "*"}') + ) THEN 'alarm' + WHEN '{{.awsTrustedAccounts}}' = '' THEN 'ok' + WHEN EXISTS ( + SELECT 1 FROM JSONB_ARRAY_ELEMENTS(assume_role_policy::jsonb -> 'Statement') AS s + WHERE (s ->> 'Effect') = 'Allow' AND NOT('{{.awsTrustedAccounts}}' LIKE ('%' || ((s -> 'Principal' ->> 'AWS')::text) || '%')) + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 FROM JSONB_ARRAY_ELEMENTS(assume_role_policy::jsonb -> 'Statement') AS s + WHERE (s ->> 'Effect') = 'Allow' AND ((s ->> 'Principal')::text = '\"*\"' OR + (s ->> 'Principal')::text = '{"AWS": "*"}') + ) THEN name || ' is publicly accessible' + WHEN '{{.awsTrustedAccounts}}' = '' THEN 'trusted AWS accounts are not defined' + WHEN EXISTS ( + SELECT 1 FROM JSONB_ARRAY_ELEMENTS(assume_role_policy::jsonb -> 'Statement') AS s + WHERE (s ->> 'Effect') = 'Allow' AND NOT('{{.awsTrustedAccounts}}' LIKE ('%' || ((s -> 'Principal' ->> 'AWS')::text) || '%')) + ) THEN name || ' is not configured to allow access only to trusted AWS accounts' + ELSE name || ' is configured to allow access only to trusted AWS accounts' + END AS reason, + region, + account_id + FROM + aws_iam_role PrimaryTable: aws_iam_role ListOfTables: - aws_iam_role @@ -21,4 +55,4 @@ Tags: score_tags: - Problem Identities IntegrationType: - - aws_cloud_account + - aws_cloud_account \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_check_that_only_safelisted_iam_users_exist.yaml b/compliance/controls/baseline/aws/IAM/aws_check_that_only_safelisted_iam_users_exist.yaml old mode 100755 new mode 100644 index 1a29cd407..93d3033dd --- a/compliance/controls/baseline/aws/IAM/aws_check_that_only_safelisted_iam_users_exist.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_check_that_only_safelisted_iam_users_exist.yaml @@ -1,15 +1,32 @@ +Description: Ensure that only safelisted IAM Users exist within your AWS account. ID: aws_check_that_only_safelisted_iam_users_exist -Title: "Check that only safelisted IAM Users exist" -Description: "Ensure that only safelisted IAM Users exist within your AWS account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n name as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when '{{.awsApprovedIamUsers}}' LIKE '%' || name || '%' then 'ok'\n else 'alarm'\n end as status,\n case\n when '{{.awsApprovedIamUsers}}' LIKE '%' || name || '%' then name || ' user is approved'\n else name || ' user is not approved'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_user v\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: - Key: awsApprovedIamUsers Required: true + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + name AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN '{{.awsApprovedIamUsers}}' LIKE '%' || name || '%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN '{{.awsApprovedIamUsers}}' LIKE '%' || name || '%' THEN name || ' user is approved' + ELSE name || ' user is not approved' + END AS reason, + region, + account_id + FROM + aws_iam_user v Severity: high Tags: platform_score_cloud_service_name: @@ -20,5 +37,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Check that only safelisted IAM Users exist \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_credentials_last_used.yaml b/compliance/controls/baseline/aws/IAM/aws_credentials_last_used.yaml old mode 100755 new mode 100644 index 3c1dd2b7b..5a02267f0 --- a/compliance/controls/baseline/aws/IAM/aws_credentials_last_used.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_credentials_last_used.yaml @@ -1,13 +1,71 @@ +Description: Ensure that unused AWS IAM credentials are decommissioned to follow security best practices. ID: aws_credentials_last_used -Title: "Credentials Last Used" -Description: "Ensure that unused AWS IAM credentials are decommissioned to follow security best practices." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n user_name, \n og_account_id,\n og_resource_id,\n CASE \n WHEN not password_enabled::bool THEN 'skip'\n WHEN password_last_used < NOW() - INTERVAL '90 days' THEN 'alarm' \n ELSE 'ok'\n END AS status,\n CASE\n WHEN not password_enabled::bool THEN 'password is disabled'\n WHEN password_last_used < NOW() - INTERVAL '90 days' THEN 'the password is considered unused and its better to be removed'\n ELSE 'the password is being used'\n END AS reason,\n region, \n account_id\nFROM aws_iam_credential_report\n\nUNION ALL\n\nSELECT \n user_name, \n og_account_id,\n og_resource_id,\n CASE \n WHEN not access_key_1_active::bool THEN 'skip'\n WHEN access_key_1_last_used_date < NOW() - INTERVAL '90 days' THEN 'alarm' \n ELSE 'ok'\n END AS status,\n CASE\n WHEN not access_key_1_active::bool THEN 'access key 1 is disabled'\n WHEN access_key_1_last_used_date < NOW() - INTERVAL '90 days' THEN 'access key 1 is considered unused and its better to be removed'\n ELSE 'access key 1 is being used'\n END AS reason,\n region, \n account_id\nFROM aws_iam_credential_report\n\nUNION ALL\n\nSELECT \n user_name, \n og_account_id,\n og_resource_id,\n CASE \n WHEN not access_key_2_active::bool THEN 'skip'\n WHEN access_key_2_last_used_date < NOW() - INTERVAL '90 days' THEN 'alarm' \n ELSE 'ok'\n END AS status,\n CASE\n WHEN not access_key_2_active::bool THEN 'access key 2 is disabled'\n WHEN access_key_2_last_used_date < NOW() - INTERVAL '90 days' THEN 'access key 2 is considered unused and its better to be removed'\n ELSE 'access key 2 is being used'\n END AS reason,\n region, \n account_id\nFROM aws_iam_credential_report;\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + user_name, + og_account_id, + og_resource_id, + CASE + WHEN NOT password_enabled::bool THEN 'skip' + WHEN password_last_used < NOW() - INTERVAL '90 days' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled::bool THEN 'password is disabled' + WHEN password_last_used < NOW() - INTERVAL '90 days' THEN 'the password is considered unused and its better to be removed' + ELSE 'the password is being used' + END AS reason, + region, + account_id + FROM aws_iam_credential_report + + UNION ALL + + SELECT + user_name, + og_account_id, + og_resource_id, + CASE + WHEN NOT access_key_1_active::bool THEN 'skip' + WHEN access_key_1_last_used_date < NOW() - INTERVAL '90 days' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT access_key_1_active::bool THEN 'access key 1 is disabled' + WHEN access_key_1_last_used_date < NOW() - INTERVAL '90 days' THEN 'access key 1 is considered unused and its better to be removed' + ELSE 'access key 1 is being used' + END AS reason, + region, + account_id + FROM aws_iam_credential_report + + UNION ALL + + SELECT + user_name, + og_account_id, + og_resource_id, + CASE + WHEN NOT access_key_2_active::bool THEN 'skip' + WHEN access_key_2_last_used_date < NOW() - INTERVAL '90 days' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT access_key_2_active::bool THEN 'access key 2 is disabled' + WHEN access_key_2_last_used_date < NOW() - INTERVAL '90 days' THEN 'access key 2 is considered unused and its better to be removed' + ELSE 'access key 2 is being used' + END AS reason, + region, + account_id + FROM aws_iam_credential_report; Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +76,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Insecure Keys -IntegrationType: - - aws_cloud_account +Title: Credentials Last Used \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_cross_account_access_lacks_external_id_and_mfa.yaml b/compliance/controls/baseline/aws/IAM/aws_cross_account_access_lacks_external_id_and_mfa.yaml old mode 100755 new mode 100644 index ba3fc0ad8..a35bd7956 --- a/compliance/controls/baseline/aws/IAM/aws_cross_account_access_lacks_external_id_and_mfa.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_cross_account_access_lacks_external_id_and_mfa.yaml @@ -1,32 +1,37 @@ +Description: Ensure cross-account access roles are using Multi-Factor Authentication (MFA) or External IDs. ID: aws_cross_account_access_lacks_external_id_and_mfa -Title: "Cross-Account Access Lacks External ID and MFA" -Description: "Ensure cross-account access roles are using Multi-Factor Authentication (MFA) or External IDs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_iam_role + Parameters: [] + PrimaryTable: aws_iam_role QueryToExecute: | - select - r.arn as resource, + SELECT + r.arn AS resource, r.og_account_id, r.og_resource_id, - case - when (s -> 'Principal' ->>'AWS') is null or not((s -> 'Principal' ->>'AWS') ~ '^arn:aws:iam::[0-9]+:root$') then 'pass' - when ((s ->> 'Condition') LIKE '%aws:MultiFactorAuthPresent%') or ((s ->> 'Condition') LIKE '%sts:ExternalId%') then 'ok' - else 'alarm' - end as status, - case - when (s -> 'Principal' ->>'AWS') is null or not((s -> 'Principal' ->>'AWS') ~ '^arn:aws:iam::[0-9]+:root$') then r.title || 'cross-account access not enabled.' - when ((s ->> 'Condition') LIKE '%aws:MultiFactorAuthPresent%') or ((s ->> 'Condition') LIKE '%sts:ExternalId%') then 'MFA enabled for cross-account access' - else r.title || 'MFA not enabled for cross-account access' - end as reason, + CASE + WHEN (s -> 'Principal' ->> 'AWS') IS NULL + OR NOT ((s -> 'Principal' ->> 'AWS') ~ '^arn:aws:iam::[0-9]+:root$') THEN 'pass' + WHEN ((s ->> 'Condition') LIKE '%aws:MultiFactorAuthPresent%') + OR ((s ->> 'Condition') LIKE '%sts:ExternalId%') THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (s -> 'Principal' ->> 'AWS') IS NULL + OR NOT ((s -> 'Principal' ->> 'AWS') ~ '^arn:aws:iam::[0-9]+:root$') THEN r.title || ' cross-account access not enabled.' + WHEN ((s ->> 'Condition') LIKE '%aws:MultiFactorAuthPresent%') + OR ((s ->> 'Condition') LIKE '%sts:ExternalId%') THEN 'MFA enabled for cross-account access' + ELSE r.title || ' MFA not enabled for cross-account access' + END AS reason, region, account_id - from - aws_iam_role as r, - jsonb_array_elements(assume_role_policy -> 'Statement') as s - PrimaryTable: aws_iam_role - ListOfTables: - - aws_iam_role - Parameters: [] + FROM + aws_iam_role AS r, + jsonb_array_elements(assume_role_policy -> 'Statement') AS s Severity: medium Tags: platform_score_cloud_service_name: @@ -37,5 +42,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Cross-Account Access Lacks External ID and MFA \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_ec2_purchase_restriction.yaml b/compliance/controls/baseline/aws/IAM/aws_ec2_purchase_restriction.yaml old mode 100755 new mode 100644 index 333371fc2..92c8588fe --- a/compliance/controls/baseline/aws/IAM/aws_ec2_purchase_restriction.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_ec2_purchase_restriction.yaml @@ -1,21 +1,80 @@ +Description: Restrict unintended IAM users from purchasing Amazon EC2 Reserved Instances and/or Savings Plans. ID: aws_ec2_purchase_restriction -Title: "Amazon EC2 Purchase Restriction" -Description: "Restrict unintended IAM users from purchasing Amazon EC2 Reserved Instances and/or Savings Plans." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH too_permissive_policies AS (\n SELECT\n arn\n FROM\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'Action') AS action\n WHERE\n action IN ('ec2:PurchaseReservedInstancesOffering', 'savingsplans:CreateSavingsPlan')\n)\n\nSELECT\n name AS resource,\n og_account_id,\n og_resource_id,\n CASE\n WHEN EXISTS(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as parn\n LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn where tp.arn is not null\n ) and '{{.awsAllowedUsersPurchaseEc2}}' not like '%' || name || '%' THEN 'alarm'\n WHEN EXISTS(\n SELECT 1 \n FROM jsonb_array_elements(inline_policies_std) AS p, jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'Action') AS action\n WHERE\n action IN ('ec2:PurchaseReservedInstancesOffering', 'savingsplans:CreateSavingsPlan')\n AND s ->> 'Effect' = 'Allow'\n ) and '{{.awsAllowedUsersPurchaseEc2}}' not like '%' || name || '%' THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as parn\n LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn where tp.arn is not null\n ) and '{{.awsAllowedUsersPurchaseEc2}}' not like '%' || name || '%' THEN 'User has access to purchase ec2 but is not in your organization allowed list'\n WHEN EXISTS(\n SELECT 1 \n FROM jsonb_array_elements(inline_policies_std) AS p, jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'Action') AS action\n WHERE\n action IN ('ec2:PurchaseReservedInstancesOffering', 'savingsplans:CreateSavingsPlan')\n AND s ->> 'Effect' = 'Allow'\n ) and '{{.awsAllowedUsersPurchaseEc2}}' not like '%' || name || '%' THEN 'User has access to purchase ec2 but is not in your organization allowed list'\n ELSE 'User either not have the access to purchase ec2 or is in the allowed list'\n END AS reason,\n region, \n account_id\nFROM\n aws_iam_user\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_policy - aws_iam_user Parameters: - Key: awsAllowedUsersPurchaseEc2 Required: true + PrimaryTable: aws_iam_user + QueryToExecute: | + WITH too_permissive_policies AS ( + SELECT + arn + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + action IN ('ec2:PurchaseReservedInstancesOffering', 'savingsplans:CreateSavingsPlan') + ) + + SELECT + name AS resource, + og_account_id, + og_resource_id, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS parn + LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn + WHERE tp.arn IS NOT NULL + ) + AND '{{.awsAllowedUsersPurchaseEc2}}' NOT LIKE '%' || name || '%' THEN 'alarm' + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements(inline_policies_std) AS p, + jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + action IN ('ec2:PurchaseReservedInstancesOffering', 'savingsplans:CreateSavingsPlan') + AND s ->> 'Effect' = 'Allow' + ) + AND '{{.awsAllowedUsersPurchaseEc2}}' NOT LIKE '%' || name || '%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS parn + LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn + WHERE tp.arn IS NOT NULL + ) + AND '{{.awsAllowedUsersPurchaseEc2}}' NOT LIKE '%' || name || '%' THEN 'User has access to purchase EC2 but is not in your organization allowed list' + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements(inline_policies_std) AS p, + jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + action IN ('ec2:PurchaseReservedInstancesOffering', 'savingsplans:CreateSavingsPlan') + AND s ->> 'Effect' = 'Allow' + ) + AND '{{.awsAllowedUsersPurchaseEc2}}' NOT LIKE '%' || name || '%' THEN 'User has access to purchase EC2 but is not in your organization allowed list' + ELSE 'User either does not have access to purchase EC2 or is in the allowed list' + END AS reason, + region, + account_id + FROM + aws_iam_user Severity: medium Tags: platform_score_cloud_service_name: - AWS Identity and Access Management (IAM) score_service_name: - AWS Identity and Access Management (IAM) -IntegrationType: - - aws_cloud_account +Title: Amazon EC2 Purchase Restriction \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_enable_mfa_for_iam_users_with_console_password.yaml b/compliance/controls/baseline/aws/IAM/aws_enable_mfa_for_iam_users_with_console_password.yaml old mode 100755 new mode 100644 index af85d9ef8..453f8a6d3 --- a/compliance/controls/baseline/aws/IAM/aws_enable_mfa_for_iam_users_with_console_password.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_enable_mfa_for_iam_users_with_console_password.yaml @@ -1,13 +1,30 @@ +Description: Ensure that Multi-Factor Authentication (MFA) is enabled for all Amazon IAM users with console access. ID: aws_enable_mfa_for_iam_users_with_console_password -Title: "Enable MFA for IAM Users with Console Password" -Description: "Ensure that Multi-Factor Authentication (MFA) is enabled for all Amazon IAM users with console access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN mfa_enabled = false or mfa_devices is null THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN mfa_enabled = false or mfa_devices is null THEN name || ' is not MFA-protected.' \n ELSE name || ' is MFA-protected.'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_user\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN mfa_enabled = FALSE OR mfa_devices IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN mfa_enabled = FALSE OR mfa_devices IS NULL THEN name || ' is not MFA-protected.' + ELSE name || ' is MFA-protected.' + END AS reason, + region, + account_id + FROM + aws_iam_user Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Enable MFA for IAM Users with Console Password \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_enforce_infrastructure_as_code_using_iam_policies.yaml b/compliance/controls/baseline/aws/IAM/aws_enforce_infrastructure_as_code_using_iam_policies.yaml old mode 100755 new mode 100644 index 10e4bec2f..ef8275fbd --- a/compliance/controls/baseline/aws/IAM/aws_enforce_infrastructure_as_code_using_iam_policies.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_enforce_infrastructure_as_code_using_iam_policies.yaml @@ -1,19 +1,80 @@ +Description: Enforce Infrastructure as Code by controlling access for requests made on your behalf. ID: aws_enforce_infrastructure_as_code_using_iam_policies -Title: "Enforce Infrastructure as Code using IAM Policies" -Description: "Enforce Infrastructure as Code by controlling access for requests made on your behalf." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH too_permissive_policies AS (\n SELECT\n arn\n FROM\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'NotAction') AS notAction\n WHERE\n notAction IN ('cloudformation:*')\n AND s ->> 'Effect' = 'Deny'\n AND (s -> 'Condition' -> 'StringNotEquals' ->> 'aws:CalledViaFirst') = 'cloudformation.amazonaws.com'\n)\n\nSELECT\n name AS resource,\n og_account_id,\n og_resource_id,\n CASE\n WHEN EXISTS(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as parn\n LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn where tp.arn is not null\n ) THEN 'ok'\n WHEN EXISTS(\n SELECT 1 \n FROM jsonb_array_elements(inline_policies_std) AS p, jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'NotAction') AS notAction\n WHERE\n notAction IN ('cloudformation:*')\n AND s ->> 'Effect' = 'Deny'\n AND (s -> 'Condition' -> 'StringNotEquals' ->> 'aws:CalledViaFirst') = 'cloudformation.amazonaws.com'\n ) THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN EXISTS(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as parn\n LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn where tp.arn is not null\n ) THEN 'IAM user is forced to deploy AWS resources via CloudFormation only'\n WHEN EXISTS(\n SELECT 1 \n FROM jsonb_array_elements(inline_policies_std) AS p, jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'NotAction') AS notAction\n WHERE\n notAction IN ('cloudformation:*')\n AND s ->> 'Effect' = 'Deny'\n AND (s -> 'Condition' -> 'StringNotEquals' ->> 'aws:CalledViaFirst') = 'cloudformation.amazonaws.com'\n ) THEN 'IAM user is forced to deploy AWS resources via CloudFormation only'\n ELSE 'IAM user is not forced to deploy AWS resources via CloudFormation only'\n END AS reason,\n region, \n account_id\nFROM\n aws_iam_user AS g\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_policy - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + WITH too_permissive_policies AS ( + SELECT + arn + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'NotAction') AS notAction + WHERE + notAction IN ('cloudformation:*') + AND s ->> 'Effect' = 'Deny' + AND (s -> 'Condition' -> 'StringNotEquals' ->> 'aws:CalledViaFirst') = 'cloudformation.amazonaws.com' + ) + + SELECT + name AS resource, + og_account_id, + og_resource_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS parn + LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn + WHERE tp.arn IS NOT NULL + ) + THEN 'ok' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(inline_policies_std) AS p, jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'NotAction') AS notAction + WHERE + notAction IN ('cloudformation:*') + AND s ->> 'Effect' = 'Deny' + AND (s -> 'Condition' -> 'StringNotEquals' ->> 'aws:CalledViaFirst') = 'cloudformation.amazonaws.com' + ) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS parn + LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn + WHERE tp.arn IS NOT NULL + ) + THEN 'IAM user is forced to deploy AWS resources via CloudFormation only' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(inline_policies_std) AS p, jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'NotAction') AS notAction + WHERE + notAction IN ('cloudformation:*') + AND s ->> 'Effect' = 'Deny' + AND (s -> 'Condition' -> 'StringNotEquals' ->> 'aws:CalledViaFirst') = 'cloudformation.amazonaws.com' + ) + THEN 'IAM user is forced to deploy AWS resources via CloudFormation only' + ELSE 'IAM user is not forced to deploy AWS resources via CloudFormation only' + END AS reason, + region, + account_id + FROM + aws_iam_user AS g Severity: medium Tags: platform_score_cloud_service_name: - AWS Identity and Access Management (IAM) score_service_name: - AWS Identity and Access Management (IAM) -IntegrationType: - - aws_cloud_account +Title: Enforce Infrastructure as Code using IAM Policies \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_expired_ssl_tls_certificate.yaml b/compliance/controls/baseline/aws/IAM/aws_expired_ssl_tls_certificate.yaml old mode 100755 new mode 100644 index 77f8ffc6c..e30f6cf19 --- a/compliance/controls/baseline/aws/IAM/aws_expired_ssl_tls_certificate.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_expired_ssl_tls_certificate.yaml @@ -1,13 +1,30 @@ +Description: Ensure expired SSL/TLS certificates are removed from AWS IAM. ID: aws_expired_ssl_tls_certificate -Title: "Expired SSL/TLS Certificate" -Description: "Ensure expired SSL/TLS certificates are removed from AWS IAM." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN expiration < now() THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN expiration < now() THEN 'certificate has been expired'\n ELSE 'certificate is not expired'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_server_certificate\n" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: [] + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN expiration < NOW() THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expiration < NOW() THEN 'certificate has been expired' + ELSE 'certificate is not expired' + END AS reason, + region, + account_id + FROM + aws_iam_server_certificate Severity: low Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Expiring Certificates -IntegrationType: - - aws_cloud_account +Title: Expired SSL/TLS Certificate \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_hardware_mfa_for_aws_root_account.yaml b/compliance/controls/baseline/aws/IAM/aws_hardware_mfa_for_aws_root_account.yaml old mode 100755 new mode 100644 index f35929c7c..ae538500e --- a/compliance/controls/baseline/aws/IAM/aws_hardware_mfa_for_aws_root_account.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_hardware_mfa_for_aws_root_account.yaml @@ -1,14 +1,37 @@ +Description: Ensure hardware MFA is enabled for the 'root' account. ID: aws_hardware_mfa_for_aws_root_account -Title: "Hardware MFA for AWS Root Account" -Description: "Ensure hardware MFA is enabled for the 'root' account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n (r.user_name || ' in account ' || r.account_id) as resource,\n r.og_account_id,\n r.og_resource_id,\n case\n when not r.mfa_active::bool then 'alarm'\n when m.serial_number is not null then 'alarm'\n else 'ok'\n end as status,\n case\n when not r.mfa_active::bool then 'mfa is not activated'\n when m.serial_number is not null then 'user is using virtual mfa'\n else 'user is using hardware mfs'\n end as reason,\n r.region, \n r.account_id\nfrom\n aws_iam_credential_report as r\n left join aws_iam_virtual_mfa_device as m on (m.user -> 'Arn')::text = r.user_arn\nwhere\n r.user_name = ''\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report - aws_iam_virtual_mfa_device Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + (r.user_name || ' in account ' || r.account_id) AS resource, + r.og_account_id, + r.og_resource_id, + CASE + WHEN NOT r.mfa_active::bool THEN 'alarm' + WHEN m.serial_number IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT r.mfa_active::bool THEN 'mfa is not activated' + WHEN m.serial_number IS NOT NULL THEN 'user is using virtual mfa' + ELSE 'user is using hardware mfa' + END AS reason, + r.region, + r.account_id + FROM + aws_iam_credential_report AS r + LEFT JOIN aws_iam_virtual_mfa_device AS m + ON (m.user -> 'Arn')::text = r.user_arn + WHERE + r.user_name = '' Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +42,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Hardware MFA for AWS Root Account \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_access_analyzer_findings.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_access_analyzer_findings.yaml old mode 100755 new mode 100644 index f47d5f15c..66e1ced6f --- a/compliance/controls/baseline/aws/IAM/aws_iam_access_analyzer_findings.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_access_analyzer_findings.yaml @@ -1,13 +1,38 @@ +Description: Ensure that IAM Access Analyzer findings are reviewed and resolved to maintain access security to your AWS resources. ID: aws_iam_access_analyzer_findings -Title: "IAM Access Analyzer Findings" -Description: "Ensure that IAM Access Analyzer findings are reviewed and resolved to maintain access security to your AWS resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.name as resource,\n a.og_account_id,\n a.og_resource_id,\n case\n when exists (\n select 1 from jsonb_array_elements(findings) as f where (f ->> 'Status') = 'ACTIVE'\n ) then 'alarm'\n else 'ok'\n end as status,\n case\n when exists (\n select 1 from jsonb_array_elements(findings) as f where (f ->> 'Status') = 'ACTIVE'\n ) then 'There are unresolved findings in this analyzer'\n else 'There is no unresolved findings in this analyzer'\n end as reason,\n a.region, \n a.account_id\nfrom\n aws_accessanalyzer_analyzer as a\n" - PrimaryTable: aws_accessanalyzer_analyzer ListOfTables: - aws_accessanalyzer_analyzer Parameters: [] + PrimaryTable: aws_accessanalyzer_analyzer + QueryToExecute: | + SELECT + a.name AS resource, + a.og_account_id, + a.og_resource_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(findings) AS f + WHERE (f ->> 'Status') = 'ACTIVE' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(findings) AS f + WHERE (f ->> 'Status') = 'ACTIVE' + ) THEN 'There are unresolved findings in this analyzer' + ELSE 'There is no unresolved findings in this analyzer' + END AS reason, + a.region, + a.account_id + FROM + aws_accessanalyzer_analyzer AS a Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +43,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Access Analyzer Findings \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_access_analyzer_in_use.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_access_analyzer_in_use.yaml old mode 100755 new mode 100644 index dfc415f8b..8e79af02c --- a/compliance/controls/baseline/aws/IAM/aws_iam_access_analyzer_in_use.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_access_analyzer_in_use.yaml @@ -1,14 +1,41 @@ +Description: Ensure that IAM Access Analyzer feature is enabled to maintain access security to your AWS resources. ID: aws_iam_access_analyzer_in_use -Title: "IAM Access Analyzer in Use" -Description: "Ensure that IAM Access Analyzer feature is enabled to maintain access security to your AWS resources." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.account_id as resource,\n a.og_account_id,\n a.og_resource_id,\n case\n when exists (\n select 1 from aws_accessanalyzer_analyzer as an where a.account_id = an.account_id limit 1\n ) then 'ok'\n else 'alarm'\n end as status,\n case\n when exists (\n select 1 from aws_accessanalyzer_analyzer as an where a.account_id = an.account_id limit 1\n ) then 'Amazon IAM Access Analyzer feature is used to protect your cloud resources'\n else 'There are no access analyzers available on this account'\n end as reason,\n a.region, \n a.account_id\nfrom\n aws_account as a\n" - PrimaryTable: aws_account ListOfTables: - aws_accessanalyzer_analyzer - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + a.account_id AS resource, + a.og_account_id, + a.og_resource_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM aws_accessanalyzer_analyzer AS an + WHERE a.account_id = an.account_id + LIMIT 1 + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM aws_accessanalyzer_analyzer AS an + WHERE a.account_id = an.account_id + LIMIT 1 + ) THEN 'Amazon IAM Access Analyzer feature is used to protect your cloud resources' + ELSE 'There are no access analyzers available on this account' + END AS reason, + a.region, + a.account_id + FROM + aws_account AS a Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +46,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Access Analyzer in Use \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_group_with_inline_policies.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_group_with_inline_policies.yaml old mode 100755 new mode 100644 index 9e5cfe0c3..d33a455f0 --- a/compliance/controls/baseline/aws/IAM/aws_iam_group_with_inline_policies.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_group_with_inline_policies.yaml @@ -1,13 +1,30 @@ +Description: Ensure IAM groups don't have inline policies attached. ID: aws_iam_group_with_inline_policies -Title: "IAM Group With Inline Policies" -Description: "Ensure IAM groups don't have inline policies attached." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n name as resource,\n og_account_id,\n og_resource_id,\n case\n when inline_policies is null then 'ok'\n else 'alarm'\n end as status,\n case\n when inline_policies is null then name || ' is not using inline policies'\n else name || ' is using inline policies'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_group\n" - PrimaryTable: aws_iam_group ListOfTables: - aws_iam_group Parameters: [] + PrimaryTable: aws_iam_group + QueryToExecute: | + SELECT + name AS resource, + og_account_id, + og_resource_id, + CASE + WHEN inline_policies IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN inline_policies IS NULL THEN name || ' is not using inline policies' + ELSE name || ' is using inline policies' + END AS reason, + region, + account_id + FROM + aws_iam_group Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Group With Inline Policies \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_groups_with_administrative_privileges.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_groups_with_administrative_privileges.yaml old mode 100755 new mode 100644 index 35f750489..34c329008 --- a/compliance/controls/baseline/aws/IAM/aws_iam_groups_with_administrative_privileges.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_groups_with_administrative_privileges.yaml @@ -1,13 +1,30 @@ +Description: Ensure there are no IAM groups with administrative permissions available in your AWS cloud account. ID: aws_iam_groups_with_administrative_privileges -Title: "IAM Groups with Administrative Privileges" -Description: "Ensure there are no IAM groups with administrative permissions available in your AWS cloud account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id,\n og_resource_id,\n case\n when attached_policy_arns::text like '%arn:aws:iam::aws:policy/AdministratorAccess%' then 'alarm'\n else 'ok'\n end as status,\n case\n when attached_policy_arns::text like '%arn:aws:iam::aws:policy/AdministratorAccess%' then name || ' iam group has AWS administrator-level permissions'\n else name || ' iam group does not have AWS administrator-level permissions'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_group\n" - PrimaryTable: aws_iam_group ListOfTables: - aws_iam_group Parameters: [] + PrimaryTable: aws_iam_group + QueryToExecute: | + SELECT + arn AS resource, + og_account_id, + og_resource_id, + CASE + WHEN attached_policy_arns::text LIKE '%arn:aws:iam::aws:policy/AdministratorAccess%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN attached_policy_arns::text LIKE '%arn:aws:iam::aws:policy/AdministratorAccess%' THEN name || ' IAM group has AWS administrator-level permissions' + ELSE name || ' IAM group does not have AWS administrator-level permissions' + END AS reason, + region, + account_id + FROM + aws_iam_group Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Groups with Administrative Privileges \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_password_policy.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_password_policy.yaml old mode 100755 new mode 100644 index 6d4b32cf3..4829793bf --- a/compliance/controls/baseline/aws/IAM/aws_iam_password_policy.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_password_policy.yaml @@ -1,14 +1,35 @@ +Description: Ensure that your AWS cloud account has a strong IAM password policy in use. ID: aws_iam_password_policy -Title: "IAM Password Policy" -Description: "Ensure that your AWS cloud account has a strong IAM password policy in use." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.account_id as resource,\n a.og_account_id as og_account_id,\n a.og_resource_id as og_resource_id,\n case\n when p.account_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when p.account_id is null then a.account_id || ' is not configured with a custom IAM password policy'\n else a.account_id || ' is configured with a custom IAM password policy'\n end as reason,\n a.region, \n a.account_id\nfrom\n aws_account a\n left join aws_iam_account_password_policy as p on p.account_id = a.account_id\n" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_account_password_policy Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + a.account_id AS resource, + a.og_account_id AS og_account_id, + a.og_resource_id AS og_resource_id, + CASE + WHEN p.account_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN p.account_id IS NULL THEN a.account_id || ' is not configured with a custom IAM password policy' + ELSE a.account_id || ' is configured with a custom IAM password policy' + END AS reason, + a.region, + a.account_id + FROM + aws_account a + LEFT JOIN + aws_iam_account_password_policy AS p + ON + p.account_id = a.account_id Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +40,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Password Policy \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_policies_with_effect_set_to_allow_and_notaction.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_policies_with_effect_set_to_allow_and_notaction.yaml old mode 100755 new mode 100644 index 3cce9e1f0..86d3b0c2f --- a/compliance/controls/baseline/aws/IAM/aws_iam_policies_with_effect_set_to_allow_and_notaction.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_policies_with_effect_set_to_allow_and_notaction.yaml @@ -1,13 +1,31 @@ +Description: Ensure that IAM policies do not use "Allow" in combination with "NotAction" element to follow IAM security best practices. ID: aws_iam_policies_with_effect_set_to_allow_and_notaction -Title: "IAM Policies with Effect set to Allow and NotAction" -Description: "Ensure that IAM policies do not use \"Allow\" in combination with \"NotAction\" element to follow IAM security best practices." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n name as resource,\n og_account_id,\n og_resource_id,\n case\n when (s -> 'NotAction' is not null and s ->> 'Effect' = 'Allow') then 'alarm'\n else 'ok'\n end as status,\n case\n when (s -> 'NotAction' is not null and s ->> 'Effect' = 'Allow') then name || ' has allowed nonAction policy'\n else name || ' does not have allowed nonAction policy'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') as s\n" - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_policy Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + SELECT + name AS resource, + og_account_id, + og_resource_id, + CASE + WHEN (s -> 'NotAction' IS NOT NULL AND s ->> 'Effect' = 'Allow') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (s -> 'NotAction' IS NOT NULL AND s ->> 'Effect' = 'Allow') THEN name || ' has allowed nonAction policy' + ELSE name || ' does not have allowed nonAction policy' + END AS reason, + region, + account_id + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS s Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +36,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Policies with Effect set to Allow and NotAction \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_policies_with_full_administrative_privileges.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_policies_with_full_administrative_privileges.yaml old mode 100755 new mode 100644 index a054034aa..ba0ba6b3b --- a/compliance/controls/baseline/aws/IAM/aws_iam_policies_with_full_administrative_privileges.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_policies_with_full_administrative_privileges.yaml @@ -1,13 +1,45 @@ +Description: Ensure IAM policies that allow full '*:*' administrative privileges aren't created. ID: aws_iam_policies_with_full_administrative_privileges -Title: "IAM Policies With Full Administrative Privileges" -Description: "Ensure IAM policies that allow full '*:*' administrative privileges aren't created." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id,\n og_resource_id,\n case\n when exists(select 1 from jsonb_array_elements_text(stmt -> 'Action') as a where a = '*') and stmt ->> 'Effect' = 'Allow' and stmt ->> 'Resource' = '[\"*\"]' then 'alarm'\n else 'ok'\n end as status,\n case\n when exists(select 1 from jsonb_array_elements_text(stmt -> 'Action') as a where a = '*') and stmt ->> 'Effect' = 'Allow' and stmt ->> 'Resource' = '[\"*\"]' then 'policy allows full administrative privileges'\n else 'policy does not allow full administrative privileges'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_policy as p,\n jsonb_array_elements(p.policy_std -> 'Statement') as stmt\n" - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_policy Parameters: [] + PrimaryTable: aws_iam_policy + QueryToExecute: | + SELECT + arn AS resource, + og_account_id, + og_resource_id, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements_text(stmt -> 'Action') AS a + WHERE a = '*' + ) + AND stmt ->> 'Effect' = 'Allow' + AND stmt ->> 'Resource' = '[\"*\"]' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements_text(stmt -> 'Action') AS a + WHERE a = '*' + ) + AND stmt ->> 'Effect' = 'Allow' + AND stmt ->> 'Resource' = '[\"*\"]' + THEN 'policy allows full administrative privileges' + ELSE 'policy does not allow full administrative privileges' + END AS reason, + region, + account_id + FROM + aws_iam_policy AS p, + jsonb_array_elements(p.policy_std -> 'Statement') AS stmt Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +50,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Policies With Full Administrative Privileges \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_role_policy_too_permissive.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_role_policy_too_permissive.yaml old mode 100755 new mode 100644 index c3eb04a34..ce5a79a38 --- a/compliance/controls/baseline/aws/IAM/aws_iam_role_policy_too_permissive.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_role_policy_too_permissive.yaml @@ -1,14 +1,71 @@ +Description: Ensure that the access policies attached to your IAM roles adhere to the principle of least privilege. ID: aws_iam_role_policy_too_permissive -Title: "IAM Role Policy Too Permissive" -Description: "Ensure that the access policies attached to your IAM roles adhere to the principle of least privilege." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH too_permissive_policies AS (\n SELECT\n arn\n FROM\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'Action') AS action\n WHERE\n action IN ('*', '*:*')\n AND s ->> 'Effect' = 'Allow'\n)\n\nSELECT\n name AS resource,\n og_account_id,\n og_resource_id,\n CASE\n WHEN EXISTS(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as parn\n LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn where tp.arn is not null\n ) THEN 'alarm'\n WHEN EXISTS(\n SELECT 1 \n FROM jsonb_array_elements(inline_policies_std) AS p, jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'Action') AS action\n WHERE\n action IN ('*', '*:*')\n AND s ->> 'Effect' = 'Allow'\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as parn\n LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn where tp.arn is not null\n ) THEN ' there is too permissive attached policy'\n WHEN EXISTS(\n SELECT 1 \n FROM jsonb_array_elements(inline_policies_std) AS p, jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s,\n jsonb_array_elements_text(s -> 'Action') AS action\n WHERE\n action IN ('*', '*:*')\n AND s ->> 'Effect' = 'Allow'\n ) THEN ' there is too permissive inline policy'\n ELSE 'there is no too permissive policy'\n END AS reason,\n region, \n account_id\nFROM\n aws_iam_role AS r\n" - PrimaryTable: aws_iam_role ListOfTables: - aws_iam_policy - aws_iam_role Parameters: [] + PrimaryTable: aws_iam_role + QueryToExecute: | + WITH too_permissive_policies AS ( + SELECT + arn + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + action IN ('*', '*:*') + AND s ->> 'Effect' = 'Allow' + ) + + SELECT + name AS resource, + og_account_id, + og_resource_id, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS parn + LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn + WHERE tp.arn IS NOT NULL + ) THEN 'alarm' + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements(inline_policies_std) AS p, + jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + action IN ('*', '*:*') + AND s ->> 'Effect' = 'Allow' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS parn + LEFT JOIN too_permissive_policies AS tp ON parn = tp.arn + WHERE tp.arn IS NOT NULL + ) THEN 'there is too permissive attached policy' + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements(inline_policies_std) AS p, + jsonb_array_elements(p -> 'PolicyDocument' -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + action IN ('*', '*:*') + AND s ->> 'Effect' = 'Allow' + ) THEN 'there is too permissive inline policy' + ELSE 'there is no too permissive policy' + END AS reason, + region, + account_id + FROM + aws_iam_role AS r Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +76,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Role Policy Too Permissive \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_server_certificate_size.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_server_certificate_size.yaml old mode 100755 new mode 100644 index 6711ff762..3cdf9877b --- a/compliance/controls/baseline/aws/IAM/aws_iam_server_certificate_size.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_server_certificate_size.yaml @@ -1,18 +1,34 @@ +Description: Ensure that all your SSL/TLS certificates are using either 2048 or 4096 bit RSA keys instead of 1024-bit keys. ID: aws_iam_server_certificate_size -Title: "AWS IAM Server Certificate Size" -Description: "Ensure that all your SSL/TLS certificates are using either 2048 or 4096 bit RSA keys instead of 1024-bit keys." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN certificate_body_length < 2048 THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN certificate_body_length < 2048 THEN 'The key length is 1024 therefore it is insecure' \n ELSE 'Key is secure.'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_server_certificate\n" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: [] + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN certificate_body_length < 2048 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN certificate_body_length < 2048 THEN 'The key length is 1024 therefore it is insecure' + ELSE 'Key is secure.' + END AS reason, + region, + account_id + FROM + aws_iam_server_certificate Severity: medium Tags: platform_score_cloud_service_name: - AWS Identity and Access Management (IAM) score_service_name: - AWS Identity and Access Management (IAM) -IntegrationType: - - aws_cloud_account +Title: AWS IAM Server Certificate Size \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_support_role.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_support_role.yaml old mode 100755 new mode 100644 index bb7665e5d..5837ae7b9 --- a/compliance/controls/baseline/aws/IAM/aws_iam_support_role.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_support_role.yaml @@ -1,15 +1,43 @@ +Description: Ensure there is an active IAM Support Role available within your AWS cloud account. ID: aws_iam_support_role -Title: "IAM Support Role" -Description: "Ensure there is an active IAM Support Role available within your AWS cloud account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with aws_support_access_roles as (\n select \n arn,\n account_id \n from \n aws_iam_role \n where \n attached_policy_arns::text ilike '%arn:aws:iam::aws:policy/AWSSupportAccess%'\n)\n\nselect\n a.account_id as resource,\n a.og_account_id,\n a.og_resource_id,\n case\n when r.arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when r.arn is null then 'there is no AWS Support Access role for this account'\n else 'this account has AWS Support Access role'\n end as reason,\n a.region, \n a.account_id\nfrom\n aws_account as a\n left join aws_support_access_roles as r on a.account_id = r.account_id\n" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_iam_role - aws_support_access_roles Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + WITH aws_support_access_roles AS ( + SELECT + arn, + account_id + FROM + aws_iam_role + WHERE + attached_policy_arns::TEXT ILIKE '%arn:aws:iam::aws:policy/AWSSupportAccess%' + ) + + SELECT + a.account_id AS resource, + a.og_account_id, + a.og_resource_id, + CASE + WHEN r.arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN r.arn IS NULL THEN 'there is no AWS Support Access role for this account' + ELSE 'this account has AWS Support Access role' + END AS reason, + a.region, + a.account_id + FROM + aws_account AS a + LEFT JOIN aws_support_access_roles AS r ON a.account_id = r.account_id Severity: high Tags: platform_score_cloud_service_name: @@ -20,5 +48,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Support Role \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_user_no_policies.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_user_no_policies.yaml old mode 100755 new mode 100644 index 486ffe8ea..da44fd1dd --- a/compliance/controls/baseline/aws/IAM/aws_iam_user_no_policies.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_user_no_policies.yaml @@ -1,13 +1,30 @@ +Description: Ensure that IAM users receive permissions only through IAM groups. ID: aws_iam_user_no_policies -Title: "Receive Permissions via IAM Groups Only" -Description: "Ensure that IAM users receive permissions only through IAM groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN attached_policy_arns is null and inline_policies is null THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN attached_policy_arns is null and inline_policies is null THEN name || ' does not receive access permissions through IAM groups only.' \n ELSE name || ' does receive access permissions through IAM groups only.'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_user\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN attached_policy_arns IS NULL AND inline_policies IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN attached_policy_arns IS NULL AND inline_policies IS NULL THEN name || ' does not receive access permissions through IAM groups only.' + ELSE name || ' does receive access permissions through IAM groups only.' + END AS reason, + region, + account_id + FROM + aws_iam_user Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Receive Permissions via IAM Groups Only \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_30_days.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_30_days.yaml old mode 100755 new mode 100644 index a1ce6f472..d8fce66aa --- a/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_30_days.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_30_days.yaml @@ -1,14 +1,39 @@ +Description: Ensure AWS Identity and Access Management (IAM) user passwords are reset before expiration (30 Days). ID: aws_iam_user_password_expiry_30_days -Title: "IAM User Password Expiry 30 Days" -Description: "Ensure AWS Identity and Access Management (IAM) user passwords are reset before expiration (30 Days)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n r.user_name as resource,\n r.og_account_id,\n r.og_resource_id,\n case\n when not password_enabled then 'skip'\n when password_last_changed is null then 'alarm'\n when password_next_rotation is not null then 'ok'\n when password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < now() - '30 days'::interval then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then 'password not enabled'\n when password_last_changed is null then 'password last change not recognized'\n when password_next_rotation is not null then 'password has password policy'\n when password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < now() - '30 days'::interval then 'password is about to expire'\n else 'password has been reseted recently'\n end as reason,\n r.region, \n r.account_id\nfrom\n aws_iam_credential_report as r\n left join aws_iam_account_password_policy as p on r.account_id = p.account_id\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_account_password_policy - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + r.user_name AS resource, + r.og_account_id, + r.og_resource_id, + CASE + WHEN NOT password_enabled THEN 'skip' + WHEN password_last_changed IS NULL THEN 'alarm' + WHEN password_next_rotation IS NOT NULL THEN 'ok' + WHEN password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < NOW() - '30 days'::interval THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN 'password not enabled' + WHEN password_last_changed IS NULL THEN 'password last change not recognized' + WHEN password_next_rotation IS NOT NULL THEN 'password has password policy' + WHEN password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < NOW() - '30 days'::interval THEN 'password is about to expire' + ELSE 'password has been reseted recently' + END AS reason, + r.region, + r.account_id + FROM + aws_iam_credential_report AS r + LEFT JOIN aws_iam_account_password_policy AS p + ON r.account_id = p.account_id Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +44,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM User Password Expiry 30 Days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_7_days.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_7_days.yaml old mode 100755 new mode 100644 index 491bc97df..6a6436c2a --- a/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_7_days.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_7_days.yaml @@ -1,14 +1,39 @@ +Description: Ensure AWS Identity and Access Management (IAM) user passwords are reset before expiration (7 Days). ID: aws_iam_user_password_expiry_7_days -Title: "IAM User Password Expiry 7 Days" -Description: "Ensure AWS Identity and Access Management (IAM) user passwords are reset before expiration (7 Days)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n r.user_name as resource,\n r.og_account_id,\n r.og_resource_id,\n case\n when not password_enabled then 'skip'\n when password_last_changed is null then 'alarm'\n when password_next_rotation is not null then 'ok'\n when password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < now() - '7 days'::interval then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then 'password not enabled'\n when password_last_changed is null then 'password last change not recognized'\n when password_next_rotation is not null then 'password has password policy'\n when password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < now() - '7 days'::interval then 'password is about to expire'\n else 'password has been reseted recently'\n end as reason,\n r.region, \n r.account_id\nfrom\n aws_iam_credential_report as r\n left join aws_iam_account_password_policy as p on r.account_id = p.account_id\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_account_password_policy - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + r.user_name AS resource, + r.og_account_id, + r.og_resource_id, + CASE + WHEN NOT password_enabled THEN 'skip' + WHEN password_last_changed IS NULL THEN 'alarm' + WHEN password_next_rotation IS NOT NULL THEN 'ok' + WHEN password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < NOW() - '7 days'::interval THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN 'password not enabled' + WHEN password_last_changed IS NULL THEN 'password last change not recognized' + WHEN password_next_rotation IS NOT NULL THEN 'password has password policy' + WHEN password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < NOW() - '7 days'::interval THEN 'password is about to expire' + ELSE 'password has been reset recently' + END AS reason, + r.region, + r.account_id + FROM + aws_iam_credential_report AS r + LEFT JOIN + aws_iam_account_password_policy AS p ON r.account_id = p.account_id Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +44,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM User Password Expiry 7 Days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_x_days.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_x_days.yaml old mode 100755 new mode 100644 index c2dca09a4..6aad6cb18 --- a/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_x_days.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_user_password_expiry_x_days.yaml @@ -1,16 +1,41 @@ +Description: Ensure AWS Identity and Access Management (IAM) user passwords are reset before expiration (X Days). ID: aws_iam_user_password_expiry_x_days -Title: "IAM User Password Expiry X Days" -Description: "Ensure AWS Identity and Access Management (IAM) user passwords are reset before expiration (X Days)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n r.user_name as resource,\n r.og_account_id,\n r.og_resource_id,\n case\n when not password_enabled then 'skip'\n when password_last_changed is null then 'alarm'\n when password_next_rotation is not null then 'ok'\n when password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < now() - '{{.awsIamUserPasswordExpirationDays}} days'::interval then 'alarm'\n else 'ok'\n end as status,\n case\n when not password_enabled then 'password not enabled'\n when password_last_changed is null then 'password last change not recognized'\n when password_next_rotation is not null then 'password has password policy'\n when password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < now() - '{{.awsIamUserPasswordExpirationDays}} days'::interval then 'password is about to expire'\n else 'password has been reseted recently'\n end as reason,\n r.region, \n r.account_id\nfrom\n aws_iam_credential_report as r\n left join aws_iam_account_password_policy as p on r.account_id = p.account_id\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_account_password_policy - aws_iam_credential_report Parameters: - Key: awsIamUserPasswordExpirationDays Required: true + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + r.user_name AS resource, + r.og_account_id, + r.og_resource_id, + CASE + WHEN NOT password_enabled THEN 'skip' + WHEN password_last_changed IS NULL THEN 'alarm' + WHEN password_next_rotation IS NOT NULL THEN 'ok' + WHEN password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < NOW() - '{{.awsIamUserPasswordExpirationDays}} days'::interval THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT password_enabled THEN 'password not enabled' + WHEN password_last_changed IS NULL THEN 'password last change not recognized' + WHEN password_next_rotation IS NOT NULL THEN 'password has password policy' + WHEN password_last_changed::timestamp + (COALESCE(p.max_password_age, '90') || ' days')::interval < NOW() - '{{.awsIamUserPasswordExpirationDays}} days'::interval THEN 'password is about to expire' + ELSE 'password has been reset recently' + END AS reason, + r.region, + r.account_id + FROM + aws_iam_credential_report AS r + LEFT JOIN aws_iam_account_password_policy AS p + ON r.account_id = p.account_id Severity: high Tags: platform_score_cloud_service_name: @@ -21,5 +46,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM User Password Expiry X Days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_user_policies.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_user_policies.yaml old mode 100755 new mode 100644 index d21582268..0d5863ab7 --- a/compliance/controls/baseline/aws/IAM/aws_iam_user_policies.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_user_policies.yaml @@ -1,13 +1,30 @@ +Description: Ensure AWS IAM policies are attached to groups instead of users as an IAM best practice. ID: aws_iam_user_policies -Title: "IAM User Policies" -Description: "Ensure AWS IAM policies are attached to groups instead of users as an IAM best practice." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n u.name as resource,\n u.og_account_id,\n u.og_resource_id,\n case\n when attached_policy_arns is null then 'ok'\n else 'alarm'\n end as status,\n case\n when attached_policy_arns is null then 'this user does not have any policies attached'\n else 'policies are better to be attached to only iam groups'\n end as reason,\n u.region, \n u.account_id\nfrom\n aws_iam_user as u\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + u.name AS resource, + u.og_account_id, + u.og_resource_id, + CASE + WHEN attached_policy_arns IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN attached_policy_arns IS NULL THEN 'this user does not have any policies attached' + ELSE 'policies are better to be attached to only IAM groups' + END AS reason, + u.region, + u.account_id + FROM + aws_iam_user AS u Severity: low Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM User Policies \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_user_with_password_and_access_keys.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_user_with_password_and_access_keys.yaml old mode 100755 new mode 100644 index 2818ccd73..f1c26d43e --- a/compliance/controls/baseline/aws/IAM/aws_iam_user_with_password_and_access_keys.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_user_with_password_and_access_keys.yaml @@ -1,14 +1,35 @@ +Description: Ensure that IAM users have either API access or console access in order to follow IAM security best practices. ID: aws_iam_user_with_password_and_access_keys -Title: "IAM User with Password and Access Keys" -Description: "Ensure that IAM users have either API access or console access in order to follow IAM security best practices." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n u.name as resource,\n u.og_account_id,\n u.og_resource_id,\n case\n when (login_profile ->> 'UserName' is not null) and (k.access_key_id is not null) then 'alarm'\n else 'ok'\n end as status,\n case\n when (login_profile ->> 'UserName' is not null) and (k.access_key_id is not null) then u.name || ' is being used for both API access or for management console access '\n else u.name || ' is either being used for API access or for management console access '\n end as reason,\n u.region, \n u.account_id\nfrom\n aws_iam_user as u\n left join aws_iam_access_key as k on u.name = k.user_name\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_access_key - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + u.name AS resource, + u.og_account_id, + u.og_resource_id, + CASE + WHEN (login_profile ->> 'UserName' IS NOT NULL) AND (k.access_key_id IS NOT NULL) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (login_profile ->> 'UserName' IS NOT NULL) AND (k.access_key_id IS NOT NULL) THEN u.name || ' is being used for both API access or for management console access' + ELSE u.name || ' is either being used for API access or for management console access' + END AS reason, + u.region, + u.account_id + FROM + aws_iam_user AS u + LEFT JOIN + aws_iam_access_key AS k + ON + u.name = k.user_name Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +40,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM User with Password and Access Keys \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_users_unauthorized_to_edit_access_policies.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_users_unauthorized_to_edit_access_policies.yaml old mode 100755 new mode 100644 index df03cca2a..124c92f44 --- a/compliance/controls/baseline/aws/IAM/aws_iam_users_unauthorized_to_edit_access_policies.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_users_unauthorized_to_edit_access_policies.yaml @@ -1,16 +1,85 @@ +Description: Ensure AWS IAM users that are not authorized to edit IAM access policies are decommissioned. ID: aws_iam_users_unauthorized_to_edit_access_policies -Title: "IAM Users Unauthorized to Edit Access Policies" -Description: "Ensure AWS IAM users that are not authorized to edit IAM access policies are decommissioned.." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH authorize_to_edit_policy AS (\n SELECT\n arn,\n (select ARRAY_AGG(action) from jsonb_array_elements_text(s -> 'Action') AS action)\n FROM\n aws_iam_policy,\n jsonb_array_elements(policy_std -> 'Statement') AS s\n WHERE \n ((select ARRAY_AGG(action) from jsonb_array_elements_text(s -> 'Action') AS action) @> ARRAY[\n 'iam:CreatePolicy',\n 'iam:CreatePolicyVersion',\n 'iam:DeleteGroupPolicy',\n 'iam:DeletePolicy',\n 'iam:DeletePolicyVersion',\n 'iam:DeleteRolePolicy',\n 'iam:DeleteUserPolicy',\n 'iam:DetachGroupPolicy',\n 'iam:DetachRolePolicy',\n 'iam:DetachUserPolicy',\n 'iam:PutGroupPolicy',\n 'iam:PutRolePolicy',\n 'iam:PutUserPolicy',\n 'iam:UpdateAssumeRolePolicy'\n ]\n and\n (s ->> 'Effect') = 'Allow')\n or \n ((select ARRAY_AGG(action) from jsonb_array_elements_text(s -> 'Action') AS action) @> ARRAY[\n 'iam:*'\n ]\n and\n (s ->> 'Effect') = 'Allow')\n )\n\nSELECT\n name AS resource,\n og_account_id,\n og_resource_id,\n CASE\n WHEN EXISTS(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as parn\n LEFT JOIN authorize_to_edit_policy AS ep ON parn = ep.arn where ep.arn is not null\n ) and ('{{.awsIamUsersAuthorizedToEditPolicy}}' not like '%' || user_id || '%') THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS(\n select 1 from jsonb_array_elements_text(attached_policy_arns) as parn\n LEFT JOIN authorize_to_edit_policy AS ep ON parn = ep.arn where ep.arn is not null\n ) and ('{{.awsIamUsersAuthorizedToEditPolicy}}' not like '%' || user_id || '%') THEN 'this iam user is not authorized to edit policies'\n ELSE 'ok'\n END AS reason,\n region, \n account_id\nFROM\n aws_iam_user\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_policy - aws_iam_user Parameters: - Key: awsIamUsersAuthorizedToEditPolicy Required: true + PrimaryTable: aws_iam_user + QueryToExecute: | + WITH authorize_to_edit_policy AS ( + SELECT + arn, + (SELECT ARRAY_AGG(action) + FROM jsonb_array_elements_text(s -> 'Action') AS action) + FROM + aws_iam_policy, + jsonb_array_elements(policy_std -> 'Statement') AS s + WHERE + (( + SELECT ARRAY_AGG(action) + FROM jsonb_array_elements_text(s -> 'Action') AS action + ) @> ARRAY[ + 'iam:CreatePolicy', + 'iam:CreatePolicyVersion', + 'iam:DeleteGroupPolicy', + 'iam:DeletePolicy', + 'iam:DeletePolicyVersion', + 'iam:DeleteRolePolicy', + 'iam:DeleteUserPolicy', + 'iam:DetachGroupPolicy', + 'iam:DetachRolePolicy', + 'iam:DetachUserPolicy', + 'iam:PutGroupPolicy', + 'iam:PutRolePolicy', + 'iam:PutUserPolicy', + 'iam:UpdateAssumeRolePolicy' + ] + AND (s ->> 'Effect') = 'Allow') + OR ( + ( + SELECT ARRAY_AGG(action) + FROM jsonb_array_elements_text(s -> 'Action') AS action + ) @> ARRAY['iam:*'] + AND (s ->> 'Effect') = 'Allow' + ) + ) + + SELECT + name AS resource, + og_account_id, + og_resource_id, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS parn + LEFT JOIN authorize_to_edit_policy AS ep ON parn = ep.arn + WHERE ep.arn IS NOT NULL + ) + AND ('{{.awsIamUsersAuthorizedToEditPolicy}}' NOT LIKE '%' || user_id || '%') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS parn + LEFT JOIN authorize_to_edit_policy AS ep ON parn = ep.arn + WHERE ep.arn IS NOT NULL + ) + AND ('{{.awsIamUsersAuthorizedToEditPolicy}}' NOT LIKE '%' || user_id || '%') + THEN 'this iam user is not authorized to edit policies' + ELSE 'ok' + END AS reason, + region, + account_id + FROM + aws_iam_user Severity: high Tags: platform_score_cloud_service_name: @@ -21,5 +90,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Users Unauthorized to Edit Access Policies \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_iam_users_with_administrative_privileges.yaml b/compliance/controls/baseline/aws/IAM/aws_iam_users_with_administrative_privileges.yaml old mode 100755 new mode 100644 index 9aafd8854..3e1991c61 --- a/compliance/controls/baseline/aws/IAM/aws_iam_users_with_administrative_privileges.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_iam_users_with_administrative_privileges.yaml @@ -1,13 +1,38 @@ +Description: Ensure there are no IAM users with administrative permissions available in your AWS cloud account. ID: aws_iam_users_with_administrative_privileges -Title: "IAM Users with Administrative Privileges" -Description: "Ensure there are no IAM users with administrative permissions available in your AWS cloud account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN EXISTS (\n SELECT 1\n FROM jsonb_array_elements_text(attached_policy_arns::jsonb) AS elem\n WHERE SUBSTRING(elem::text FROM 'policy/(.*)') = 'AdministratorAccess'\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS (\n SELECT 1\n FROM jsonb_array_elements_text(attached_policy_arns::jsonb) AS elem\n WHERE SUBSTRING(elem::text FROM 'policy/(.*)') = 'AdministratorAccess'\n ) THEN name || ' has administrator access' \n ELSE name || ' does not have administrator access'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_user\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns::jsonb) AS elem + WHERE SUBSTRING(elem::text FROM 'policy/(.*)') = 'AdministratorAccess' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns::jsonb) AS elem + WHERE SUBSTRING(elem::text FROM 'policy/(.*)') = 'AdministratorAccess' + ) THEN name || ' has administrator access' + ELSE name || ' does not have administrator access' + END AS reason, + region, + account_id + FROM + aws_iam_user Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +43,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: IAM Users with Administrative Privileges \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_inactive_iam_console_user.yaml b/compliance/controls/baseline/aws/IAM/aws_inactive_iam_console_user.yaml old mode 100755 new mode 100644 index 74258aad7..0f8ac0806 --- a/compliance/controls/baseline/aws/IAM/aws_inactive_iam_console_user.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_inactive_iam_console_user.yaml @@ -1,14 +1,39 @@ +Description: Ensure no AWS IAM users have been inactive for a long (specified) period of time. ID: aws_inactive_iam_console_user -Title: "Inactive IAM Console User" -Description: "Ensure no AWS IAM users have been inactive for a long (specified) period of time." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n u.og_resource_id,\n u.og_account_id,\n CASE\n WHEN (k.access_key_id is null and \n (password_last_used is null or\n password_last_used::timestamp < now() - '90 days'::interval)\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN (k.access_key_id is null and \n (password_last_used is null or\n password_last_used::timestamp < now() - '90 days'::interval)\n ) THEN 'certificate has been expired'\n ELSE 'certificate is not expired'\n END AS reason,\n u.region,\n u.account_id\nFROM \n aws_iam_user AS u\n LEFT JOIN aws_iam_access_key AS k ON u.name = k.user_name\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_access_key - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + name AS resource, + u.og_resource_id, + u.og_account_id, + CASE + WHEN (k.access_key_id IS NULL AND + (password_last_used IS NULL OR + password_last_used::timestamp < NOW() - '90 days'::interval) + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (k.access_key_id IS NULL AND + (password_last_used IS NULL OR + password_last_used::timestamp < NOW() - '90 days'::interval) + ) THEN 'certificate has been expired' + ELSE 'certificate is not expired' + END AS reason, + u.region, + u.account_id + FROM + aws_iam_user AS u + LEFT JOIN aws_iam_access_key AS k + ON u.name = k.user_name Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +44,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Inactive IAM Console User \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_mfa_device_deactivated.yaml b/compliance/controls/baseline/aws/IAM/aws_mfa_device_deactivated.yaml old mode 100755 new mode 100644 index 5b0a6fcd5..c60217514 --- a/compliance/controls/baseline/aws/IAM/aws_mfa_device_deactivated.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_mfa_device_deactivated.yaml @@ -1,31 +1,35 @@ +Description: A Multi-Factor Authentication (MFA) device deactivation for an IAM user has been detected. ID: aws_mfa_device_deactivated -Title: "MFA Device Deactivated" -Description: "A Multi-Factor Authentication (MFA) device deactivation for an IAM user has been detected." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_iam_user + - aws_iam_virtual_mfa_device + Parameters: [] + PrimaryTable: aws_iam_user QueryToExecute: | - select - a.arn as resource, + SELECT + a.arn AS resource, a.og_account_id, a.og_resource_id, - case - when mfa.serial_number is null then 'alarm' - else 'ok' - end as status, - case - when mfa.serial_number is null then a.title || 'mfa device not activated.' - else a.title || 'mfa device activated.' - end as reason, + CASE + WHEN mfa.serial_number IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN mfa.serial_number IS NULL THEN a.title || 'mfa device not activated.' + ELSE a.title || 'mfa device activated.' + END AS reason, a.region, a.account_id - from - aws_iam_user as a - left join aws_iam_virtual_mfa_device as mfa on a.user_id = mfa.user_id - PrimaryTable: aws_iam_user - ListOfTables: - - aws_iam_user - - aws_iam_virtual_mfa_device - Parameters: [] + FROM + aws_iam_user AS a + LEFT JOIN + aws_iam_virtual_mfa_device AS mfa + ON + a.user_id = mfa.user_id Severity: high Tags: platform_score_cloud_service_name: @@ -36,5 +40,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: MFA Device Deactivated \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_multi_account_centralized_management.yaml b/compliance/controls/baseline/aws/IAM/aws_multi_account_centralized_management.yaml old mode 100755 new mode 100644 index 13a9cf929..8cc43c73e --- a/compliance/controls/baseline/aws/IAM/aws_multi_account_centralized_management.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_multi_account_centralized_management.yaml @@ -1,13 +1,32 @@ +Description: Set up, organize and manage your AWS accounts for optimal security and manageability. ID: aws_multi_account_centralized_management -Title: "AWS Multi-Account Centralized Management" -Description: "Set up, organize and manage your AWS accounts for optimal security and manageability." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n organization_id as resource,\n og_account_id,\n og_resource_id,\n CASE\n WHEN count(*) = 1 THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN count(*) = 1 THEN organization_id || ' only has one account' \n ELSE organization_id || ' has multiple accounts'\n END AS reason\nFROM \n aws_account\nGROUP BY\n organization_id,\n og_account_id,\n og_resource_id;\n" - PrimaryTable: aws_account ListOfTables: - aws_account Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT + organization_id AS resource, + og_account_id, + og_resource_id, + CASE + WHEN count(*) = 1 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN count(*) = 1 THEN organization_id || ' only has one account' + ELSE organization_id || ' has multiple accounts' + END AS reason + FROM + aws_account + GROUP BY + organization_id, + og_account_id, + og_resource_id; Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +37,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Tolerate Failures -IntegrationType: - - aws_cloud_account +Title: AWS Multi-Account Centralized Management \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_pre_heartbleed_server_certificates.yaml b/compliance/controls/baseline/aws/IAM/aws_pre_heartbleed_server_certificates.yaml old mode 100755 new mode 100644 index a22b476d8..8c3086529 --- a/compliance/controls/baseline/aws/IAM/aws_pre_heartbleed_server_certificates.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_pre_heartbleed_server_certificates.yaml @@ -1,13 +1,30 @@ +Description: Ensure that your server certificates are not vulnerable to Heartbleed security bug. ID: aws_pre_heartbleed_server_certificates -Title: "Pre-Heartbleed Server Certificates" -Description: "Ensure that your server certificates are not vulnerable to Heartbleed security bug." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN upload_date < '2014-04-01' THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN upload_date < '2014-04-01' THEN name || ' is vulnerable to Heartbleed security bug.' \n ELSE name || ' is vulnerable to Heartbleed security bug.'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_server_certificate\n" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: [] + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN upload_date < '2014-04-01' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN upload_date < '2014-04-01' THEN name || ' is vulnerable to Heartbleed security bug.' + ELSE name || ' is not vulnerable to Heartbleed security bug.' + END AS reason, + region, + account_id + FROM + aws_iam_server_certificate Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Pre-Heartbleed Server Certificates \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_root_account_access_keys_present.yaml b/compliance/controls/baseline/aws/IAM/aws_root_account_access_keys_present.yaml old mode 100755 new mode 100644 index af61a810f..b53df81ed --- a/compliance/controls/baseline/aws/IAM/aws_root_account_access_keys_present.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_root_account_access_keys_present.yaml @@ -1,14 +1,33 @@ +Description: Ensure that your AWS root account is not using access keys as a security best practice. ID: aws_root_account_access_keys_present -Title: "Root Account Access Keys Present" -Description: "Ensure that your AWS root account is not using access keys as a security best practice." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n u.og_resource_id,\n u.og_account_id,\n CASE\n WHEN r.access_key_1_active or r.access_key_2_active THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN r.access_key_1_active or r.access_key_2_active THEN u.name || ' does not have any active access key pair'\n ELSE u.name || ' has at least one active access key pair.'\n END AS reason,\n u.region,\n u.account_id\nFROM \n aws_iam_user AS u\n LEFT JOIN aws_iam_credential_report AS r ON u.name = r.user_name\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_credential_report - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + name AS resource, + u.og_resource_id, + u.og_account_id, + CASE + WHEN r.access_key_1_active OR r.access_key_2_active THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.access_key_1_active OR r.access_key_2_active THEN u.name || ' does not have any active access key pair' + ELSE u.name || ' has at least one active access key pair.' + END AS reason, + u.region, + u.account_id + FROM + aws_iam_user AS u + LEFT JOIN aws_iam_credential_report AS r + ON u.name = r.user_name Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +38,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Insecure Keys -IntegrationType: - - aws_cloud_account +Title: Root Account Access Keys Present \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_root_account_active_signing_certificates.yaml b/compliance/controls/baseline/aws/IAM/aws_root_account_active_signing_certificates.yaml old mode 100755 new mode 100644 index 67494c79c..dc5790274 --- a/compliance/controls/baseline/aws/IAM/aws_root_account_active_signing_certificates.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_root_account_active_signing_certificates.yaml @@ -1,13 +1,32 @@ +Description: Ensure that your AWS root account user is not using X.509 certificates to validate API requests. ID: aws_root_account_active_signing_certificates -Title: "Root Account Active Signing Certificates" -Description: "Ensure that your AWS root account user is not using X.509 certificates to validate API requests." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n (user_name || ' in account ' || account_id) as resource,\n og_account_id,\n og_resource_id,\n case\n when cert_1_active or cert_2_active then 'alarm'\n else 'ok'\n end as status,\n case\n when cert_1_active or cert_2_active then 'is using X.509 certificates to perform SOAP-protocol requests to AWS services. It is better to be disabled'\n else 'is not using X.509 certificates to perform SOAP-protocol requests to AWS services'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_credential_report\nwhere\n user_name = ''\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + (user_name || ' in account ' || account_id) AS resource, + og_account_id, + og_resource_id, + CASE + WHEN cert_1_active OR cert_2_active THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN cert_1_active OR cert_2_active THEN 'is using X.509 certificates to perform SOAP-protocol requests to AWS services. It is better to be disabled' + ELSE 'is not using X.509 certificates to perform SOAP-protocol requests to AWS services' + END AS reason, + region, + account_id + FROM + aws_iam_credential_report + WHERE + user_name = '' Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +37,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Insecure Keys -IntegrationType: - - aws_cloud_account +Title: Root Account Active Signing Certificates \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_root_account_credentials_usage.yaml b/compliance/controls/baseline/aws/IAM/aws_root_account_credentials_usage.yaml old mode 100755 new mode 100644 index cc46a350e..1fb99047d --- a/compliance/controls/baseline/aws/IAM/aws_root_account_credentials_usage.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_root_account_credentials_usage.yaml @@ -1,13 +1,33 @@ +Description: Ensure that root account credentials have not been used recently to access your AWS account. ID: aws_root_account_credentials_usage -Title: "Root Account Credentials Usage" -Description: "Ensure that root account credentials have not been used recently to access your AWS account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n (user_name || ' in account ' || account_id) as resource,\n og_account_id,\n og_resource_id,\n case\n when password_last_used + '7 days'::interval > now() then 'alarm'\n else 'ok'\n end as status,\n case\n when password_last_used + '7 days'::interval > now() then 'root user has been used recently (it is better to minimize root user usage)'\n else 'root user has not been used recently'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_credential_report\nwhere\n user_name = ''\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + (user_name || ' in account ' || account_id) AS resource, + og_account_id, + og_resource_id, + CASE + WHEN password_last_used + '7 days'::interval > NOW() THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN password_last_used + '7 days'::interval > NOW() THEN + 'root user has been used recently (it is better to minimize root user usage)' + ELSE 'root user has not been used recently' + END AS reason, + region, + account_id + FROM + aws_iam_credential_report + WHERE + user_name = '' Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +38,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Insecure Keys -IntegrationType: - - aws_cloud_account +Title: Root Account Credentials Usage \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_root_mfa_enabled.yaml b/compliance/controls/baseline/aws/IAM/aws_root_mfa_enabled.yaml old mode 100755 new mode 100644 index 706586d40..0ee9b31e9 --- a/compliance/controls/baseline/aws/IAM/aws_root_mfa_enabled.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_root_mfa_enabled.yaml @@ -1,13 +1,32 @@ +Description: Ensure that Multi-Factor Authentication (MFA) is enabled for your AWS root account. ID: aws_root_mfa_enabled -Title: "Root MFA Enabled" -Description: "Ensure that Multi-Factor Authentication (MFA) is enabled for your AWS root account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n (user_name || ' in account ' || account_id) as resource,\n og_account_id,\n og_resource_id,\n case\n when mfa_active::bool then 'ok'\n else 'alarm'\n end as status,\n case\n when mfa_active::bool then 'mfa is active for root account'\n else 'mfa is not active for root account'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_credential_report\nwhere\n user_name = ''\n" - PrimaryTable: aws_iam_credential_report ListOfTables: - aws_iam_credential_report Parameters: [] + PrimaryTable: aws_iam_credential_report + QueryToExecute: | + SELECT + (user_name || ' in account ' || account_id) AS resource, + og_account_id, + og_resource_id, + CASE + WHEN mfa_active::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN mfa_active::bool THEN 'mfa is active for root account' + ELSE 'mfa is not active for root account' + END AS reason, + region, + account_id + FROM + aws_iam_credential_report + WHERE + user_name = '' Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +37,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Root MFA Enabled \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_45_days.yaml b/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_45_days.yaml old mode 100755 new mode 100644 index 540a3d99a..f0a196d50 --- a/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_45_days.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_45_days.yaml @@ -1,18 +1,34 @@ +Description: Ensure IAM SSH public keys are rotated on a periodic basis to adhere to AWS security best practices. ID: aws_ssh_public_keys_rotated_45_days -Title: "SSH Public Keys Rotated 45 Days" -Description: "Ensure IAM SSH public keys are rotated on a periodic basis to adhere to AWS security best practices." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n ssh_public_key_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN now() - update_date > '45 days'::interval THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN now() - update_date > '45 days'::interval THEN 'ssh key is too old and should be removed' \n ELSE 'ssh key is not too old'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_ssh_public_key\n" - PrimaryTable: aws_iam_ssh_public_key ListOfTables: - aws_iam_ssh_public_key Parameters: [] + PrimaryTable: aws_iam_ssh_public_key + QueryToExecute: | + SELECT + ssh_public_key_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN now() - update_date > '45 days'::interval THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN now() - update_date > '45 days'::interval THEN 'ssh key is too old and should be removed' + ELSE 'ssh key is not too old' + END AS reason, + region, + account_id + FROM + aws_iam_ssh_public_key Severity: medium Tags: platform_score_cloud_service_name: - AWS Identity and Access Management (IAM) score_service_name: - AWS Identity and Access Management (IAM) -IntegrationType: - - aws_cloud_account +Title: SSH Public Keys Rotated 45 Days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_90_days.yaml b/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_90_days.yaml old mode 100755 new mode 100644 index 001f83e14..b56b9bf95 --- a/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_90_days.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_90_days.yaml @@ -1,18 +1,34 @@ +Description: Ensure IAM SSH public keys are rotated on a periodic basis to adhere to AWS security best practices. ID: aws_ssh_public_keys_rotated_90_days -Title: "SSH Public Keys Rotated 90 Days" -Description: "Ensure IAM SSH public keys are rotated on a periodic basis to adhere to AWS security best practices." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n ssh_public_key_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN now() - update_date > '90 days'::interval THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN now() - update_date > '90 days'::interval THEN 'ssh key is too old and should be removed' \n ELSE 'ssh key is not too old'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_ssh_public_key\n" - PrimaryTable: aws_iam_ssh_public_key ListOfTables: - aws_iam_ssh_public_key Parameters: [] + PrimaryTable: aws_iam_ssh_public_key + QueryToExecute: | + SELECT + ssh_public_key_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN now() - update_date > '90 days'::interval THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN now() - update_date > '90 days'::interval THEN 'ssh key is too old and should be removed' + ELSE 'ssh key is not too old' + END AS reason, + region, + account_id + FROM + aws_iam_ssh_public_key Severity: medium Tags: platform_score_cloud_service_name: - AWS Identity and Access Management (IAM) score_service_name: - AWS Identity and Access Management (IAM) -IntegrationType: - - aws_cloud_account +Title: SSH Public Keys Rotated 90 Days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_x_days.yaml b/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_x_days.yaml old mode 100755 new mode 100644 index ccd56ddbe..a89e287d8 --- a/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_x_days.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_ssh_public_keys_rotated_x_days.yaml @@ -1,20 +1,36 @@ +Description: Ensure IAM SSH public keys are rotated on a periodic basis to adhere to AWS security best practices. ID: aws_ssh_public_keys_rotated_x_days -Title: "SSH Public Keys Rotated X Days" -Description: "Ensure IAM SSH public keys are rotated on a periodic basis to adhere to AWS security best practices." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n ssh_public_key_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN now() - update_date > '{{.awsSshPublicKeyRotateDays}} days'::interval THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN now() - update_date > '{{.awsSshPublicKeyRotateDays}} days'::interval THEN 'ssh key is too old and should be removed' \n ELSE 'ssh key is not too old'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_ssh_public_key\n" - PrimaryTable: aws_iam_ssh_public_key ListOfTables: - aws_iam_ssh_public_key Parameters: - Key: awsSshPublicKeyRotateDays Required: true + PrimaryTable: aws_iam_ssh_public_key + QueryToExecute: | + SELECT + ssh_public_key_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN now() - update_date > '{{.awsSshPublicKeyRotateDays}} days'::interval THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN now() - update_date > '{{.awsSshPublicKeyRotateDays}} days'::interval THEN 'ssh key is too old and should be removed' + ELSE 'ssh key is not too old' + END AS reason, + region, + account_id + FROM + aws_iam_ssh_public_key Severity: medium Tags: platform_score_cloud_service_name: - AWS Identity and Access Management (IAM) score_service_name: - AWS Identity and Access Management (IAM) -IntegrationType: - - aws_cloud_account +Title: SSH Public Keys Rotated X Days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_ssl_tls_certificate_expiry_30_days.yaml b/compliance/controls/baseline/aws/IAM/aws_ssl_tls_certificate_expiry_30_days.yaml old mode 100755 new mode 100644 index 3b9cb147e..5ea2544f1 --- a/compliance/controls/baseline/aws/IAM/aws_ssl_tls_certificate_expiry_30_days.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_ssl_tls_certificate_expiry_30_days.yaml @@ -1,22 +1,39 @@ +Description: Ensure SSL/TLS certificates are renewed before their expiration. ID: aws_ssl_tls_certificate_expiry_30_days -Title: "SSL/TLS Certificate Expiry 30 Days" -Description: "Ensure SSL/TLS certificates are renewed before their expiration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN expiration - '30 days'::interval < now() THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN expiration < now() THEN 'certificate has been expired'\n WHEN expiration - '30 days'::interval < now() THEN 'certificate is about to expire in ' || expiration \n ELSE 'certificate is not going to expire soon'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_server_certificate\n" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: [] + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN expiration - '30 days'::interval < NOW() THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expiration < NOW() THEN 'certificate has been expired' + WHEN expiration - '30 days'::interval < NOW() THEN 'certificate is about to expire in ' || expiration + ELSE 'certificate is not going to expire soon' + END AS reason, + region, + account_id + FROM + aws_iam_server_certificate Severity: high -Tags: +Tags: platform_score_cloud_service_name: - AWS Identity and Access Management (IAM) - platform_score_use_case: + platform_score_use_case: - Problem Identities - score_service_name: + score_service_name: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: SSL/TLS Certificate Expiry 30 Days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_ssl_tls_certificate_expiry_x_days.yaml b/compliance/controls/baseline/aws/IAM/aws_ssl_tls_certificate_expiry_x_days.yaml old mode 100755 new mode 100644 index 99180ac14..fe9a288c2 --- a/compliance/controls/baseline/aws/IAM/aws_ssl_tls_certificate_expiry_x_days.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_ssl_tls_certificate_expiry_x_days.yaml @@ -1,15 +1,33 @@ +Description: Ensure SSL/TLS certificates are renewed before their expiration. ID: aws_ssl_tls_certificate_expiry_x_days -Title: "SSL/TLS Certificate Expiry X Days" -Description: "Ensure SSL/TLS certificates are renewed before their expiration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN expiration - ('{{.awsIamServerCertificateAge}}' || ' days')::interval < now() THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN expiration < now() THEN 'certificate has been expired'\n WHEN expiration - ('{{.awsIamServerCertificateAge}}' || ' days')::interval < now() THEN 'certificate is about to expire in ' || expiration \n ELSE 'certificate is not going to expire soon'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_server_certificate\n" - PrimaryTable: aws_iam_server_certificate ListOfTables: - aws_iam_server_certificate Parameters: - Key: awsIamServerCertificateAge Required: true + PrimaryTable: aws_iam_server_certificate + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN expiration - ('{{.awsIamServerCertificateAge}}' || ' days')::interval < NOW() THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expiration < NOW() THEN 'certificate has been expired' + WHEN expiration - ('{{.awsIamServerCertificateAge}}' || ' days')::interval < NOW() THEN 'certificate is about to expire in ' || expiration + ELSE 'certificate is not going to expire soon' + END AS reason, + region, + account_id + FROM + aws_iam_server_certificate Severity: high Tags: platform_score_cloud_service_name: @@ -20,5 +38,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: SSL/TLS Certificate Expiry X Days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_unapproved_iam_policy_in_use.yaml b/compliance/controls/baseline/aws/IAM/aws_unapproved_iam_policy_in_use.yaml old mode 100755 new mode 100644 index e3b6480e2..9a71dcd34 --- a/compliance/controls/baseline/aws/IAM/aws_unapproved_iam_policy_in_use.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_unapproved_iam_policy_in_use.yaml @@ -1,15 +1,33 @@ +Description: Ensure there are no unapproved AWS Identity and Access Management (IAM) policies in use. ID: aws_unapproved_iam_policy_in_use -Title: "Unapproved IAM Policy in Use" -Description: "Ensure there are no unapproved AWS Identity and Access Management (IAM) policies in use." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n name as resource,\n og_account_id,\n og_resource_id,\n case\n when attachment_count > 0 and '{{.awsUnapprovedIamPolicies}}' LIKE '%' || name || '%' then 'alarm'\n else 'ok'\n end as status,\n case\n when attachment_count > 0 and '{{.awsUnapprovedIamPolicies}}' LIKE '%' || name || '%' then name || ' is an unapproved iam policy which is being used'\n when attachment_count > 0 then name || ' is not unapproved'\n else name || ' is not being used'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_policy\n" - PrimaryTable: aws_iam_policy ListOfTables: - aws_iam_policy Parameters: - Key: awsUnapprovedIamPolicies Required: true + PrimaryTable: aws_iam_policy + QueryToExecute: | + SELECT + name AS resource, + og_account_id, + og_resource_id, + CASE + WHEN attachment_count > 0 AND '{{.awsUnapprovedIamPolicies}}' LIKE '%' || name || '%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN attachment_count > 0 AND '{{.awsUnapprovedIamPolicies}}' LIKE '%' || name || '%' THEN name || ' is an unapproved iam policy which is being used' + WHEN attachment_count > 0 THEN name || ' is not unapproved' + ELSE name || ' is not being used' + END AS reason, + region, + account_id + FROM + aws_iam_policy Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +38,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Unapproved IAM Policy in Use \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_unnecessary_access_keys.yaml b/compliance/controls/baseline/aws/IAM/aws_unnecessary_access_keys.yaml old mode 100755 new mode 100644 index a5e12bdce..5462c044b --- a/compliance/controls/baseline/aws/IAM/aws_unnecessary_access_keys.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_unnecessary_access_keys.yaml @@ -1,14 +1,32 @@ +Description: Ensure there is a maximum of one active access key pair available for any single IAM user. ID: aws_unnecessary_access_keys -Title: "Unnecessary Access Keys" -Description: "Ensure there is a maximum of one active access key pair available for any single IAM user." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n u.name as resource,\n u.og_account_id,\n u.og_resource_id,\n case\n when (select count(*) from aws_iam_access_key as k where u.name = k.user_name) > 1 then 'alarm'\n else 'ok'\n end as status,\n case\n when (select count(*) from aws_iam_access_key as k where u.name = k.user_name) > 1 then u.name || ' user has more than one access keys'\n when (select count(*) from aws_iam_access_key as k where u.name = k.user_name) = 1 then u.name || ' user has only one access key'\n else u.name || ' user has no access key'\n end as reason,\n u.region, \n u.account_id\nfrom\n aws_iam_user as u\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_access_key - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + SELECT + u.name AS resource, + u.og_account_id, + u.og_resource_id, + CASE + WHEN (SELECT COUNT(*) FROM aws_iam_access_key AS k WHERE u.name = k.user_name) > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (SELECT COUNT(*) FROM aws_iam_access_key AS k WHERE u.name = k.user_name) > 1 THEN u.name || ' user has more than one access keys' + WHEN (SELECT COUNT(*) FROM aws_iam_access_key AS k WHERE u.name = k.user_name) = 1 THEN u.name || ' user has only one access key' + ELSE u.name || ' user has no access key' + END AS reason, + u.region, + u.account_id + FROM + aws_iam_user AS u Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +37,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Insecure Keys -IntegrationType: - - aws_cloud_account +Title: Unnecessary Access Keys \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_unnecessary_ssh_public_keys.yaml b/compliance/controls/baseline/aws/IAM/aws_unnecessary_ssh_public_keys.yaml old mode 100755 new mode 100644 index 5460f3ba1..09cc4dda3 --- a/compliance/controls/baseline/aws/IAM/aws_unnecessary_ssh_public_keys.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_unnecessary_ssh_public_keys.yaml @@ -1,14 +1,44 @@ +Description: Ensure there is a maximum of one active SSH public key assigned to any single IAM user. ID: aws_unnecessary_ssh_public_keys -Title: "Unnecessary SSH Public Keys" -Description: "Ensure there is a maximum of one active SSH public keys assigned to any single IAM user." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with active_count AS (\n select \n user_name, \n count(*) \n from \n aws_iam_ssh_public_key \n where \n status = 'Active' \n group by \n user_name\n)\nSELECT \n arn as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN c.count > 1 THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN c.count > 1 THEN u.name || ' has more than one active ssh key'\n ELSE u.name || ' does not have more than one active ssh key'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_user AS u\n left join active_count AS c ON u.name = c.user_name;\n" - PrimaryTable: aws_iam_user ListOfTables: - aws_iam_ssh_public_key - aws_iam_user Parameters: [] + PrimaryTable: aws_iam_user + QueryToExecute: | + WITH active_count AS ( + SELECT + user_name, + COUNT(*) + FROM + aws_iam_ssh_public_key + WHERE + status = 'Active' + GROUP BY + user_name + ) + SELECT + arn AS resource, + og_resource_id, + og_account_id, + CASE + WHEN c.count > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.count > 1 THEN u.name || ' has more than one active ssh key' + ELSE u.name || ' does not have more than one active ssh key' + END AS reason, + region, + account_id + FROM + aws_iam_user AS u + LEFT JOIN active_count AS c + ON u.name = c.user_name; Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +49,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Insecure Keys -IntegrationType: - - aws_cloud_account +Title: Unnecessary SSH Public Keys \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_unused_iam_group.yaml b/compliance/controls/baseline/aws/IAM/aws_unused_iam_group.yaml old mode 100755 new mode 100644 index 80c9c06cb..df8466a5a --- a/compliance/controls/baseline/aws/IAM/aws_unused_iam_group.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_unused_iam_group.yaml @@ -1,13 +1,30 @@ +Description: Ensure all IAM groups have at least one user. ID: aws_unused_iam_group -Title: "Unused IAM Group" -Description: "Ensure all IAM groups have at least one user." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n name as resource,\n og_account_id,\n og_resource_id,\n case\n when users is null then 'alarm'\n else 'ok'\n end as status,\n case\n when users is null then name || ' group is unused and should be removed'\n else name || ' group is being used'\n end as reason,\n region, \n account_id\nfrom\n aws_iam_group\n" - PrimaryTable: aws_iam_group ListOfTables: - aws_iam_group Parameters: [] + PrimaryTable: aws_iam_group + QueryToExecute: | + SELECT + name AS resource, + og_account_id, + og_resource_id, + CASE + WHEN users IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN users IS NULL THEN name || ' group is unused and should be removed' + ELSE name || ' group is being used' + END AS reason, + region, + account_id + FROM + aws_iam_group Severity: low Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Unused IAM Group \ No newline at end of file diff --git a/compliance/controls/baseline/aws/IAM/aws_valid_iam_identity_providers.yaml b/compliance/controls/baseline/aws/IAM/aws_valid_iam_identity_providers.yaml old mode 100755 new mode 100644 index f94482b72..11091486d --- a/compliance/controls/baseline/aws/IAM/aws_valid_iam_identity_providers.yaml +++ b/compliance/controls/baseline/aws/IAM/aws_valid_iam_identity_providers.yaml @@ -1,15 +1,63 @@ +Description: Ensure valid IAM Identity Providers are used within your AWS account for secure user authentication and authorization. ID: aws_valid_iam_identity_providers -Title: "Valid IAM Identity Providers" -Description: "Ensure valid IAM Identity Providers are used within your AWS account for secure user authentication and authorization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with locations AS (\n SELECT\n og_resource_id, unnest(xpath('/md:EntityDescriptor/md:IDPSSODescriptor/md:SingleLogoutService/@Location', unnest(xpath('/md:EntityDescriptor', saml_metadata_document::xml, ARRAY[ARRAY['md', 'urn:oasis:names:tc:SAML:2.0:metadata']])), ARRAY[ARRAY['md', 'urn:oasis:names:tc:SAML:2.0:metadata']]))::text as location\n FROM aws_iam_saml_provider\n)\nSELECT \n arn as resource,\n og_resource_id,\n og_account_id,\n saml_metadata_document,\n CASE\n WHEN '{{.awsTrustedEndpoints}}' = '' THEN 'ok'\n WHEN EXISTS (\n select 1 from locations as l where l.og_resource_id = p.og_resource_id and l.location not like '{{.awsTrustedEndpoints}}'\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN '{{.awsTrustedEndpoints}}' = '' THEN 'trusted endpoints not provided'\n WHEN EXISTS (\n select 1 from locations as l where l.og_resource_id = p.og_resource_id and l.location not like '{{.awsTrustedEndpoints}}') THEN 'location is not inside trusted endpoints'\n ELSE 'is inside trusted endpoints'\n END AS reason,\n region,\n account_id\nFROM \n aws_iam_saml_provider AS p\n" - PrimaryTable: aws_iam_saml_provider ListOfTables: - aws_iam_saml_provider Parameters: - Key: awsTrustedEndpoints Required: true + PrimaryTable: aws_iam_saml_provider + QueryToExecute: | + WITH locations AS ( + SELECT + og_resource_id, + UNNEST( + XPATH( + '/md:EntityDescriptor/md:IDPSSODescriptor/md:SingleLogoutService/@Location', + UNNEST( + XPATH( + '/md:EntityDescriptor', + saml_metadata_document::XML, + ARRAY[ARRAY['md', 'urn:oasis:names:tc:SAML:2.0:metadata']] + ) + ), + ARRAY[ARRAY['md', 'urn:oasis:names:tc:SAML:2.0:metadata']] + ) + )::TEXT AS location + FROM aws_iam_saml_provider + ) + SELECT + arn AS resource, + og_resource_id, + og_account_id, + saml_metadata_document, + CASE + WHEN '{{.awsTrustedEndpoints}}' = '' THEN 'ok' + WHEN EXISTS ( + SELECT 1 + FROM locations AS l + WHERE l.og_resource_id = p.og_resource_id + AND l.location NOT LIKE '{{.awsTrustedEndpoints}}' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN '{{.awsTrustedEndpoints}}' = '' THEN 'trusted endpoints not provided' + WHEN EXISTS ( + SELECT 1 + FROM locations AS l + WHERE l.og_resource_id = p.og_resource_id + AND l.location NOT LIKE '{{.awsTrustedEndpoints}}' + ) THEN 'location is not inside trusted endpoints' + ELSE 'is inside trusted endpoints' + END AS reason, + region, + account_id + FROM + aws_iam_saml_provider AS p Severity: high Tags: platform_score_cloud_service_name: @@ -20,5 +68,4 @@ Tags: - AWS Identity and Access Management (IAM) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Valid IAM Identity Providers \ No newline at end of file diff --git a/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificate_expired.yaml b/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificate_expired.yaml old mode 100755 new mode 100644 index 5272b142f..b16af7f4b --- a/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificate_expired.yaml +++ b/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificate_expired.yaml @@ -1,13 +1,30 @@ +Description: Ensure expired SSL/TLS certificates are removed from AWS Certificate Manager (ACM). ID: aws_acm_certificate_expired -Title: "ACM Certificate Expired" -Description: "Ensure expired SSL/TLS certificates are removed from AWS Certificate Manager (ACM)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n certificate_arn as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN status = 'EXPIRED' THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN status = 'EXPIRED' THEN 'certificate has been expired' \n ELSE 'certificate not expired'\n END AS reason,\n region,\n account_id\nFROM \n aws_acm_certificate\n" - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_resource_id, + og_account_id, + CASE + WHEN status = 'EXPIRED' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status = 'EXPIRED' THEN 'certificate has been expired' + ELSE 'certificate not expired' + END AS reason, + region, + account_id + FROM + aws_acm_certificate Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Certificate Manager score_tags: - Tolerate Failures -IntegrationType: - - aws_cloud_account +Title: ACM Certificate Expired \ No newline at end of file diff --git a/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_renewal_7_days_before_expiration.yaml b/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_renewal_7_days_before_expiration.yaml old mode 100755 new mode 100644 index 99e4d19bc..839aa1ece --- a/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_renewal_7_days_before_expiration.yaml +++ b/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_renewal_7_days_before_expiration.yaml @@ -1,13 +1,34 @@ +Description: Ensure Amazon Certificate Manager (ACM) certificates are renewed before their expiration. ID: aws_acm_certificates_renewal_7_days_before_expiration -Title: "AWS ACM Certificates Renewal (7 days before expiration)" -Description: "Ensure Amazon Certificate Manager (ACM) certificates are renewed before their expiration." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n certificate_arn as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN not_after - '7 days'::interval < now() THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN not_after < now() THEN 'certificate has been expired'\n WHEN not_after - '7 days'::interval < now() THEN 'certificate is about to expire in ' || not_after \n ELSE 'certificate is not going to expire soon'\n END AS reason,\n region,\n account_id\nFROM \n aws_acm_certificate\n" - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_resource_id, + og_account_id, + CASE + WHEN not_after - '7 days'::interval < now() + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN not_after < now() + THEN 'certificate has been expired' + WHEN not_after - '7 days'::interval < now() + THEN 'certificate is about to expire in ' || not_after + ELSE 'certificate is not going to expire soon' + END AS reason, + region, + account_id + FROM + aws_acm_certificate Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +39,4 @@ Tags: - AWS Certificate Manager score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: AWS ACM Certificates Renewal (7 days before expiration) \ No newline at end of file diff --git a/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_validity.yaml b/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_validity.yaml old mode 100755 new mode 100644 index b38f9887d..534e39a29 --- a/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_validity.yaml +++ b/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_validity.yaml @@ -1,13 +1,32 @@ +Description: Ensure expired SSL/TLS certificates are removed from AWS Certificate Manager (ACM). ID: aws_acm_certificates_validity -Title: "AWS ACM Certificates Validity" -Description: "Ensure expired SSL/TLS certificates are removed from AWS Certificate Manager (ACM)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n certificate_arn as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN status = 'EXPIRED' then 'skip'\n WHEN status = 'PENDING_VALIDATION' THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN status = 'EXPIRED' then 'certificate has been expired'\n WHEN status = 'PENDING_VALIDATION' THEN 'certificate validation is pending' \n ELSE 'certificate has been validated'\n END AS reason,\n region,\n account_id\nFROM \n aws_acm_certificate\n" - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_resource_id, + og_account_id, + CASE + WHEN status = 'EXPIRED' THEN 'skip' + WHEN status = 'PENDING_VALIDATION' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status = 'EXPIRED' THEN 'certificate has been expired' + WHEN status = 'PENDING_VALIDATION' THEN 'certificate validation is pending' + ELSE 'certificate has been validated' + END AS reason, + region, + account_id + FROM + aws_acm_certificate Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +37,4 @@ Tags: - AWS Certificate Manager score_tags: - Tolerate Failures -IntegrationType: - - aws_cloud_account +Title: AWS ACM Certificates Validity \ No newline at end of file diff --git a/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_with_wildcard_domain_names.yaml b/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_with_wildcard_domain_names.yaml old mode 100755 new mode 100644 index 0afdd438b..c9509b5f8 --- a/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_with_wildcard_domain_names.yaml +++ b/compliance/controls/baseline/aws/acm_certificate/aws_acm_certificates_with_wildcard_domain_names.yaml @@ -1,13 +1,30 @@ +Description: Ensure that wildcard certificates issued by Amazon Certificate Manager (ACM) or imported to ACM are not in use. ID: aws_acm_certificates_with_wildcard_domain_names -Title: "AWS ACM Certificates with Wildcard Domain Names" -Description: "Ensure that wildcard certificates issued by Amazon Certificate Manager (ACM) or imported to ACM are not in use." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n certificate_arn as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN domain_name LIKE '*%' then 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN domain_name LIKE '*%' then 'wildcard domain name certificate is used'\n ELSE 'single domain name certificate is used'\n END AS reason,\n region,\n account_id\nFROM \n aws_acm_certificate\n" - PrimaryTable: aws_acm_certificate ListOfTables: - aws_acm_certificate Parameters: [] + PrimaryTable: aws_acm_certificate + QueryToExecute: | + SELECT + certificate_arn AS resource, + og_resource_id, + og_account_id, + CASE + WHEN domain_name LIKE '*' THEN 'ALARM' + ELSE 'OK' + END AS status, + CASE + WHEN domain_name LIKE '*' THEN 'WILDCARD DOMAIN NAME CERTIFICATE IS USED' + ELSE 'SINGLE DOMAIN NAME CERTIFICATE IS USED' + END AS reason, + region, + account_id + FROM + aws_acm_certificate Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS Certificate Manager score_tags: - Tolerate Failures -IntegrationType: - - aws_cloud_account +Title: AWS ACM Certificates with Wildcard Domain Names \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_backup_service_lifecycle_configuration.yaml b/compliance/controls/baseline/aws/backup/aws_backup_service_lifecycle_configuration.yaml old mode 100755 new mode 100644 index df94b1456..6f6736257 --- a/compliance/controls/baseline/aws/backup/aws_backup_service_lifecycle_configuration.yaml +++ b/compliance/controls/baseline/aws/backup/aws_backup_service_lifecycle_configuration.yaml @@ -1,29 +1,9 @@ +Description: Ensure Amazon Backup plans have a compliant lifecycle configuration enabled. ID: aws_backup_service_lifecycle_configuration -Title: "AWS Backup Service Lifecycle Configuration" -Description: "Ensure Amazon Backup plans have a compliant lifecycle configuration enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - account_id || ' backup region setting in ' || region as resource, - og_resource_id, - og_account_id, - case - when r -> 'Lifecycle' ->> 'DeleteAfterDays' is null and r -> 'Lifecycle' ->> 'MoveToColdStorageAfterDays' is null then 'alarm' - when r -> 'Lifecycle' ->> 'DeleteAfterDays' <> '{{.awsBackupPlanDeleteAfterDays}}' or r -> 'Lifecycle' ->> 'MoveToColdStorageAfterDays' <> '{{.awsBackupPlanMoveToColdStorageAfterDays}}' then 'alarm' - else 'ok' - end as status, - case - when r -> 'Lifecycle' ->> 'DeleteAfterDays' is null and r -> 'Lifecycle' ->> 'MoveToColdStorageAfterDays' is null then 'there is no lifecycle configuration enabled' - when r -> 'Lifecycle' ->> 'DeleteAfterDays' <> '{{.awsBackupPlanDeleteAfterDays}}' or r -> 'Lifecycle' ->> 'MoveToColdStorageAfterDays' <> '{{.awsBackupPlanMoveToColdStorageAfterDays}}' then 'lifecycle configuration is not compatible with your setting' - else 'lifecycle configuration is compatible with your setting' - end as reason, - region, - account_id - from - aws_backup_plan, - jsonb_array_elements(rules) as r - PrimaryTable: aws_backup_plan ListOfTables: - aws_backup_plan Parameters: @@ -31,11 +11,39 @@ Query: Required: true - Key: awsBackupPlanMoveToColdStorageAfterDays Required: true + PrimaryTable: aws_backup_plan + QueryToExecute: | + SELECT + account_id || ' backup region setting in ' || region AS resource, + og_resource_id, + og_account_id, + CASE + WHEN r -> 'Lifecycle' ->> 'DeleteAfterDays' IS NULL + AND r -> 'Lifecycle' ->> 'MoveToColdStorageAfterDays' IS NULL + THEN 'alarm' + WHEN r -> 'Lifecycle' ->> 'DeleteAfterDays' <> '{{.awsBackupPlanDeleteAfterDays}}' + OR r -> 'Lifecycle' ->> 'MoveToColdStorageAfterDays' <> '{{.awsBackupPlanMoveToColdStorageAfterDays}}' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN r -> 'Lifecycle' ->> 'DeleteAfterDays' IS NULL + AND r -> 'Lifecycle' ->> 'MoveToColdStorageAfterDays' IS NULL + THEN 'there is no lifecycle configuration enabled' + WHEN r -> 'Lifecycle' ->> 'DeleteAfterDays' <> '{{.awsBackupPlanDeleteAfterDays}}' + OR r -> 'Lifecycle' ->> 'MoveToColdStorageAfterDays' <> '{{.awsBackupPlanMoveToColdStorageAfterDays}}' + THEN 'lifecycle configuration is not compatible with your setting' + ELSE 'lifecycle configuration is compatible with your setting' + END AS reason, + region, + account_id + FROM + aws_backup_plan, + jsonb_array_elements(rules) AS r Severity: medium Tags: platform_score_cloud_service_name: - AWS Backup score_service_name: - AWS Backup -IntegrationType: - - aws_cloud_account +Title: AWS Backup Service Lifecycle Configuration \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_check_for_protected_amazon_backup_resource_types.yaml b/compliance/controls/baseline/aws/backup/aws_check_for_protected_amazon_backup_resource_types.yaml old mode 100755 new mode 100644 index d65e7b332..b86f3acde --- a/compliance/controls/baseline/aws/backup/aws_check_for_protected_amazon_backup_resource_types.yaml +++ b/compliance/controls/baseline/aws/backup/aws_check_for_protected_amazon_backup_resource_types.yaml @@ -1,36 +1,36 @@ +Description: Ensure that the appropriate resource types are protected by Amazon Backup within your AWS account. ID: aws_check_for_protected_amazon_backup_resource_types -Title: "Check for Protected Amazon Backup Resource Types" -Description: "Ensure that the appropriate resource types are protected by Amazon Backup within your AWS account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_backup_region_settings + Parameters: + - Key: awsBackupResourceTypeOptInPreference + Required: true + PrimaryTable: aws_backup_region_settings QueryToExecute: | - select - account_id || ' backup region setting in ' || region as resource, + SELECT + account_id || ' backup region setting in ' || region AS resource, og_resource_id, og_account_id, - case - when resource_type_opt_in_preference::jsonb='{{.awsBackupResourceTypeOptInPreference}}'::jsonb then 'ok' - else 'alarm' - end as status, - case - when resource_type_opt_in_preference::jsonb='{{.awsBackupResourceTypeOptInPreference}}'::jsonb then account_id || ' backup region setting in ' || region || ' is compliant.' - else account_id || ' backup region setting in ' || region || ' is not compliant.' - end as reason, + CASE + WHEN resource_type_opt_in_preference::jsonb = '{{.awsBackupResourceTypeOptInPreference}}'::jsonb THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN resource_type_opt_in_preference::jsonb = '{{.awsBackupResourceTypeOptInPreference}}'::jsonb THEN account_id || ' backup region setting in ' || region || ' is compliant.' + ELSE account_id || ' backup region setting in ' || region || ' is not compliant.' + END AS reason, region, account_id - from + FROM aws_backup_region_settings - PrimaryTable: aws_backup_region_settings - ListOfTables: - - aws_backup_region_settings - Parameters: - - Key: awsBackupResourceTypeOptInPreference - Required: true Severity: medium Tags: platform_score_cloud_service_name: - AWS Backup score_service_name: - AWS Backup -IntegrationType: - - aws_cloud_account +Title: Check for Protected Amazon Backup Resource Types \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_configure_aws_backup_vault_access_policy.yaml b/compliance/controls/baseline/aws/backup/aws_configure_aws_backup_vault_access_policy.yaml old mode 100755 new mode 100644 index 820e5b257..52a78a5ea --- a/compliance/controls/baseline/aws/backup/aws_configure_aws_backup_vault_access_policy.yaml +++ b/compliance/controls/baseline/aws/backup/aws_configure_aws_backup_vault_access_policy.yaml @@ -1,39 +1,46 @@ +Description: Prevent deletion of backups using an Amazon Backup vault resource-based access policy. ID: aws_configure_aws_backup_vault_access_policy -Title: "Configure AWS Backup Vault Access Policy" -Description: "Prevent deletion of backups using an Amazon Backup vault resource-based access policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_backup_vault + Parameters: [] + PrimaryTable: aws_backup_vault QueryToExecute: | - select - name as resource, + SELECT + name AS resource, og_resource_id, og_account_id, - case - when policy is null then 'alarm' - when exists( - select 1 - from jsonb_array_elements(policy -> 'Statement') as s - where ((s ->> 'Effect') = 'Deny') and ((s ->> 'Action') LIKE '%backup:DeleteRecoveryPoint%') - ) then 'ok' - else 'alarm' - end as status, - case - when policy is null then 'there is no policy defined' - when exists( - select 1 - from jsonb_array_elements(policy -> 'Statement') as s - where ((s ->> 'Effect') = 'Deny') and ((s ->> 'Action') LIKE '%backup:DeleteRecoveryPoint%') - ) then 'has deletion protection enabled for its backups.' - else 'does not have deletion protection enabled for its backups.' - end as reason, + CASE + WHEN policy IS NULL THEN 'alarm' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(policy -> 'Statement') AS s + WHERE + (s ->> 'Effect') = 'Deny' + AND + (s ->> 'Action') LIKE '%backup:DeleteRecoveryPoint%' + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN policy IS NULL THEN 'there is no policy defined' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(policy -> 'Statement') AS s + WHERE + (s ->> 'Effect') = 'Deny' + AND + (s ->> 'Action') LIKE '%backup:DeleteRecoveryPoint%' + ) THEN 'has deletion protection enabled for its backups.' + ELSE 'does not have deletion protection enabled for its backups.' + END AS reason, region, account_id - from + FROM aws_backup_vault - PrimaryTable: aws_backup_vault - ListOfTables: - - aws_backup_vault - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -44,5 +51,4 @@ Tags: - AWS Backup score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Configure AWS Backup Vault Access Policy \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_dynamodb_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml b/compliance/controls/baseline/aws/backup/aws_dynamodb_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml old mode 100755 new mode 100644 index 885c8354a..47ac73804 --- a/compliance/controls/baseline/aws/backup/aws_dynamodb_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml +++ b/compliance/controls/baseline/aws/backup/aws_dynamodb_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml @@ -1,14 +1,48 @@ +Description: Ensure all DynamoDB are covered by a backup plan with a minimum of Life Cycle Policy 35 days ID: aws_dynamodb_instances_have_backup_with_lifecyclepolicy_above_35_days -Title: "Dynamodb Instances have backup with lifecyclepolicy above 35 days" -Description: "Ensure all DynamoDB are covered by a backup plan with a minimum of Life Cycle Policy 35 days" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH points AS (\n SELECT recovery_point_arn, resource_arn\n FROM aws_backup_recovery_point \n WHERE now() - creation_date < '35 days'::interval and (lifecycle ->> 'DeleteAfterDays')::INT >= 35 \n and resource_type = 'DynamoDB' and status = 'COMPLETED')\n\nselect\n t.arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when p.recovery_point_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when p.recovery_point_arn is null then 'lacks a backup configuration with a minimum of 35 days'\n else ''\n end as reason\n , region, account_id \nfrom \n aws_dynamodb_table as t\n left join points as p on t.arn = p.resource_arn\n" - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_backup_recovery_point - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + WITH points AS ( + SELECT + recovery_point_arn, + resource_arn + FROM + aws_backup_recovery_point + WHERE + NOW() - creation_date < '35 days'::interval + AND (lifecycle ->> 'DeleteAfterDays')::INT >= 35 + AND resource_type = 'DynamoDB' + AND status = 'COMPLETED' + ) + + SELECT + t.arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'lacks a backup configuration with a minimum of 35 days' + ELSE '' + END AS reason, + region, + account_id + FROM + aws_dynamodb_table AS t + LEFT JOIN + points AS p + ON + t.arn = p.resource_arn Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +53,4 @@ Tags: - Amazon DynamoDB score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: Dynamodb Instances have backup with lifecyclepolicy above 35 days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_dynamodb_instances_have_backup_withing_48_hours.yaml b/compliance/controls/baseline/aws/backup/aws_dynamodb_instances_have_backup_withing_48_hours.yaml old mode 100755 new mode 100644 index f1314a246..cafd953fa --- a/compliance/controls/baseline/aws/backup/aws_dynamodb_instances_have_backup_withing_48_hours.yaml +++ b/compliance/controls/baseline/aws/backup/aws_dynamodb_instances_have_backup_withing_48_hours.yaml @@ -1,14 +1,40 @@ +Description: Ensure all DynamoDB have a minimum of one restore point time in the last 48 hrs ID: aws_dynamodb_instances_have_backup_withing_48_hours -Title: "Dynamodb Instances have backup withing 48 hours" -Description: "Ensure all Dynamodb have a minimum of one restore point time in the last 48 hrs" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH points AS (\n SELECT recovery_point_arn, resource_arn\n FROM aws_backup_recovery_point \n WHERE now() - creation_date < '48 hours'::interval \n and resource_type = 'DynamoDB' and status = 'COMPLETED')\n\nselect\n t.arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when p.recovery_point_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when p.recovery_point_arn is null then 'lacks a backup with last 48 hours'\n else ''\n end as reason\n , region, account_id \nfrom \n aws_dynamodb_table as t\n left join points as p on t.arn = p.resource_arn\n" - PrimaryTable: aws_dynamodb_table ListOfTables: - aws_backup_recovery_point - aws_dynamodb_table Parameters: [] + PrimaryTable: aws_dynamodb_table + QueryToExecute: | + WITH points AS ( + SELECT recovery_point_arn, resource_arn + FROM aws_backup_recovery_point + WHERE now() - creation_date < '48 hours'::interval + AND resource_type = 'DynamoDB' + AND status = 'COMPLETED' + ) + + SELECT + t.arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'lacks a backup with last 48 hours' + ELSE '' + END AS reason, + region, + account_id + FROM + aws_dynamodb_table AS t + LEFT JOIN points AS p ON t.arn = p.resource_arn Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +45,4 @@ Tags: - Amazon DynamoDB score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: Dynamodb Instances have backup within 48 hours \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_ebs_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml b/compliance/controls/baseline/aws/backup/aws_ebs_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml old mode 100755 new mode 100644 index 6c29584ca..f5be38510 --- a/compliance/controls/baseline/aws/backup/aws_ebs_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml +++ b/compliance/controls/baseline/aws/backup/aws_ebs_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml @@ -1,14 +1,48 @@ +Description: Ensure all EBS are covered by a backup plan with a minimum of Life Cycle Policy 35 days ID: aws_ebs_instances_have_backup_with_lifecyclepolicy_above_35_days -Title: "EBS Instances have backup with lifecyclepolicy above 35 days" -Description: "Ensure all EBS are covered by a backup plan with a minimum of Life Cycle Policy 35 days" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH points AS (\n SELECT recovery_point_arn, resource_arn\n FROM aws_backup_recovery_point \n WHERE now() - creation_date < '35 days'::interval and (lifecycle ->> 'DeleteAfterDays')::INT >= 35 \n and resource_type = 'EBS' and status = 'COMPLETED')\n\nselect\n v.arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when p.recovery_point_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when p.recovery_point_arn is null then 'lacks a backup configuration with a minimum of 35 days'\n else ''\n end as reason\n , region, account_id \nfrom \n aws_ebs_volume as v\n left join points as p on v.arn = p.resource_arn\n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_backup_recovery_point - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + WITH points AS ( + SELECT + recovery_point_arn, + resource_arn + FROM + aws_backup_recovery_point + WHERE + now() - creation_date < '35 days'::interval + AND (lifecycle ->> 'DeleteAfterDays')::INT >= 35 + AND resource_type = 'EBS' + AND status = 'COMPLETED' + ) + + SELECT + v.arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'lacks a backup configuration with a minimum of 35 days' + ELSE '' + END AS reason, + region, + account_id + FROM + aws_ebs_volume AS v + LEFT JOIN + points AS p + ON + v.arn = p.resource_arn Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +53,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: EBS Instances have backup with lifecyclepolicy above 35 days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_ebs_instances_have_backup_withing_rpo_period.yaml b/compliance/controls/baseline/aws/backup/aws_ebs_instances_have_backup_withing_rpo_period.yaml old mode 100755 new mode 100644 index c5ff21f4f..88806dce6 --- a/compliance/controls/baseline/aws/backup/aws_ebs_instances_have_backup_withing_rpo_period.yaml +++ b/compliance/controls/baseline/aws/backup/aws_ebs_instances_have_backup_withing_rpo_period.yaml @@ -1,16 +1,50 @@ +Description: AWS EBS Storage Volumes that are connected need to have restorable backup within the defined period ID: aws_ebs_instances_have_backup_withing_rpo_period -Title: "Attached EBS Storage Volumes restoration needs meet RPO Standard" -Description: "AWS EBS Storage Volumes that are connected need to have restorable backup within the defined period" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH all_backup AS (\n SELECT recovery_point_arn, resource_arn, creation_date\n FROM aws_backup_recovery_point \n WHERE now() - creation_date < '2 week'::interval \n and resource_type = 'EBS' and status = 'COMPLETED'),\npoints AS (\n SELECT recovery_point_arn, resource_arn\n FROM aws_backup_recovery_point \n WHERE now() - creation_date < '{{.awsEbsInstancesBackupPeriod}} hours'::interval \n and resource_type = 'EBS' and status = 'COMPLETED')\n\nselect\n v.arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when p.recovery_point_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when p.recovery_point_arn is null and a.recovery_point_arn is null then 'there is no backup for this resource'\n when p.recovery_point_arn is null then 'last backup at ' || a.creation_date::text\n else ''\n end as reason\n , region, account_id \nfrom \n aws_ebs_volume as v\n left join points as p on v.arn = p.resource_arn\n left join all_backup as a on v.arn = a.resource_arn\n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_backup_recovery_point - aws_ebs_volume Parameters: - Key: awsEbsInstancesBackupPeriod Required: true + PrimaryTable: aws_ebs_volume + QueryToExecute: | + WITH all_backup AS ( + SELECT recovery_point_arn, resource_arn, creation_date + FROM aws_backup_recovery_point + WHERE now() - creation_date < '2 week'::interval + AND resource_type = 'EBS' + AND status = 'COMPLETED' + ), points AS ( + SELECT recovery_point_arn, resource_arn + FROM aws_backup_recovery_point + WHERE now() - creation_date < '{{.awsEbsInstancesBackupPeriod}} hours'::interval + AND resource_type = 'EBS' + AND status = 'COMPLETED' + ) + + SELECT + v.arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN p.recovery_point_arn IS NULL AND a.recovery_point_arn IS NULL THEN 'there is no backup for this resource' + WHEN p.recovery_point_arn IS NULL THEN 'last backup at ' || a.creation_date::text + ELSE '' + END AS reason, + region, + account_id + FROM + aws_ebs_volume AS v + LEFT JOIN points AS p ON v.arn = p.resource_arn + LEFT JOIN all_backup AS a ON v.arn = a.resource_arn Severity: medium Tags: platform_score_cloud_service_name: @@ -21,5 +55,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: Attached EBS Storage Volumes restoration needs meet RPO Standard \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_ec2_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml b/compliance/controls/baseline/aws/backup/aws_ec2_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml old mode 100755 new mode 100644 index cdac4611e..2f4a56456 --- a/compliance/controls/baseline/aws/backup/aws_ec2_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml +++ b/compliance/controls/baseline/aws/backup/aws_ec2_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml @@ -1,14 +1,48 @@ +Description: Ensure all EC2 are covered by a backup plan with a minimum of Life Cycle Policy 35 days ID: aws_ec2_instances_have_backup_with_lifecyclepolicy_above_35_days -Title: "EC2 Instances have backup with lifecyclepolicy above 35 days" -Description: "Ensure all EC2 are covered by a backup plan with a minimum of Life Cycle Policy 35 days" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH points AS (\n SELECT recovery_point_arn, resource_arn\n FROM aws_backup_recovery_point \n WHERE now() - creation_date < '35 days'::interval and (lifecycle ->> 'DeleteAfterDays')::INT >= 35 \n and resource_type = 'EC2' and status = 'COMPLETED')\n\nselect\n i.arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when p.recovery_point_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when p.recovery_point_arn is null then 'lacks a backup configuration with a minimum of 35 days'\n else ''\n end as reason\n , region, account_id \nfrom \n aws_ec2_instance as i\n left join points as p on i.arn = p.resource_arn\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_backup_recovery_point - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH points AS ( + SELECT + recovery_point_arn, + resource_arn + FROM + aws_backup_recovery_point + WHERE + now() - creation_date < '35 days'::interval AND + (lifecycle ->> 'DeleteAfterDays')::INT >= 35 AND + resource_type = 'EC2' AND + status = 'COMPLETED' + ) + + SELECT + i.arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'lacks a backup configuration with a minimum of 35 days' + ELSE '' + END AS reason, + region, + account_id + FROM + aws_ec2_instance AS i + LEFT JOIN + points AS p + ON + i.arn = p.resource_arn Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +53,4 @@ Tags: - AWS EC2 score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: EC2 Instances have backup with lifecyclepolicy above 35 days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_ec2_instances_have_backup_withing_48_hours.yaml b/compliance/controls/baseline/aws/backup/aws_ec2_instances_have_backup_withing_48_hours.yaml old mode 100755 new mode 100644 index 708f93031..66f9586dc --- a/compliance/controls/baseline/aws/backup/aws_ec2_instances_have_backup_withing_48_hours.yaml +++ b/compliance/controls/baseline/aws/backup/aws_ec2_instances_have_backup_withing_48_hours.yaml @@ -1,14 +1,64 @@ +Description: Verify that EC2 Instances, excluding shutdowns, spot VMs, and those under 24 hrs old, have at least one restore point in the past 48 hrs. ID: aws_ec2_instances_have_backup_withing_48_hours -Title: "Stateful EC2 Instances have operational backup within 48 hours." -Description: "Verify that EC2 Instances, excluding shutdowns, spot VMs, and those under 24 hrs old, have at least one restore point in the past 48 hrs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH all_backup AS (\n SELECT recovery_point_arn, resource_arn, creation_date\n FROM aws_backup_recovery_point \n WHERE now() - creation_date < '48 hours'::interval \n and resource_type = 'EC2' and status = 'COMPLETED'),\n points AS (\n SELECT recovery_point_arn, resource_arn\n FROM aws_backup_recovery_point \n WHERE now() - creation_date < '48 hours'::interval \n and resource_type = 'EC2' and status = 'COMPLETED')\n select\n v.arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when p.recovery_point_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when p.recovery_point_arn is null and a.recovery_point_arn is null then 'there is no backup for this resource'\n when p.recovery_point_arn is null then 'last backup at ' || a.creation_date::text\n else 'Last backup at ' || a.creation_date::text\n end as reason\n , region, account_id \n from \n aws_ec2_instance as v\n left join points as p on v.arn = p.resource_arn\n left join all_backup as a on v.arn = a.resource_arn\n where\n v.instance_lifecycle != 'spot'\n and instance_state = 'running'\n and state_transition_time <= (current_date - interval '24 hours'\n )\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_backup_recovery_point - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH all_backup AS ( + SELECT + recovery_point_arn, + resource_arn, + creation_date + FROM + aws_backup_recovery_point + WHERE + now() - creation_date < '48 hours'::interval + AND resource_type = 'EC2' + AND status = 'COMPLETED' + ), + points AS ( + SELECT + recovery_point_arn, + resource_arn + FROM + aws_backup_recovery_point + WHERE + now() - creation_date < '48 hours'::interval + AND resource_type = 'EC2' + AND status = 'COMPLETED' + ) + SELECT + v.arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN p.recovery_point_arn IS NULL + AND a.recovery_point_arn IS NULL THEN 'there is no backup for this resource' + WHEN p.recovery_point_arn IS NULL THEN 'last backup at ' || a.creation_date::text + ELSE 'Last backup at ' || a.creation_date::text + END AS reason, + region, + account_id + FROM + aws_ec2_instance AS v + LEFT JOIN + points AS p ON v.arn = p.resource_arn + LEFT JOIN + all_backup AS a ON v.arn = a.resource_arn + WHERE + v.instance_lifecycle != 'spot' + AND instance_state = 'running' + AND state_transition_time <= (current_date - INTERVAL '24 hours') Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +69,4 @@ Tags: - AWS EC2 score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: Stateful EC2 Instances have operational backup within 48 hours. \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_efs_files_have_backup_with_lifecyclepolicy_above_35_days.yaml b/compliance/controls/baseline/aws/backup/aws_efs_files_have_backup_with_lifecyclepolicy_above_35_days.yaml old mode 100755 new mode 100644 index 8d37e1f27..1463d0536 --- a/compliance/controls/baseline/aws/backup/aws_efs_files_have_backup_with_lifecyclepolicy_above_35_days.yaml +++ b/compliance/controls/baseline/aws/backup/aws_efs_files_have_backup_with_lifecyclepolicy_above_35_days.yaml @@ -1,14 +1,48 @@ +Description: Ensure all EFS files are covered by a backup plan with a minimum of Life Cycle Policy 35 days ID: aws_efs_files_have_backup_with_lifecyclepolicy_above_35_days -Title: "EFS files have backup with lifecyclepolicy above 35 days" -Description: "Ensure all EFS files are covered by a backup plan with a minimum of Life Cycle Policy 35 days" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH points AS (\n SELECT recovery_point_arn, resource_arn\n FROM aws_backup_recovery_point \n WHERE now() - creation_date < '35 days'::interval and (lifecycle ->> 'DeleteAfterDays')::INT >= 35 \n and resource_type = 'EFS' and status = 'COMPLETED')\n\nselect\n f.arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when p.recovery_point_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when p.recovery_point_arn is null then 'lacks a backup configuration with a minimum of 35 days'\n else ''\n end as reason\n , region, account_id \nfrom \n aws_efs_file_system as f\n left join points as p on f.arn = p.resource_arn\n" - PrimaryTable: aws_efs_file_system ListOfTables: - aws_backup_recovery_point - aws_efs_file_system Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + WITH points AS ( + SELECT + recovery_point_arn, + resource_arn + FROM + aws_backup_recovery_point + WHERE + now() - creation_date < '35 days'::interval + AND (lifecycle ->> 'DeleteAfterDays')::INT >= 35 + AND resource_type = 'EFS' + AND status = 'COMPLETED' + ) + + SELECT + f.arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'lacks a backup configuration with a minimum of 35 days' + ELSE '' + END AS reason, + region, + account_id + FROM + aws_efs_file_system AS f + LEFT JOIN + points AS p + ON + f.arn = p.resource_arn Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +53,4 @@ Tags: - Amazon Elastic File System (EFS) score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: EFS files have backup with lifecyclepolicy above 35 days \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_efs_files_have_backup_withing_48_hours.yaml b/compliance/controls/baseline/aws/backup/aws_efs_files_have_backup_withing_48_hours.yaml old mode 100755 new mode 100644 index 31b00669e..354a42ca8 --- a/compliance/controls/baseline/aws/backup/aws_efs_files_have_backup_withing_48_hours.yaml +++ b/compliance/controls/baseline/aws/backup/aws_efs_files_have_backup_withing_48_hours.yaml @@ -1,14 +1,46 @@ +Description: Ensure all EFS files have a minimum of one restore point time in the last 48 hrs ID: aws_efs_files_have_backup_withing_48_hours -Title: "EFS files have backup withing 48 hours" -Description: "Ensure all EFS files have a minimum of one restore point time in the last 48 hrs" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH points AS (\n SELECT recovery_point_arn, resource_arn\n FROM aws_backup_recovery_point \n WHERE now() - creation_date < '48 hours'::interval \n and resource_type = 'EFS' and status = 'COMPLETED')\n\nselect\n f.arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when p.recovery_point_arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when p.recovery_point_arn is null then 'lacks a backup with last 48 hours'\n else ''\n end as reason\n , region, account_id \nfrom \n aws_efs_file_system as f\n left join points as p on f.arn = p.resource_arn\n" - PrimaryTable: aws_efs_file_system ListOfTables: - aws_backup_recovery_point - aws_efs_file_system Parameters: [] + PrimaryTable: aws_efs_file_system + QueryToExecute: | + WITH points AS ( + SELECT + recovery_point_arn, + resource_arn + FROM + aws_backup_recovery_point + WHERE + NOW() - creation_date < '48 hours'::interval + AND resource_type = 'EFS' + AND status = 'COMPLETED' + ) + SELECT + f.arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN p.recovery_point_arn IS NULL THEN 'lacks a backup with last 48 hours' + ELSE '' + END AS reason, + region, + account_id + FROM + aws_efs_file_system AS f + LEFT JOIN + points AS p + ON + f.arn = p.resource_arn Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +51,4 @@ Tags: - Amazon Elastic File System (EFS) score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: EFS files have backup withing 48 hours \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_enable_alert_notifications_for_failed_backup_jobs.yaml b/compliance/controls/baseline/aws/backup/aws_enable_alert_notifications_for_failed_backup_jobs.yaml old mode 100755 new mode 100644 index 8715b28df..2cfc24430 --- a/compliance/controls/baseline/aws/backup/aws_enable_alert_notifications_for_failed_backup_jobs.yaml +++ b/compliance/controls/baseline/aws/backup/aws_enable_alert_notifications_for_failed_backup_jobs.yaml @@ -1,29 +1,30 @@ +Description: Ensure that email notifications for unsuccessful backup jobs are enabled. ID: aws_enable_alert_notifications_for_failed_backup_jobs -Title: "Enable Alert Notifications for Failed Backup Jobs" -Description: "Ensure that email notifications for unsuccessful backup jobs are enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_backup_vault + Parameters: [] + PrimaryTable: aws_backup_vault QueryToExecute: | - select - name as resource, + SELECT + name AS resource, og_resource_id, og_account_id, - case - when backup_vault_events::text like '%BACKUP_JOB_FAILED%' then 'ok' - else 'alarm' - end as status, - case - when backup_vault_events::text like '%BACKUP_JOB_FAILED%' then 'Backup vault is configured to send alert notifications for failed Amazon Backup jobs.' - else 'Backup vault is not configured to send alert notifications for failed Amazon Backup jobs.' - end as reason, + CASE + WHEN backup_vault_events::TEXT LIKE '%BACKUP_JOB_FAILED%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN backup_vault_events::TEXT LIKE '%BACKUP_JOB_FAILED%' THEN 'Backup vault is configured to send alert notifications for failed Amazon Backup jobs.' + ELSE 'Backup vault is not configured to send alert notifications for failed Amazon Backup jobs.' + END AS reason, region, account_id - from + FROM aws_backup_vault - PrimaryTable: aws_backup_vault - ListOfTables: - - aws_backup_vault - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS Backup score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Enable Alert Notifications for Failed Backup Jobs \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_rds_database_instances_have_a_minimum_acceptable_backup_policy.yaml b/compliance/controls/baseline/aws/backup/aws_rds_database_instances_have_a_minimum_acceptable_backup_policy.yaml old mode 100755 new mode 100644 index 30aecb539..085e435d4 --- a/compliance/controls/baseline/aws/backup/aws_rds_database_instances_have_a_minimum_acceptable_backup_policy.yaml +++ b/compliance/controls/baseline/aws/backup/aws_rds_database_instances_have_a_minimum_acceptable_backup_policy.yaml @@ -1,28 +1,29 @@ +Description: Check for all AWS RDS Database Instances are covered by configured to be backup for a minimum time period ID: aws_rds_database_instances_have_a_minimum_acceptable_backup_policy -Title: "AWS RDS Database Instances have a minimum acceptable backup policy" -Description: "Check for all AWS RDS Database Instances are covered by configured to be backup for a minimum time period" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_rds_db_instance + Parameters: + - Key: awsRdsBaselineRetentionPeriodDays + Required: true + PrimaryTable: aws_rds_db_instance QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_account_id, og_resource_id, - case - when backup_retention_period < '{{.awsRdsBaselineRetentionPeriodDays}}'::INT then 'alarm' - else 'ok' - end as status, - title || ' backup retention period set to ' || backup_retention_period || '.' as reason, + CASE + WHEN backup_retention_period < '{{.awsRdsBaselineRetentionPeriodDays}}'::INT THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' backup retention period set to ' || backup_retention_period || '.' AS reason, region, account_id - from + FROM aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance - ListOfTables: - - aws_rds_db_instance - Parameters: - - Key: awsRdsBaselineRetentionPeriodDays - Required: true Severity: medium Tags: platform_score_cloud_service_name: @@ -33,5 +34,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: AWS RDS Database Instances have a minimum acceptable backup policy \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_rds_database_instances_must_have_a_minimum_acceptable_restore_time.yaml b/compliance/controls/baseline/aws/backup/aws_rds_database_instances_must_have_a_minimum_acceptable_restore_time.yaml old mode 100755 new mode 100644 index cd75a3375..bdf1d32b1 --- a/compliance/controls/baseline/aws/backup/aws_rds_database_instances_must_have_a_minimum_acceptable_restore_time.yaml +++ b/compliance/controls/baseline/aws/backup/aws_rds_database_instances_must_have_a_minimum_acceptable_restore_time.yaml @@ -1,16 +1,44 @@ +Description: Check for all AWS RDS Database Instances to see if they are meeting the required restore time defined. ID: aws_rds_database_instances_must_have_a_minimum_acceptable_restore_time -Title: "AWS RDS Database Instances must have a minimum acceptable restore time" -Description: "Check for all AWS RDS Database Instances to see if they are meeting the required restore time defined." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n i.arn as resource,\n i.og_account_id,\n i.og_resource_id,\n case\n when c.latest_restorable_time is not null then \n case\n when now() - c.latest_restorable_time < '{{.awsRdsBaselineRestorableTimeInHrs}} hours'::interval then 'ok'\n else 'alarm'\n end\n else\n case\n when now() - i.latest_restorable_time < '{{.awsRdsBaselineRestorableTimeInHrs}} hours'::interval then 'ok'\n else 'alarm'\n end\n end as status,\n case\n when c.latest_restorable_time is not null then \n i.title || ' backup retention period set to ' || c.latest_restorable_time || '.'\n else\n i.title || ' backup retention period set to ' || i.latest_restorable_time || '.'\n end as reason,\n i.region,\n i.account_id\n from\n aws_rds_db_instance as i\n left join aws_rds_db_cluster as c on i.db_cluster_identifier = c.db_cluster_identifier\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_cluster - aws_rds_db_instance Parameters: - Key: awsRdsBaselineRestorableTimeInHrs Required: true + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + i.arn AS resource, + i.og_account_id, + i.og_resource_id, + CASE + WHEN c.latest_restorable_time IS NOT NULL THEN + CASE + WHEN now() - c.latest_restorable_time < '{{.awsRdsBaselineRestorableTimeInHrs}} hours'::interval THEN 'ok' + ELSE 'alarm' + END + ELSE + CASE + WHEN now() - i.latest_restorable_time < '{{.awsRdsBaselineRestorableTimeInHrs}} hours'::interval THEN 'ok' + ELSE 'alarm' + END + END AS status, + CASE + WHEN c.latest_restorable_time IS NOT NULL THEN + i.title || ' backup retention period set to ' || c.latest_restorable_time || '.' + ELSE + i.title || ' backup retention period set to ' || i.latest_restorable_time || '.' + END AS reason, + i.region, + i.account_id + FROM + aws_rds_db_instance AS i + LEFT JOIN aws_rds_db_cluster AS c ON i.db_cluster_identifier = c.db_cluster_identifier Severity: medium Tags: platform_score_cloud_service_name: @@ -21,5 +49,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: AWS RDS Database Instances must have a minimum acceptable restore time \ No newline at end of file diff --git a/compliance/controls/baseline/aws/backup/aws_use_kms_customer_master_keys_for_aws_backup.yaml b/compliance/controls/baseline/aws/backup/aws_use_kms_customer_master_keys_for_aws_backup.yaml old mode 100755 new mode 100644 index b6c810e91..fcd71cbd1 --- a/compliance/controls/baseline/aws/backup/aws_use_kms_customer_master_keys_for_aws_backup.yaml +++ b/compliance/controls/baseline/aws/backup/aws_use_kms_customer_master_keys_for_aws_backup.yaml @@ -1,33 +1,35 @@ +Description: Ensure that your backups are encrypted at rest using KMS Customer Master Keys (CMKs). ID: aws_use_kms_customer_master_keys_for_aws_backup -Title: "Use KMS Customer Master Keys for AWS Backup" -Description: "Ensure that your backups are encrypted at rest using KMS Customer Master Keys (CMKs)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - name as resource, - v.og_resource_id, - v.og_account_id, - case - when k.arn is null then 'alarm' - when k.key_manager = 'CUSTOMER' then 'ok' - else 'alarm' - end as status, - case - when k.arn is null then name || ' is not using a master key' - when k.key_manager = 'CUSTOMER' then name || ' is using a customer master key' - else name || ' is using a AWS-managed master key' - end as reason, - V.region, - V.account_id - from - aws_backup_vault as v - left join aws_kms_key as k on v.encryption_key_arn = k.arn - PrimaryTable: aws_backup_vault ListOfTables: - aws_backup_vault - aws_kms_key Parameters: [] + PrimaryTable: aws_backup_vault + QueryToExecute: | + SELECT + name AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN k.arn IS NULL THEN 'alarm' + WHEN k.key_manager = 'CUSTOMER' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN k.arn IS NULL THEN name || ' is not using a master key' + WHEN k.key_manager = 'CUSTOMER' THEN name || ' is using a customer master key' + ELSE name || ' is using an AWS-managed master key' + END AS reason, + v.region, + v.account_id + FROM + aws_backup_vault AS v + LEFT JOIN + aws_kms_key AS k ON v.encryption_key_arn = k.arn Severity: high Tags: platform_score_cloud_service_name: @@ -38,5 +40,4 @@ Tags: - AWS Backup score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Use KMS Customer Master Keys for AWS Backup \ No newline at end of file diff --git a/compliance/controls/baseline/aws/dynamoDb/aws_unused_dynamodb_table.yaml b/compliance/controls/baseline/aws/dynamoDb/aws_unused_dynamodb_table.yaml old mode 100755 new mode 100644 index c42c15f6d..a754d3785 --- a/compliance/controls/baseline/aws/dynamoDb/aws_unused_dynamodb_table.yaml +++ b/compliance/controls/baseline/aws/dynamoDb/aws_unused_dynamodb_table.yaml @@ -1,38 +1,44 @@ +Description: Identify and remove any unused AWS DynamoDB tables to optimize AWS costs. ID: aws_unused_dynamodb_table -Title: "Unused DynamoDb Table" -Description: "Identify and remove any unused AWS DynamoDB tables to optimize AWS costs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_dynamodb_table + Parameters: [] + PrimaryTable: aws_dynamodb_table QueryToExecute: | - select - name as resource, + SELECT + name AS resource, og_resource_id, og_account_id, - case - when item_count::int = 0 then (SELECT cost FROM pennywise_cost_estimate where resource_type = 'aws::dynamodb::table' and resource_id = t.og_resource_id limit 1) - else 0 - end as cost_optimization, - case - when item_count::int = 0 then 'alarm' - else 'ok' - end as status, - case - when item_count::int = 0 then 'Dynamodb Table is unused' - else 'Dynamodb Table is being used' - end as reason, + CASE + WHEN item_count::int = 0 THEN ( + SELECT cost + FROM pennywise_cost_estimate + WHERE resource_type = 'aws::dynamodb::table' + AND resource_id = t.og_resource_id + LIMIT 1 + ) + ELSE 0 + END AS cost_optimization, + CASE + WHEN item_count::int = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN item_count::int = 0 THEN 'Dynamodb Table is unused' + ELSE 'Dynamodb Table is being used' + END AS reason, region, account_id - from - aws_dynamodb_table as t - PrimaryTable: aws_dynamodb_table - ListOfTables: - - aws_dynamodb_table - Parameters: [] + FROM + aws_dynamodb_table AS t Severity: medium Tags: platform_score_cloud_service_name: - Amazon DynamoDB score_service_name: - Amazon DynamoDB -IntegrationType: - - aws_cloud_account +Title: Unused DynamoDb Table \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ebs/aws_ebs_encrypted.yaml b/compliance/controls/baseline/aws/ebs/aws_ebs_encrypted.yaml old mode 100755 new mode 100644 index f7d37c7a0..bcd29acdc --- a/compliance/controls/baseline/aws/ebs/aws_ebs_encrypted.yaml +++ b/compliance/controls/baseline/aws/ebs/aws_ebs_encrypted.yaml @@ -1,31 +1,32 @@ +Description: Ensure EBS volumes are encrypted to meet security and encryption compliance requirements. Encryption is a key mechanism for you to ensure that you are in full control over who has access to your data. ID: aws_ebs_encrypted -Title: "EBS Volumes need to be encrypted" -Description: "Ensure EBS volumes are encrypted to meet security and encryption compliance requirements. Encryption is a key mechanism for you to ensure that you are in full control over who has access to your data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ebs_volume + Parameters: [] + PrimaryTable: aws_ebs_volume QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when encrypted then 'ok' - else 'alarm' - end as status, - case - when encrypted then volume_id || ' encrypted.' - else volume_id || ' not encrypted.' - end as reason, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN volume_id || ' encrypted.' + ELSE volume_id || ' not encrypted.' + END AS reason, region, account_id - from + FROM aws_ebs_volume - where + WHERE state = 'in-use' - PrimaryTable: aws_ebs_volume - ListOfTables: - - aws_ebs_volume - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: EBS Volumes need to be encrypted \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ebs/aws_ebs_encrypted_with_kms_customer_master_keys.yaml b/compliance/controls/baseline/aws/ebs/aws_ebs_encrypted_with_kms_customer_master_keys.yaml old mode 100755 new mode 100644 index 78974495b..ba0c17511 --- a/compliance/controls/baseline/aws/ebs/aws_ebs_encrypted_with_kms_customer_master_keys.yaml +++ b/compliance/controls/baseline/aws/ebs/aws_ebs_encrypted_with_kms_customer_master_keys.yaml @@ -1,33 +1,36 @@ +Description: Ensure EBS volumes are encrypted with CMKs to have full control over encrypting and decrypting data. ID: aws_ebs_encrypted_with_kms_customer_master_keys -Title: "EBS Encrypted With KMS Customer Master Keys" -Description: "Ensure EBS volumes are encrypted with CMKs to have full control over encrypting and decrypting data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - volume_id as resource, - v.og_resource_id, - v.og_account_id, - case - when kms_key_id is null then 'alarm' - when k.key_manager = 'CUSTOMER' then 'ok' - else 'alarm' - end as status, - case - when kms_key_id is null then volume_id || ' is not using a master key' - when k.key_manager = 'CUSTOMER' then volume_id || ' is using a customer master key' - else volume_id || ' is using a AWS-managed master key' - end as reason, - V.region, - V.account_id - from - aws_ebs_volume as v - left join aws_kms_key as k on v.kms_key_id = k.arn - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume - aws_kms_key Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + volume_id AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + WHEN k.key_manager = 'CUSTOMER' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN volume_id || ' is not using a master key' + WHEN k.key_manager = 'CUSTOMER' THEN volume_id || ' is using a customer master key' + ELSE volume_id || ' is using an AWS-managed master key' + END AS reason, + v.region, + v.account_id + FROM + aws_ebs_volume AS v + LEFT JOIN + aws_kms_key AS k + ON v.kms_key_id = k.arn Severity: high Tags: platform_score_cloud_service_name: @@ -38,5 +41,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: EBS Encrypted With KMS Customer Master Keys \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ebs/aws_ebs_public_snapshots.yaml b/compliance/controls/baseline/aws/ebs/aws_ebs_public_snapshots.yaml old mode 100755 new mode 100644 index 648fb0c89..2d88df668 --- a/compliance/controls/baseline/aws/ebs/aws_ebs_public_snapshots.yaml +++ b/compliance/controls/baseline/aws/ebs/aws_ebs_public_snapshots.yaml @@ -1,29 +1,30 @@ +Description: Ensure that your Amazon EBS volume snapshots are not accessible to all AWS accounts. ID: aws_ebs_public_snapshots -Title: "Amazon EBS Public Snapshots" -Description: "Ensure that your Amazon EBS volume snapshots are not accessible to all AWS accounts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ebs_snapshot + Parameters: [] + PrimaryTable: aws_ebs_snapshot QueryToExecute: | - select - 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':snapshot/' || snapshot_id as resource, + SELECT + 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':snapshot/' || snapshot_id AS resource, og_resource_id, og_account_id, - case - when create_volume_permissions @> '[{"Group": "all", "UserId": null}]' then 'alarm' - else 'ok' - end as status, - case - when create_volume_permissions @> '[{"Group": "all", "UserId": null}]' then title || ' is publicly restorable.' - else title || ' is not publicly restorable.' - end as reason, + CASE + WHEN create_volume_permissions @> '[{"Group": "all", "UserId": null}]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN create_volume_permissions @> '[{"Group": "all", "UserId": null}]' THEN title || ' is publicly restorable.' + ELSE title || ' is not publicly restorable.' + END AS reason, region, account_id - from + FROM aws_ebs_snapshot; - PrimaryTable: aws_ebs_snapshot - ListOfTables: - - aws_ebs_snapshot - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Amazon EBS Public Snapshots \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ebs/aws_ebs_snapshot_encrypted.yaml b/compliance/controls/baseline/aws/ebs/aws_ebs_snapshot_encrypted.yaml old mode 100755 new mode 100644 index 977607b9d..572cc4dd8 --- a/compliance/controls/baseline/aws/ebs/aws_ebs_snapshot_encrypted.yaml +++ b/compliance/controls/baseline/aws/ebs/aws_ebs_snapshot_encrypted.yaml @@ -1,29 +1,30 @@ +Description: Ensure Amazon EBS snapshots are encrypted to meet security and compliance requirements. ID: aws_ebs_snapshot_encrypted -Title: "EBS Snapshot Encrypted" -Description: "Ensure Amazon EBS snapshots are encrypted to meet security and compliance requirements." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ebs_snapshot + Parameters: [] + PrimaryTable: aws_ebs_snapshot QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when encrypted then 'ok' - else 'alarm' - end as status, - case - when encrypted then title || ' encryption enabled.' - else title || ' encryption disabled.' - end as reason, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN title || ' encryption enabled.' + ELSE title || ' encryption disabled.' + END AS reason, region, account_id - from + FROM aws_ebs_snapshot; - PrimaryTable: aws_ebs_snapshot - ListOfTables: - - aws_ebs_snapshot - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: EBS Snapshot Encrypted \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ebs/aws_ebs_volume_unused.yaml b/compliance/controls/baseline/aws/ebs/aws_ebs_volume_unused.yaml old mode 100755 new mode 100644 index d2b21c6b4..05311b10a --- a/compliance/controls/baseline/aws/ebs/aws_ebs_volume_unused.yaml +++ b/compliance/controls/baseline/aws/ebs/aws_ebs_volume_unused.yaml @@ -1,13 +1,38 @@ +Description: Identify any unused Elastic Block Store volumes to improve cost optimization and security. ID: aws_ebs_volume_unused -Title: "Unused EBS Volumes" -Description: "Identify any unused Elastic Block Store volumes to improve cost optimization and security." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n case\n when state = 'in-use' then 0\n else (SELECT cost FROM pennywise_cost_estimate where resource_type = 'aws::ec2::volume' and resource_id = v.og_resource_id limit 1)\n end as cost_optimization,\n case\n when state = 'in-use' then 'ok'\n else 'alarm'\n end as status,\n case\n when state = 'in-use' then title || ' attached to EC2 instance.'\n else title || ' not attached to EC2 instance.'\n end as reason\n \n , region, account_id\nfrom\n aws_ebs_volume v\n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + arn AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN state = 'in-use' THEN 0 + ELSE (SELECT cost + FROM pennywise_cost_estimate + WHERE resource_type = 'aws::ec2::volume' + AND resource_id = v.og_resource_id + LIMIT 1) + END AS cost_optimization, + CASE + WHEN state = 'in-use' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN state = 'in-use' THEN title || ' attached to EC2 instance.' + ELSE title || ' not attached to EC2 instance.' + END AS reason, + region, + account_id + FROM + aws_ebs_volume v Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +43,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Optimization -IntegrationType: - - aws_cloud_account +Title: Unused EBS Volumes \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ebs/aws_ebs_volumes_attached_to_stopped_ec2_instances.yaml b/compliance/controls/baseline/aws/ebs/aws_ebs_volumes_attached_to_stopped_ec2_instances.yaml old mode 100755 new mode 100644 index 0705b95cb..95fc39499 --- a/compliance/controls/baseline/aws/ebs/aws_ebs_volumes_attached_to_stopped_ec2_instances.yaml +++ b/compliance/controls/baseline/aws/ebs/aws_ebs_volumes_attached_to_stopped_ec2_instances.yaml @@ -1,14 +1,46 @@ +Description: Identify Amazon EBS volumes attached to stopped EC2 instances (i.e. unused EBS volumes). ID: aws_ebs_volumes_attached_to_stopped_ec2_instances -Title: "EBS Volumes Attached To Stopped EC2 Instances" -Description: "Identify Amazon EBS volumes attached to stopped EC2 instances (i.e. unused EBS volumes)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n v.volume_id as resource,\n v.og_resource_id,\n v.og_account_id,\n case\n when i.instance_state = 'running' then 0\n else (SELECT cost FROM pennywise_cost_estimate where resource_type = 'aws::ec2::volume' and resource_id = v.og_resource_id limit 1)\n end as cost_optimization,\n case\n when i.instance_state = 'running' then 'ok'\n else 'alarm'\n end as status,\n case\n when i.instance_state = 'running' then v.volume_id || ' is attached to a running instance'\n else v.volume_id || ' is attached to a stopped instance'\n end as reason,\n v.region,\n v.account_id\nfrom\n aws_ebs_volume as v,\n jsonb_array_elements(attachments) as att\n left join aws_ec2_instance as i on att ->> 'InstanceId' = i.instance_id \n" - PrimaryTable: aws_ebs_volume ListOfTables: - aws_ebs_volume - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ebs_volume + QueryToExecute: | + SELECT + v.volume_id AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN i.instance_state = 'running' THEN 0 + ELSE ( + SELECT cost + FROM pennywise_cost_estimate + WHERE resource_type = 'aws::ec2::volume' + AND resource_id = v.og_resource_id + LIMIT 1 + ) + END AS cost_optimization, + CASE + WHEN i.instance_state = 'running' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN i.instance_state = 'running' THEN v.volume_id || ' is attached to a running instance' + ELSE v.volume_id || ' is attached to a stopped instance' + END AS reason, + v.region, + v.account_id + FROM + aws_ebs_volume AS v, + jsonb_array_elements(attachments) AS att + LEFT JOIN + aws_ec2_instance AS i + ON + att ->> 'InstanceId' = i.instance_id Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +51,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Missing Tags -IntegrationType: - - aws_cloud_account +Title: EBS Volumes Attached To Stopped EC2 Instances \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ebs/aws_ebs_volumes_too_old_snapshots.yaml b/compliance/controls/baseline/aws/ebs/aws_ebs_volumes_too_old_snapshots.yaml old mode 100755 new mode 100644 index 0fe25cf3a..226e7ab9d --- a/compliance/controls/baseline/aws/ebs/aws_ebs_volumes_too_old_snapshots.yaml +++ b/compliance/controls/baseline/aws/ebs/aws_ebs_volumes_too_old_snapshots.yaml @@ -1,15 +1,44 @@ +Description: Identify and remove old AWS Elastic Block Store (EBS) volume snapshots for cost optimization. ID: aws_ebs_volumes_too_old_snapshots -Title: "EBS Volumes Too Old Snapshots" -Description: "Identify and remove old AWS Elastic Block Store (EBS) volume snapshots for cost optimization." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n snapshot_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN start_time + ({{.awsEbsSnapshotAgeMaxDays}}::INT || ' days')::interval < now() THEN (SELECT cost FROM pennywise_cost_estimate where resource_type = 'aws::ec2::volumesnapshot' and resource_id = es.og_resource_id limit 1)\n ELSE 0\n END AS cost_optimization,\n CASE\n WHEN start_time + ({{.awsEbsSnapshotAgeMaxDays}}::INT || ' days')::interval < now() THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN start_time + ({{.awsEbsSnapshotAgeMaxDays}}::INT || ' days')::interval < now() THEN snapshot_id || ' snapshot is older than 30 days' \n ELSE snapshot_id || ' snapshot is not older than 30 days'\n END AS reason,\n region,\n account_id\nFROM \n aws_ebs_snapshot es\n" - PrimaryTable: aws_ebs_snapshot ListOfTables: - aws_ebs_snapshot Parameters: - key: awsEbsSnapshotAgeMaxDays required: false + PrimaryTable: aws_ebs_snapshot + QueryToExecute: | + SELECT + snapshot_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN start_time + ({{.awsEbsSnapshotAgeMaxDays}}::INT || ' days')::interval < now() + THEN ( + SELECT cost + FROM pennywise_cost_estimate + WHERE resource_type = 'aws::ec2::volumesnapshot' AND resource_id = es.og_resource_id + LIMIT 1 + ) + ELSE 0 + END AS cost_optimization, + CASE + WHEN start_time + ({{.awsEbsSnapshotAgeMaxDays}}::INT || ' days')::interval < now() + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN start_time + ({{.awsEbsSnapshotAgeMaxDays}}::INT || ' days')::interval < now() + THEN snapshot_id || ' snapshot is older than 30 days' + ELSE snapshot_id || ' snapshot is not older than 30 days' + END AS reason, + region, + account_id + FROM + aws_ebs_snapshot es Severity: high Tags: platform_score_cloud_service_name: @@ -20,5 +49,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Optimization -IntegrationType: - - aws_cloud_account +Title: EBS Volumes Too Old Snapshots \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ebs/aws_use_gp3_not_gp2.yaml b/compliance/controls/baseline/aws/ebs/aws_use_gp3_not_gp2.yaml old mode 100755 new mode 100644 index 9350ef080..f27a56612 --- a/compliance/controls/baseline/aws/ebs/aws_use_gp3_not_gp2.yaml +++ b/compliance/controls/baseline/aws/ebs/aws_use_gp3_not_gp2.yaml @@ -1,27 +1,28 @@ +Description: EBS gp2 volumes are legacy, costly, and have lower performance than gp3. ID: aws_use_gp3_not_gp2 -Title: "Use GP3, not GP2" -Description: "EBS gp2 volumes are legacy, costly, and have lower performance than gp3." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ebs_volume + Parameters: [] + PrimaryTable: aws_ebs_volume QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when volume_type = 'gp2' then 'alarm' - when volume_type = 'gp3' then 'ok' - else 'skip' - end as status, - volume_id || ' type is ' || volume_type || '.' as reason, + CASE + WHEN volume_type = 'gp2' THEN 'alarm' + WHEN volume_type = 'gp3' THEN 'ok' + ELSE 'skip' + END AS status, + volume_id || ' type is ' || volume_type || '.' AS reason, region, account_id - from + FROM aws_ebs_volume; - PrimaryTable: aws_ebs_volume - ListOfTables: - - aws_ebs_volume - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -32,5 +33,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - General Efficiency -IntegrationType: - - aws_cloud_account +Title: Use GP3, not GP2 \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ebs/aws_use_io2_not_io1.yaml b/compliance/controls/baseline/aws/ebs/aws_use_io2_not_io1.yaml old mode 100755 new mode 100644 index 62421b152..f73ee7146 --- a/compliance/controls/baseline/aws/ebs/aws_use_io2_not_io1.yaml +++ b/compliance/controls/baseline/aws/ebs/aws_use_io2_not_io1.yaml @@ -1,27 +1,28 @@ +Description: io1 Volumes are older generation less reliable than io2 for same cost. ID: aws_use_io2_not_io1 -Title: "Use io2, not io1" -Description: "io1 Volumes are older generation less reliable than io2 for same cost." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ebs_volume + Parameters: [] + PrimaryTable: aws_ebs_volume QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when volume_type = 'io1' then 'alarm' - when volume_type = 'io2' then 'ok' - else 'skip' - end as status, - volume_id || ' type is ' || volume_type || '.' as reason, + CASE + WHEN volume_type = 'io1' THEN 'alarm' + WHEN volume_type = 'io2' THEN 'ok' + ELSE 'skip' + END AS status, + volume_id || ' type is ' || volume_type || '.' AS reason, region, account_id - from + FROM aws_ebs_volume; - PrimaryTable: aws_ebs_volume - ListOfTables: - - aws_ebs_volume - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -32,5 +33,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Use io2, not io1 \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_ami_encryption.yaml b/compliance/controls/baseline/aws/ec2/aws_ami_encryption.yaml old mode 100755 new mode 100644 index 6b2ec272a..63855814c --- a/compliance/controls/baseline/aws/ec2/aws_ami_encryption.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_ami_encryption.yaml @@ -1,13 +1,40 @@ +Description: Ensure that your existing AMIs are encrypted to meet security and compliance requirements. ID: aws_ami_encryption -Title: "AWS AMI Encryption" -Description: "Ensure that your existing AMIs are encrypted to meet security and compliance requirements." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(block_device_mappings) AS b WHERE (b -> 'Ebs' ->> 'Encrypted')::bool = False\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(block_device_mappings) AS b WHERE (b -> 'Ebs' ->> 'Encrypted')::bool = False\n ) THEN name || ' has unencrypted data' \n ELSE name || ' data is encrypted'\n END AS reason,\n region,\n account_id\nFROM \n aws_ec2_ami\n" - PrimaryTable: aws_ec2_ami ListOfTables: - aws_ec2_ami Parameters: [] + PrimaryTable: aws_ec2_ami + QueryToExecute: | + SELECT + name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(block_device_mappings) AS b + WHERE (b -> 'Ebs' ->> 'Encrypted')::bool = FALSE + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(block_device_mappings) AS b + WHERE (b -> 'Ebs' ->> 'Encrypted')::bool = FALSE + ) + THEN name || ' has unencrypted data' + ELSE name || ' data is encrypted' + END AS reason, + region, + account_id + FROM + aws_ec2_ami Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +45,4 @@ Tags: - AWS EC2 score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: AWS AMI Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_default_security_group_unrestricted.yaml b/compliance/controls/baseline/aws/ec2/aws_default_security_group_unrestricted.yaml old mode 100755 new mode 100644 index fe24c8c4a..c4784c637 --- a/compliance/controls/baseline/aws/ec2/aws_default_security_group_unrestricted.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_default_security_group_unrestricted.yaml @@ -1,13 +1,48 @@ +Description: Ensure the default security group of every VPC restricts all traffic. ID: aws_default_security_group_unrestricted -Title: "Default Security Group Unrestricted" -Description: "Ensure the default security group of every VPC restricts all traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(ip_permissions) AS p\n WHERE EXISTS (SELECT 1 FROM jsonb_array_elements((p -> 'IpRanges')::jsonb) as r\n WHERE r ->> 'CidrIp' = '0.0.0.0/0')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(ip_permissions) AS p\n WHERE EXISTS (SELECT 1 FROM jsonb_array_elements((p -> 'IpRanges')::jsonb) as r\n WHERE r ->> 'CidrIp' = '0.0.0.0/0')\n ) THEN group_id || ' is not secure and compliant' \n ELSE group_id || ' is secure and compliant'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n group_name = 'default'\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE EXISTS ( + SELECT 1 + FROM jsonb_array_elements((p -> 'IpRanges')::jsonb) AS r + WHERE r ->> 'CidrIp' = '0.0.0.0/0' + ) + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE EXISTS ( + SELECT 1 + FROM jsonb_array_elements((p -> 'IpRanges')::jsonb) AS r + WHERE r ->> 'CidrIp' = '0.0.0.0/0' + ) + ) THEN group_id || ' is not secure and compliant' + ELSE group_id || ' is secure and compliant' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + group_name = 'default' Severity: low Tags: platform_score_cloud_service_name: @@ -18,5 +53,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Default Security Group Unrestricted \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_default_security_groups_in_use.yaml b/compliance/controls/baseline/aws/ec2/aws_default_security_groups_in_use.yaml old mode 100755 new mode 100644 index 5c9058b4e..a1dd3b008 --- a/compliance/controls/baseline/aws/ec2/aws_default_security_groups_in_use.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_default_security_groups_in_use.yaml @@ -1,13 +1,38 @@ +Description: Ensure default security groups aren't in use. Instead create unique security groups to better adhere to the principle of least privilege. ID: aws_default_security_groups_in_use -Title: "Default Security Groups In Use" -Description: "Ensure default security groups aren't in use. Instead create unique security groups to better adhere to the principle of least privilege." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n instance_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(security_groups) as sg\n WHERE sg ->> 'GroupName' = 'default'\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(security_groups) as sg\n WHERE sg ->> 'GroupName' = 'default'\n ) THEN instance_id || ' is using default security group' \n ELSE instance_id || ' is not using default security group'\n END AS reason,\n region,\n account_id\nFROM \n aws_ec2_instance\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + instance_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(security_groups) AS sg + WHERE sg ->> 'GroupName' = 'default' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(security_groups) AS sg + WHERE sg ->> 'GroupName' = 'default' + ) THEN instance_id || ' is using default security group' + ELSE instance_id || ' is not using default security group' + END AS reason, + region, + account_id + FROM + aws_ec2_instance Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +43,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Default Security Groups In Use \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_disable_public_ip_address_assignment_for_ec2_instances.yaml b/compliance/controls/baseline/aws/ec2/aws_disable_public_ip_address_assignment_for_ec2_instances.yaml old mode 100755 new mode 100644 index 85be43141..70e351c5e --- a/compliance/controls/baseline/aws/ec2/aws_disable_public_ip_address_assignment_for_ec2_instances.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_disable_public_ip_address_assignment_for_ec2_instances.yaml @@ -1,29 +1,30 @@ +Description: Ensure that Amazon EC2 instances are not using public IP addresses. ID: aws_disable_public_ip_address_assignment_for_ec2_instances -Title: "Disable Public IP Address Assignment for EC2 Instances" -Description: "Ensure that Amazon EC2 instances are not using public IP addresses." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when public_ip_address is null then 'ok' - else 'alarm' - end status, - case - when public_ip_address is null then instance_id || ' not publicly accessible.' - else instance_id || ' publicly accessible.' - end reason, + CASE + WHEN public_ip_address IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN public_ip_address IS NULL THEN instance_id || ' not publicly accessible.' + ELSE instance_id || ' publicly accessible.' + END AS reason, region, account_id - from + FROM aws_ec2_instance; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS EC2 score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Disable Public IP Address Assignment for EC2 Instances \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_ec2_ami_too_old.yaml b/compliance/controls/baseline/aws/ec2/aws_ec2_ami_too_old.yaml old mode 100755 new mode 100644 index aa2545a8d..a85a8e43e --- a/compliance/controls/baseline/aws/ec2/aws_ec2_ami_too_old.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_ec2_ami_too_old.yaml @@ -1,10 +1,9 @@ +Description: Ensure EC2 Amazon Machine Images (AMIs) aren't too old ID: aws_ec2_ami_too_old -Title: "EC2 AMI Too Old" -Description: "Ensure EC2 Amazon Machine Images (AMIs) aren't too old" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n image_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN is_aws_backup_managed THEN 'skip'\n WHEN root_device_type <> 'ebs' THEN 'skip'\n WHEN now() - (creation_date)::timestamp > '{{.awsEbsAmiAgeMaxDays}} days'::interval THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN is_aws_backup_managed THEN name || ' is managed by aws'\n WHEN root_device_type <> 'ebs' THEN name || ' is not stored in ebs'\n WHEN now() - (creation_date)::timestamp > '{{.awsEbsAmiAgeMaxDays}} days'::interval THEN name || ' needs to be restarted' \n ELSE name || ' launch time was not much time ago'\n END AS reason,\n case\n when is_aws_backup_managed then 0\n when root_device_type <> 'ebs' then 0\n when now() - (creation_date)::timestamp > '{{.awsEbsAmiAgeMaxDays}} days'::interval then (SELECT SUM((select cost from pennywise_cost_estimate AS es WHERE es.resource_type = 'aws::ec2::volumesnapshot' \n AND es.resource_id = s.arn limit 1))\n FROM jsonb_array_elements(block_device_mappings) AS bdm\n LEFT JOIN aws_ebs_snapshot AS s ON s.snapshot_id = bdm -> 'Ebs' ->> 'SnapshotId')\n else 0\n end as cost_optimization,\n region,\n account_id\nFROM \n aws_ec2_ami\n" - PrimaryTable: aws_ec2_ami ListOfTables: - aws_backup_managed - aws_ebs_snapshot @@ -12,6 +11,44 @@ Query: Parameters: - Key: awsEbsAmiAgeMaxDays Required: true + PrimaryTable: aws_ec2_ami + QueryToExecute: | + SELECT + image_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN is_aws_backup_managed THEN 'skip' + WHEN root_device_type <> 'ebs' THEN 'skip' + WHEN NOW() - (creation_date)::timestamp > '{{.awsEbsAmiAgeMaxDays}} days'::interval THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN is_aws_backup_managed THEN name || ' is managed by aws' + WHEN root_device_type <> 'ebs' THEN name || ' is not stored in ebs' + WHEN NOW() - (creation_date)::timestamp > '{{.awsEbsAmiAgeMaxDays}} days'::interval THEN name || ' needs to be restarted' + ELSE name || ' launch time was not much time ago' + END AS reason, + CASE + WHEN is_aws_backup_managed THEN 0 + WHEN root_device_type <> 'ebs' THEN 0 + WHEN NOW() - (creation_date)::timestamp > '{{.awsEbsAmiAgeMaxDays}} days'::interval THEN + (SELECT SUM( + (SELECT cost + FROM pennywise_cost_estimate AS es + WHERE es.resource_type = 'aws::ec2::volumesnapshot' + AND es.resource_id = s.arn + LIMIT 1) + ) + FROM jsonb_array_elements(block_device_mappings) AS bdm + LEFT JOIN aws_ebs_snapshot AS s + ON s.snapshot_id = bdm -> 'Ebs' ->> 'SnapshotId') + ELSE 0 + END AS cost_optimization, + region, + account_id + FROM + aws_ec2_ami Severity: high Tags: platform_score_cloud_service_name: @@ -22,5 +59,4 @@ Tags: - AWS EC2 score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: EC2 AMI Too Old \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_ec2_desired_instance_type.yaml b/compliance/controls/baseline/aws/ec2/aws_ec2_desired_instance_type.yaml old mode 100755 new mode 100644 index 9cf9752fe..98b0f01e4 --- a/compliance/controls/baseline/aws/ec2/aws_ec2_desired_instance_type.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_ec2_desired_instance_type.yaml @@ -1,15 +1,34 @@ +Description: Ensure all EC2 instances are of a given instance type Optimal and Aligned with our Organization ID: aws_ec2_desired_instance_type -Title: "EC2 Instances types are Approved" -Description: "Ensure all EC2 instances are of a given instance type Optimal and Aligned with our Organization" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n instance_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN '{{.awsAllowedInstanceTypes}}' = '' THEN 'ok'\n WHEN '{{.awsAllowedInstanceTypes}}' LIKE '%' || instance_type || '%' THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN '{{.awsAllowedInstanceTypes}}' = '' THEN 'allowed instance types not defined'\n WHEN '{{.awsAllowedInstanceTypes}}' LIKE '%' || instance_type || '%' THEN instance_id || ' instance type is allowed by your organization' \n ELSE instance_id || ' instance type is not allowed by your organization'\n END AS reason,\n region,\n account_id\nFROM \n aws_ec2_instance\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: - Key: awsAllowedInstanceTypes Required: false + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + instance_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN '{{.awsAllowedInstanceTypes}}' = '' THEN 'ok' + WHEN '{{.awsAllowedInstanceTypes}}' LIKE '%' || instance_type || '%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN '{{.awsAllowedInstanceTypes}}' = '' THEN 'allowed instance types not defined' + WHEN '{{.awsAllowedInstanceTypes}}' LIKE '%' || instance_type || '%' THEN instance_id || ' instance type is allowed by your organization' + ELSE instance_id || ' instance type is not allowed by your organization' + END AS reason, + region, + account_id + FROM + aws_ec2_instance Severity: high Tags: platform_score_cloud_service_name: @@ -20,5 +39,4 @@ Tags: - AWS EC2 score_tags: - Over Utilization -IntegrationType: - - aws_cloud_account +Title: EC2 Instances types are Approved \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_ec2_instance_in_vpc.yaml b/compliance/controls/baseline/aws/ec2/aws_ec2_instance_in_vpc.yaml old mode 100755 new mode 100644 index 6bbc3bfbc..5ab68758d --- a/compliance/controls/baseline/aws/ec2/aws_ec2_instance_in_vpc.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_ec2_instance_in_vpc.yaml @@ -1,30 +1,32 @@ +Description: Ensure EC2 instances are launched using the EC2-VPC platform instead of EC2-Classic outdated platform. ID: aws_ec2_instance_in_vpc -Title: "EC2 Instance In VPC" -Description: "Ensure EC2 instances are launched using the EC2-VPC platform instead of EC2-Classic outdated platform." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when vpc_id is null then 'alarm' - else 'ok' - end as status, - case - when vpc_id is null then title || ' not in VPC.' - else title || ' in VPC.' - end as reason, + CASE + WHEN vpc_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vpc_id IS NULL THEN title || ' not in VPC.' + ELSE title || ' in VPC.' + END AS reason, region, account_id - from + FROM aws_ec2_instance - where instance_state = 'running'; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - Parameters: [] + WHERE + instance_state = 'running'; Severity: medium Tags: platform_score_cloud_service_name: @@ -35,5 +37,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: EC2 Instance In VPC \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_ec2_instance_naming_conventions.yaml b/compliance/controls/baseline/aws/ec2/aws_ec2_instance_naming_conventions.yaml old mode 100755 new mode 100644 index 45ba219f9..37f8795d9 --- a/compliance/controls/baseline/aws/ec2/aws_ec2_instance_naming_conventions.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_ec2_instance_naming_conventions.yaml @@ -1,15 +1,34 @@ +Description: Follow proper naming conventions for EC2 instances. ID: aws_ec2_instance_naming_conventions -Title: "EC2 Instance Naming Conventions" -Description: "Follow proper naming conventions for EC2 instances." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n instance_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN '{{.awsEc2NamingPattern}}' = '' then 'ok'\n WHEN tags ->> 'Name' LIKE '{{.awsEc2NamingPattern}}' THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN '{{.awsEc2NamingPattern}}' = '' THEN 'ec2 naming pattern not defined' \n WHEN tags ->> 'Name' LIKE '{{.awsEc2NamingPattern}}' THEN instance_id || ' name is followed by your organization naming pattern' \n ELSE instance_id || ' name is not followed by your organization naming pattern'\n END AS reason,\n region,\n account_id\nFROM \n aws_ec2_instance\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: - Key: awsEc2NamingPattern Required: false + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + instance_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN '{{.awsEc2NamingPattern}}' = '' THEN 'ok' + WHEN tags ->> 'Name' LIKE '{{.awsEc2NamingPattern}}' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN '{{.awsEc2NamingPattern}}' = '' THEN 'ec2 naming pattern not defined' + WHEN tags ->> 'Name' LIKE '{{.awsEc2NamingPattern}}' THEN instance_id || ' name is followed by your organization naming pattern' + ELSE instance_id || ' name is not followed by your organization naming pattern' + END AS reason, + region, + account_id + FROM + aws_ec2_instance Severity: low Tags: platform_score_cloud_service_name: @@ -20,5 +39,4 @@ Tags: - AWS EC2 score_tags: - Missing Tags -IntegrationType: - - aws_cloud_account +Title: EC2 Instance Naming Conventions \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_ec2_instance_not_in_public_subnet.yaml b/compliance/controls/baseline/aws/ec2/aws_ec2_instance_not_in_public_subnet.yaml old mode 100755 new mode 100644 index 7bc8b554e..e4e1cf286 --- a/compliance/controls/baseline/aws/ec2/aws_ec2_instance_not_in_public_subnet.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_ec2_instance_not_in_public_subnet.yaml @@ -1,29 +1,30 @@ +Description: Ensure that no backend EC2 instances are provisioned in public subnets. ID: aws_ec2_instance_not_in_public_subnet -Title: "EC2 Instance Not In Public Subnet" -Description: "Ensure that no backend EC2 instances are provisioned in public subnets." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when public_ip_address is null then 'ok' - else 'alarm' - end status, - case - when public_ip_address is null then instance_id || ' not publicly accessible.' - else instance_id || ' publicly accessible.' - end reason, + CASE + WHEN public_ip_address IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN public_ip_address IS NULL THEN instance_id || ' not publicly accessible.' + ELSE instance_id || ' publicly accessible.' + END AS reason, region, account_id - from + FROM aws_ec2_instance; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: EC2 Instance Not In Public Subnet \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_ec2_instance_termination_protection.yaml b/compliance/controls/baseline/aws/ec2/aws_ec2_instance_termination_protection.yaml old mode 100755 new mode 100644 index a2dfc09e5..b9eaf2164 --- a/compliance/controls/baseline/aws/ec2/aws_ec2_instance_termination_protection.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_ec2_instance_termination_protection.yaml @@ -1,34 +1,34 @@ +Description: Ensure termination protection safety feature is enabled for EC2 instances that aren't part of ASGs ID: aws_ec2_instance_termination_protection -Title: "EC2 Instance Termination Protection" -Description: "Ensure termination protection safety feature is enabled for ec2 instances that aren't part of ASGs" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance QueryToExecute: | - select - instance_id as resource, + SELECT + instance_id AS resource, og_resource_id, og_account_id, - case - when disable_api_termination = 'false' then 'alarm' - else 'ok' - end status, - case - when disable_api_termination = 'false' then instance_id || ' Termination Protection safety feature is not enabled' - else instance_id || ' Termination Protection safety feature is enabled.' - end as reason, + CASE + WHEN disable_api_termination = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN disable_api_termination = 'false' THEN instance_id || ' Termination Protection safety feature is not enabled' + ELSE instance_id || ' Termination Protection safety feature is enabled.' + END AS reason, region, account_id - from + FROM aws_ec2_instance - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - AWS EC2 score_service_name: - AWS EC2 -IntegrationType: - - aws_cloud_account +Title: EC2 Instance Termination Protection \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_ec2_instance_too_old.yaml b/compliance/controls/baseline/aws/ec2/aws_ec2_instance_too_old.yaml old mode 100755 new mode 100644 index e9c24bfbd..fe9109045 --- a/compliance/controls/baseline/aws/ec2/aws_ec2_instance_too_old.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_ec2_instance_too_old.yaml @@ -1,13 +1,30 @@ +Description: Ensure EC2 instances aren't too old. ID: aws_ec2_instance_too_old -Title: "EC2 Instance Too Old" -Description: "Ensure EC2 instances aren't too old." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n instance_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN now() - (og_description -> 'Instance' ->> 'LaunchTime')::timestamp > '180 days'::interval THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN now() - (og_description -> 'Instance' ->> 'LaunchTime')::timestamp > '180 days'::interval THEN instance_id || ' needs to be restarted' \n ELSE instance_id || ' launch time was not much time ago'\n END AS reason,\n region,\n account_id\nFROM \n aws_ec2_instance\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + SELECT + instance_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN now() - (og_description -> 'Instance' ->> 'LaunchTime')::timestamp > '180 days'::interval THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN now() - (og_description -> 'Instance' ->> 'LaunchTime')::timestamp > '180 days'::interval THEN instance_id || ' needs to be restarted' + ELSE instance_id || ' launch time was not much time ago' + END AS reason, + region, + account_id + FROM + aws_ec2_instance Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS EC2 score_tags: - Under Utilization -IntegrationType: - - aws_cloud_account +Title: EC2 Instance Too Old \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_ec2_instances_with_multiple_elastic_network_interfaces.yaml b/compliance/controls/baseline/aws/ec2/aws_ec2_instances_with_multiple_elastic_network_interfaces.yaml old mode 100755 new mode 100644 index bf717e74f..b1fa223d9 --- a/compliance/controls/baseline/aws/ec2/aws_ec2_instances_with_multiple_elastic_network_interfaces.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_ec2_instances_with_multiple_elastic_network_interfaces.yaml @@ -1,18 +1,51 @@ +Description: Ensure that Amazon EC2 instances are not using multiple ENIs. ID: aws_ec2_instances_with_multiple_elastic_network_interfaces -Title: "EC2 Instances with Multiple Elastic Network Interfaces" -Description: "Ensure that Amazon EC2 instances are not using multiple ENIs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with instance_nis as (\n select\n i.instance_id, count(ni)\n from\n aws_ec2_instance as i,\n jsonb_array_elements(network_interfaces) as ni\n where ni -> 'Attachment' ->> 'Status' = 'attached'\n group by i.instance_id\n )\n \n select\n i.instance_id as resource,\n og_resource_id,\n og_account_id,\n case\n when nis.count > 1 then 'alarm'\n else 'ok'\n end status,\n case\n when nis.count > 1 then i.instance_id || ' Has more than one network interfaces.'\n else i.instance_id || ' Has more than one network interfaces.'\n end as reason,\n region,\n account_id\n from\n aws_ec2_instance as i left join\n instance_nis as nis on i.instance_id = nis.instance_id\n" - PrimaryTable: aws_ec2_instance ListOfTables: - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_instance + QueryToExecute: | + WITH instance_nis AS ( + SELECT + i.instance_id, + COUNT(ni) + FROM + aws_ec2_instance AS i, + JSONB_ARRAY_ELEMENTS(network_interfaces) AS ni + WHERE + ni -> 'Attachment' ->> 'Status' = 'attached' + GROUP BY + i.instance_id + ) + + SELECT + i.instance_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN nis.count > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN nis.count > 1 THEN i.instance_id || ' Has more than one network interfaces.' + ELSE i.instance_id || ' Has more than one network interfaces.' + END AS reason, + region, + account_id + FROM + aws_ec2_instance AS i + LEFT JOIN + instance_nis AS nis + ON + i.instance_id = nis.instance_id Severity: high Tags: platform_score_cloud_service_name: - AWS EC2 score_service_name: - AWS EC2 -IntegrationType: - - aws_cloud_account +Title: EC2 Instances with Multiple Elastic Network Interfaces \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_publicly_shared_ami.yaml b/compliance/controls/baseline/aws/ec2/aws_publicly_shared_ami.yaml old mode 100755 new mode 100644 index 3dc1a00d5..f06b9d535 --- a/compliance/controls/baseline/aws/ec2/aws_publicly_shared_ami.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_publicly_shared_ami.yaml @@ -1,29 +1,30 @@ +Description: Ensure AMIs aren't publicly shared to avoid exposing sensitive data. ID: aws_publicly_shared_ami -Title: "Publicly Shared AMI" -Description: "Ensure AMIs aren't publicly shared to avoid exposing sensitive data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_ami + Parameters: [] + PrimaryTable: aws_ec2_ami QueryToExecute: | - select - title as resource, + SELECT + title AS resource, og_resource_id, og_account_id, - case - when public then 'alarm' - else 'ok' - end as status, - case - when public then title || ' publicly accessible.' - else title || ' not publicly accessible.' - end as reason, + CASE + WHEN public THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason, region, account_id - from + FROM aws_ec2_ami; - PrimaryTable: aws_ec2_ami - ListOfTables: - - aws_ec2_ami - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Publicly Shared AMI \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_require_imdsv2_for_ec2_instances.yaml b/compliance/controls/baseline/aws/ec2/aws_require_imdsv2_for_ec2_instances.yaml old mode 100755 new mode 100644 index 001932285..4d9789ef3 --- a/compliance/controls/baseline/aws/ec2/aws_require_imdsv2_for_ec2_instances.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_require_imdsv2_for_ec2_instances.yaml @@ -1,29 +1,30 @@ +Description: Ensure that all the Amazon EC2 instances require the use of Instance Metadata Service Version 2 (IMDSv2). ID: aws_require_imdsv2_for_ec2_instances -Title: "Require IMDSv2 for EC2 Instances" -Description: "Ensure that all the Amazon EC2 instances require the use of Instance Metadata Service Version 2 (IMDSv2)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when metadata_options ->> 'HttpTokens' = 'optional' then 'alarm' - else 'ok' - end as status, - case - when metadata_options ->> 'HttpTokens' = 'optional' then title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' - else title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' - end as reason, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN metadata_options ->> 'HttpTokens' = 'optional' THEN title || ' not configured to use Instance Metadata Service Version 2 (IMDSv2).' + ELSE title || ' configured to use Instance Metadata Service Version 2 (IMDSv2).' + END AS reason, region, account_id - from + FROM aws_ec2_instance; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Require IMDSv2 for EC2 Instances \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_security_group_name_prefixed_with_launch_wizard.yaml b/compliance/controls/baseline/aws/ec2/aws_security_group_name_prefixed_with_launch_wizard.yaml old mode 100755 new mode 100644 index 755a44132..922305d31 --- a/compliance/controls/baseline/aws/ec2/aws_security_group_name_prefixed_with_launch_wizard.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_security_group_name_prefixed_with_launch_wizard.yaml @@ -1,39 +1,41 @@ +Description: Ensure no security group name is prefixed with 'launch-wizard'. ID: aws_security_group_name_prefixed_with_launch_wizard -Title: "Security Group Name Prefixed With 'launch-wizard'" -Description: "Ensure no security group name is prefixed with 'launch-wizard'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_instance + Parameters: [] + PrimaryTable: aws_ec2_instance QueryToExecute: | - with launch_wizard_sg_attached_instance as ( - select - distinct arn as arn - from + WITH launch_wizard_sg_attached_instance AS ( + SELECT + DISTINCT arn AS arn + FROM aws_ec2_instance, - jsonb_array_elements(security_groups) as sg - where - sg ->> 'GroupName' like 'launch-wizard%' + jsonb_array_elements(security_groups) AS sg + WHERE + sg ->> 'GroupName' LIKE 'launch-wizard%' ) - select - i.arn as resource, + SELECT + i.arn AS resource, og_resource_id, og_account_id, - case - when sg.arn is null then 'ok' - else 'alarm' - end as status, - case - when sg.arn is null then i.title || ' not associated with launch-wizard security group.' - else i.title || ' associated with launch-wizard security group.' - end as reason, + CASE + WHEN sg.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sg.arn IS NULL THEN i.title || ' not associated with launch-wizard security group.' + ELSE i.title || ' associated with launch-wizard security group.' + END AS reason, i.region, i.account_id - from - aws_ec2_instance as i - left join launch_wizard_sg_attached_instance as sg on i.arn = sg.arn; - PrimaryTable: aws_ec2_instance - ListOfTables: - - aws_ec2_instance - Parameters: [] + FROM + aws_ec2_instance AS i + LEFT JOIN launch_wizard_sg_attached_instance AS sg + ON i.arn = sg.arn; Severity: low Tags: platform_score_cloud_service_name: @@ -44,5 +46,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Security Group Name Prefixed With 'launch-wizard' \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_security_group_port_range.yaml b/compliance/controls/baseline/aws/ec2/aws_security_group_port_range.yaml old mode 100755 new mode 100644 index 7b0030fe9..37f0c54e2 --- a/compliance/controls/baseline/aws/ec2/aws_security_group_port_range.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_security_group_port_range.yaml @@ -1,42 +1,43 @@ +Description: Ensure no security group opens range of ports. ID: aws_security_group_port_range -Title: "Security Group Port Range" -Description: "Ensure no security group opens range of ports." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_vpc_security_group + - aws_vpc_security_group_rule + Parameters: [] + PrimaryTable: aws_vpc_security_group QueryToExecute: | - with ingress_sg as ( - select + WITH ingress_sg AS ( + SELECT group_id - from + FROM aws_vpc_security_group_rule - where + WHERE from_port = from_port - and not is_egress - group by + AND NOT is_egress + GROUP BY group_id ) - select - sg.group_id as resource, + SELECT + sg.group_id AS resource, og_resource_id, og_account_id, - case - when isg.group_id is null then 'ok' - else 'alarm' - end as status, - case - when isg.group_id is null then sg.group_id || ' does not allow unrestricted FTP access' - else sg.group_id || ' allows unrestricted FTP access' - end as reason, + CASE + WHEN isg.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN isg.group_id IS NULL THEN sg.group_id || ' does not allow unrestricted FTP access' + ELSE sg.group_id || ' allows unrestricted FTP access' + END AS reason, region, account_id - from - aws_vpc_security_group as sg - left join ingress_sg as isg on sg.group_id = isg.group_id - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group - - aws_vpc_security_group_rule - Parameters: [] + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_sg AS isg ON sg.group_id = isg.group_id Severity: very high Tags: platform_score_cloud_service_name: @@ -47,5 +48,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Security Group Port Range \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unassociated_elastic_ip_addresses.yaml b/compliance/controls/baseline/aws/ec2/aws_unassociated_elastic_ip_addresses.yaml old mode 100755 new mode 100644 index cfe1118f2..17c4d21ff --- a/compliance/controls/baseline/aws/ec2/aws_unassociated_elastic_ip_addresses.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unassociated_elastic_ip_addresses.yaml @@ -1,33 +1,34 @@ +Description: Identify unassociated Elastic IP addresses, and delete them to help lower the cost of your monthly AWS bill. ID: aws_unassociated_elastic_ip_addresses -Title: "Unassociated Elastic IP Addresses" -Description: "Identify unassociated Elastic IP addresses, and delete them to help lower the cost of your monthly AWS bill." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_vpc_eip + Parameters: [] + PrimaryTable: aws_vpc_eip QueryToExecute: | - select - 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':eip/' || allocation_id as resource, + SELECT + 'arn:' || partition || ':ec2:' || region || ':' || account_id || ':eip/' || allocation_id AS resource, og_account_id, og_resource_id, - case - when association_id is null then 'alarm' - else 'ok' - end as status, - case - when association_id is null then title || ' is not associated with any resource.' - else title || ' is associated with a resource.' - end as reason, - case - when association_id is null then '3.6'::float - else '0'::float - end as cost_optimization, + CASE + WHEN association_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN association_id IS NULL THEN title || ' is not associated with any resource.' + ELSE title || ' is associated with a resource.' + END AS reason, + CASE + WHEN association_id IS NULL THEN '3.6'::float + ELSE '0'::float + END AS cost_optimization, region, account_id - from + FROM aws_vpc_eip; - PrimaryTable: aws_vpc_eip - ListOfTables: - - aws_vpc_eip - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -38,5 +39,4 @@ Tags: - AWS EC2 score_tags: - Orphaned Resources -IntegrationType: - - aws_cloud_account +Title: Unassociated Elastic IP Addresses \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_cifs_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_cifs_access.yaml old mode 100755 new mode 100644 index 8caee82eb..4db85009e --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_cifs_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_cifs_access.yaml @@ -1,15 +1,53 @@ +Description: Ensure no security group allows unrestricted inbound access to UDP port 445 (CIFS). ID: aws_unrestricted_cifs_access -Title: "Unrestricted CIFS Access" -Description: "Ensure no security group allows unrestricted inbound access to UDP port 445 (CIFS)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsCifsTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '445') and ((p ->> 'ToPort') = '445')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsCifsTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '445') and ((p ->> 'ToPort') = '445')\n ) THEN group_name || ' has Unrestricted CIFS Access' \n ELSE group_name || ' CIFS Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n exists (select 1 from jsonb_array_elements(ip_permissions) as p where ((p ->> 'FromPort') = '445') and ((p ->> 'ToPort') = '445'))\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - Key: awsCifsTrustedIpRange Required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ('{{.awsCifsTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%') + AND ((p ->> 'FromPort') = '445') + AND ((p ->> 'ToPort') = '445') + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ('{{.awsCifsTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%') + AND ((p ->> 'FromPort') = '445') + AND ((p ->> 'ToPort') = '445') + ) THEN group_name || ' has Unrestricted CIFS Access' + ELSE group_name || ' CIFS Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE ((p ->> 'FromPort') = '445') + AND ((p ->> 'ToPort') = '445') + ) Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +58,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted CIFS Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_icmp_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_icmp_access.yaml old mode 100755 new mode 100644 index 7e5c8a4be..01837c5c9 --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_icmp_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_icmp_access.yaml @@ -1,15 +1,46 @@ +Description: Ensure no security group allows unrestricted inbound access to ICMP. ID: aws_unrestricted_icmp_access -Title: "Unrestricted ICMP Access" -Description: "Ensure no security group allows unrestricted inbound access to ICMP." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsIcmpTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'IpProtocol') = 'icmp')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsIcmpTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'IpProtocol') = 'icmp')\n ) THEN group_name || ' has Unrestricted ICMP Access' \n ELSE group_name || ' ICMP Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n exists (select 1 from jsonb_array_elements(ip_permissions) as p where (p ->> 'IpProtocol') = 'icmp')\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - Key: awsIcmpTrustedIpRange Required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ('{{.awsIcmpTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%') + AND ((p ->> 'IpProtocol') = 'icmp') + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ('{{.awsIcmpTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%') + AND ((p ->> 'IpProtocol') = 'icmp') + ) THEN group_name || ' has Unrestricted ICMP Access' + ELSE group_name || ' ICMP Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + EXISTS (SELECT 1 FROM jsonb_array_elements(ip_permissions) AS p WHERE (p ->> 'IpProtocol') = 'icmp') Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +51,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted ICMP Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_mongodb_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_mongodb_access.yaml old mode 100755 new mode 100644 index ef49437a7..60e62275a --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_mongodb_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_mongodb_access.yaml @@ -1,15 +1,53 @@ +Description: Ensure no security group allows unrestricted ingress access to MongoDB port 27017 ID: aws_unrestricted_mongodb_access -Title: "Unrestricted MongoDB Access" -Description: "Ensure no security group allows unrestricted ingress access to MongoDB port 27017" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsMongodbTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '27017') and ((p ->> 'ToPort') = '27017')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsMongodbTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '27017') and ((p ->> 'ToPort') = '27017')\n ) THEN group_name || ' has Unrestricted MongoDb Access' \n ELSE group_name || ' MongoDb Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n exists (select 1 from jsonb_array_elements(ip_permissions) as p where ((p ->> 'FromPort') = '27017') and ((p ->> 'ToPort') = '27017'))\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - Key: awsMongodbTrustedIpRange Required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE '{{.awsMongodbTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%' + AND (p ->> 'FromPort') = '27017' + AND (p ->> 'ToPort') = '27017' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE '{{.awsMongodbTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%' + AND (p ->> 'FromPort') = '27017' + AND (p ->> 'ToPort') = '27017' + ) THEN group_name || ' has Unrestricted MongoDb Access' + ELSE group_name || ' MongoDb Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE (p ->> 'FromPort') = '27017' + AND (p ->> 'ToPort') = '27017' + ) Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +58,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted MongoDB Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_mssql_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_mssql_access.yaml old mode 100755 new mode 100644 index 3dff80524..82c13d7f0 --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_mssql_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_mssql_access.yaml @@ -1,15 +1,53 @@ +Description: Ensure no security group allows unrestricted ingress access to port 1433. ID: aws_unrestricted_mssql_access -Title: "Unrestricted MsSQL Access" -Description: "Ensure no security group allows unrestricted ingress access to port 1433." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsMssqlTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '1433') and ((p ->> 'ToPort') = '1433')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsMssqlTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '1433') and ((p ->> 'ToPort') = '1433')\n ) THEN group_name || ' has Unrestricted MsSQL Access' \n ELSE group_name || ' MsSQL Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n exists (select 1 from jsonb_array_elements(ip_permissions) as p where ((p ->> 'FromPort') = '1433') and ((p ->> 'ToPort') = '1433'))\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - Key: awsMssqlTrustedIpRange Required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE '{{.awsMssqlTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%' + AND (p ->> 'FromPort') = '1433' + AND (p ->> 'ToPort') = '1433' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE '{{.awsMssqlTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%' + AND (p ->> 'FromPort') = '1433' + AND (p ->> 'ToPort') = '1433' + ) THEN group_name || ' has Unrestricted MsSQL Access' + ELSE group_name || ' MsSQL Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE (p ->> 'FromPort') = '1433' + AND (p ->> 'ToPort') = '1433' + ) Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +58,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted MsSQL Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_mysql_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_mysql_access.yaml old mode 100755 new mode 100644 index 924bb377f..f906e92e5 --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_mysql_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_mysql_access.yaml @@ -1,15 +1,55 @@ +Description: Ensure no security group allows unrestricted ingress access to port 3306. ID: aws_unrestricted_mysql_access -Title: "Unrestricted MySQL Access" -Description: "Ensure no security group allows unrestricted ingress access to port 3306." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsMysqlTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '3306') and ((p ->> 'ToPort') = '3306')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsMysqlTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '3306') and ((p ->> 'ToPort') = '3306')\n ) THEN group_name || ' has Unrestricted MySQL Access' \n ELSE group_name || ' MySQL Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n exists (select 1 from jsonb_array_elements(ip_permissions) as p where ((p ->> 'FromPort') = '3306') and ((p ->> 'ToPort') = '3306'))\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - Key: awsMysqlTrustedIpRange Required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ('{{.awsMysqlTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%') + AND ((p ->> 'FromPort') = '3306') + AND ((p ->> 'ToPort') = '3306') + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ('{{.awsMysqlTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%') + AND ((p ->> 'FromPort') = '3306') + AND ((p ->> 'ToPort') = '3306') + ) + THEN group_name || ' has Unrestricted MySQL Access' + ELSE group_name || ' MySQL Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE ((p ->> 'FromPort') = '3306') + AND ((p ->> 'ToPort') = '3306') + ) Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +60,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted MySQL Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_netbios_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_netbios_access.yaml old mode 100755 new mode 100644 index 27fc55525..e94fce79d --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_netbios_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_netbios_access.yaml @@ -1,15 +1,53 @@ +Description: Ensure no security group allows unrestricted inbound access to port UDP/137, UDP/138, and TPC/139 (NetBIOS). ID: aws_unrestricted_netbios_access -Title: "Unrestricted NetBIOS Access" -Description: "Ensure no security group allows unrestricted inbound access to port UDP/137, UDP/138, and TPC/139 (NetBIOS)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsNetBiosTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') in ('137', '138', '139')) and ((p ->> 'ToPort') in ('137', '138', '139'))\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsNetBiosTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') in ('137', '138', '139')) and ((p ->> 'ToPort') in ('137', '138', '139'))\n ) THEN group_name || ' has Unrestricted NetBIOS Access' \n ELSE group_name || ' NetBIOS Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n exists (select 1 from jsonb_array_elements(ip_permissions) as p where ((p ->> 'FromPort') in ('137', '138', '139')) and ((p ->> 'ToPort') in ('137', '138', '139')))\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - Key: awsNetBiosTrustedIpRange Required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE '{{.awsNetBiosTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%' + AND (p ->> 'FromPort') IN ('137', '138', '139') + AND (p ->> 'ToPort') IN ('137', '138', '139') + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE '{{.awsNetBiosTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%' + AND (p ->> 'FromPort') IN ('137', '138', '139') + AND (p ->> 'ToPort') IN ('137', '138', '139') + ) THEN group_name || ' has Unrestricted NetBIOS Access' + ELSE group_name || ' NetBIOS Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE (p ->> 'FromPort') IN ('137', '138', '139') + AND (p ->> 'ToPort') IN ('137', '138', '139') + ) Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +58,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted NetBIOS Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_opensearch_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_opensearch_access.yaml old mode 100755 new mode 100644 index 35f9e53fb..dbdf83c93 --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_opensearch_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_opensearch_access.yaml @@ -1,15 +1,53 @@ +Description: Ensure no security group allows unrestricted inbound access to TCP port 9200 (OpenSearch). ID: aws_unrestricted_opensearch_access -Title: "Unrestricted OpenSearch Access" -Description: "Ensure no security group allows unrestricted inbound access to TCP port 9200 (OpenSearch)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsOpensearchTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '9200') and ((p ->> 'ToPort') = '9200')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsOpensearchTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '9200') and ((p ->> 'ToPort') = '9200')\n ) THEN group_name || ' has Unrestricted OpenSearch Access' \n ELSE group_name || ' OpenSearch Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n exists (select 1 from jsonb_array_elements(ip_permissions) as p where ((p ->> 'FromPort') = '9200') and ((p ->> 'ToPort') = '9200'))\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - Key: awsOpensearchTrustedIpRange Required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE '{{.awsOpensearchTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%' + AND (p ->> 'FromPort') = '9200' + AND (p ->> 'ToPort') = '9200' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE '{{.awsOpensearchTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%' + AND (p ->> 'FromPort') = '9200' + AND (p ->> 'ToPort') = '9200' + ) THEN group_name || ' has Unrestricted OpenSearch Access' + ELSE group_name || ' OpenSearch Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE (p ->> 'FromPort') = '9200' + AND (p ->> 'ToPort') = '9200' + ) Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +58,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted OpenSearch Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_oracle_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_oracle_access.yaml old mode 100755 new mode 100644 index 513257ad7..77b0021dd --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_oracle_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_oracle_access.yaml @@ -1,15 +1,53 @@ +Description: Ensure no security group allows unrestricted ingress access to port 1521. ID: aws_unrestricted_oracle_access -Title: "Unrestricted Oracle Access" -Description: "Ensure no security group allows unrestricted ingress access to port 1521." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsOracleTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '1521') and ((p ->> 'ToPort') = '1521')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsOracleTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '1521') and ((p ->> 'ToPort') = '1521')\n ) THEN group_name || ' has Unrestricted Oracle Access' \n ELSE group_name || ' Oracle Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n exists (select 1 from jsonb_array_elements(ip_permissions) as p where ((p ->> 'FromPort') = '1521') and ((p ->> 'ToPort') = '1521'))\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - Key: awsOracleTrustedIpRange Required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE '{{.awsOracleTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%' + AND (p ->> 'FromPort') = '1521' + AND (p ->> 'ToPort') = '1521' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE '{{.awsOracleTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%' + AND (p ->> 'FromPort') = '1521' + AND (p ->> 'ToPort') = '1521' + ) THEN group_name || ' has Unrestricted Oracle Access' + ELSE group_name || ' Oracle Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE (p ->> 'FromPort') = '1521' + AND (p ->> 'ToPort') = '1521' + ) Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +58,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted Oracle Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_rpc_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_rpc_access.yaml old mode 100755 new mode 100644 index 80b019e74..45cfc4291 --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_rpc_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_rpc_access.yaml @@ -1,15 +1,53 @@ +Description: Ensure no security group allows unrestricted inbound access to TCP port 135 (RPC). ID: aws_unrestricted_rpc_access -Title: "Unrestricted RPC Access" -Description: "Ensure no security group allows unrestricted inbound access to TCP port 135 (RPC)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsRpcTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '135') and ((p ->> 'ToPort') = '135')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsRpcTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '135') and ((p ->> 'ToPort') = '135')\n ) THEN group_name || ' has Unrestricted RPC Access' \n ELSE group_name || ' RPC Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n exists (select 1 from jsonb_array_elements(ip_permissions) as p where ((p ->> 'FromPort') = '135') and ((p ->> 'ToPort') = '135'))\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - Key: awsRpcTrustedIpRange Required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ('{{.awsRpcTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%') + AND (p ->> 'FromPort') = '135' + AND (p ->> 'ToPort') = '135' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ('{{.awsRpcTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%') + AND (p ->> 'FromPort') = '135' + AND (p ->> 'ToPort') = '135' + ) THEN group_name || ' has Unrestricted RPC Access' + ELSE group_name || ' RPC Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE (p ->> 'FromPort') = '135' + AND (p ->> 'ToPort') = '135' + ) Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +58,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted RPC Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_security_group_ingress_on_uncommon_ports.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_security_group_ingress_on_uncommon_ports.yaml old mode 100755 new mode 100644 index de6f6d8a5..fdb050058 --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_security_group_ingress_on_uncommon_ports.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_security_group_ingress_on_uncommon_ports.yaml @@ -1,13 +1,40 @@ +Description: Ensure no security group contains any 0.0.0.0/0 ingress rules. ID: aws_unrestricted_security_group_ingress_on_uncommon_ports -Title: "Unrestricted Security Group Ingress on Uncommon Ports" -Description: "Ensure no security group contains any 0.0.0.0/0 ingress rules." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ((p ->> 'IpRanges') LIKE '%0.0.0.0/0%' or (p ->> 'IpRanges' LIKE '%::/0%'))\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ((p ->> 'IpRanges') LIKE '%0.0.0.0/0%' or (p ->> 'IpRanges' LIKE '%::/0%'))\n ) THEN group_name || ' has Unrestricted Access' \n ELSE group_name || ' Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ((p ->> 'IpRanges') LIKE '%0.0.0.0/0%' OR (p ->> 'IpRanges' LIKE '%::/0%')) + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ((p ->> 'IpRanges') LIKE '%0.0.0.0/0%' OR (p ->> 'IpRanges' LIKE '%::/0%')) + ) THEN group_name || ' has Unrestricted Access' + ELSE group_name || ' Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +45,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted Security Group Ingress on Uncommon Ports \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_smtp_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_smtp_access.yaml old mode 100755 new mode 100644 index 6ebc464f4..16e86f242 --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_smtp_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_smtp_access.yaml @@ -1,15 +1,53 @@ +Description: Ensure no security group allows unrestricted inbound access to TCP port 25 (SMTP). ID: aws_unrestricted_smtp_access -Title: "Unrestricted SMTP Access" -Description: "Ensure no security group allows unrestricted inbound access to TCP port 25 (SMTP)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n group_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsSmtpTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '25') and ((p ->> 'ToPort') = '25')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN exists (\n select 1\n from jsonb_array_elements(ip_permissions) as p,\n jsonb_array_elements(p -> 'IpRanges') as r\n where ('{{.awsSmtpTrustedIpRange}}' not LIKE '%' || (r ->> 'CidrIp') || '%') and ((p ->> 'FromPort') = '25') and ((p ->> 'ToPort') = '25')\n ) THEN group_name || ' has Unrestricted SMTP Access' \n ELSE group_name || ' SMTP Access is secure'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_security_group\nWHERE\n exists (select 1 from jsonb_array_elements(ip_permissions) as p where ((p ->> 'FromPort') = '25') and ((p ->> 'ToPort') = '25'))\n" - PrimaryTable: aws_vpc_security_group ListOfTables: - aws_vpc_security_group Parameters: - Key: awsSmtpTrustedIpRange Required: true + PrimaryTable: aws_vpc_security_group + QueryToExecute: | + SELECT + group_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ('{{.awsSmtpTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%') + AND ((p ->> 'FromPort') = '25') + AND ((p ->> 'ToPort') = '25') + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p, + jsonb_array_elements(p -> 'IpRanges') AS r + WHERE ('{{.awsSmtpTrustedIpRange}}' NOT LIKE '%' || (r ->> 'CidrIp') || '%') + AND ((p ->> 'FromPort') = '25') + AND ((p ->> 'ToPort') = '25') + ) THEN group_name || ' has Unrestricted SMTP Access' + ELSE group_name || ' SMTP Access is secure' + END AS reason, + region, + account_id + FROM + aws_vpc_security_group + WHERE + EXISTS ( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS p + WHERE ((p ->> 'FromPort') = '25') + AND ((p ->> 'ToPort') = '25') + ) Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +58,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted SMTP Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unrestricted_ssh_access.yaml b/compliance/controls/baseline/aws/ec2/aws_unrestricted_ssh_access.yaml old mode 100755 new mode 100644 index da7488665..10b22515b --- a/compliance/controls/baseline/aws/ec2/aws_unrestricted_ssh_access.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unrestricted_ssh_access.yaml @@ -1,48 +1,49 @@ +Description: Ensure no security groups allow ingress from 0.0.0.0/0 to port 22. ID: aws_unrestricted_ssh_access -Title: "Unrestricted SSH Access" -Description: "Ensure no security groups allow ingress from 0.0.0.0/0 to port 22." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_vpc_security_group + - aws_vpc_security_group_rule + Parameters: [] + PrimaryTable: aws_vpc_security_group QueryToExecute: | - with ingress_sg as ( - select + WITH ingress_sg AS ( + SELECT group_id - from + FROM aws_vpc_security_group_rule - where + WHERE ( cidr_ipv4 = '0.0.0.0/0' - or cidr_ipv6 = '::/0' + OR cidr_ipv6 = '::/0' ) - and ip_protocol <> 'icmp' - and from_port = 22 - and to_port = 22 - and not is_egress - group by + AND ip_protocol <> 'icmp' + AND from_port = 22 + AND to_port = 22 + AND NOT is_egress + GROUP BY group_id ) - select - sg.group_id as resource, + SELECT + sg.group_id AS resource, og_resource_id, og_account_id, - case - when isg.group_id is null then 'ok' - else 'alarm' - end as status, - case - when isg.group_id is null then sg.group_id || ' does not allow unrestricted SSH access' - else sg.group_id || ' allows unrestricted SSH access' - end as reason, + CASE + WHEN isg.group_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN isg.group_id IS NULL THEN sg.group_id || ' does not allow unrestricted SSH access' + ELSE sg.group_id || ' allows unrestricted SSH access' + END AS reason, region, account_id - from - aws_vpc_security_group as sg - left join ingress_sg as isg on sg.group_id = isg.group_id - PrimaryTable: aws_vpc_security_group - ListOfTables: - - aws_vpc_security_group - - aws_vpc_security_group_rule - Parameters: [] + FROM + aws_vpc_security_group AS sg + LEFT JOIN ingress_sg AS isg ON sg.group_id = isg.group_id Severity: very high Tags: platform_score_cloud_service_name: @@ -53,5 +54,4 @@ Tags: - AWS EC2 score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted SSH Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unused_ami.yaml b/compliance/controls/baseline/aws/ec2/aws_unused_ami.yaml old mode 100755 new mode 100644 index f84d89772..788388672 --- a/compliance/controls/baseline/aws/ec2/aws_unused_ami.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unused_ami.yaml @@ -1,16 +1,71 @@ +Description: Identify unused Amazon Machine Images (AMI) to help lower the cost of your monthly AWS bill. ID: aws_unused_ami -Title: "Unused AMI" -Description: "Identify unused Amazon Machine Images (AMI) to help lower the cost of your monthly AWS bill." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with dlm_managed as (\n select og_resource_id from aws_ec2_ami CROSS JOIN jsonb_each(tags) where (key like 'aws:dlm%' or key = 'dlm:managed') limit 1\n)\nselect\n ami.name as resource,\n ami.og_resource_id,\n ami.og_account_id,\n case\n when is_aws_backup_managed then 'skip'\n when ami.root_device_type <> 'ebs' then 'skip'\n when i.arn is null then 'alarm'\n else 'ok'\n end as status,\n case\n when is_aws_backup_managed then name || ' is managed by aws'\n when ami.root_device_type <> 'ebs' then name || ' is not stored in ebs'\n when i.arn is null then ami.name || ' is unused.'\n else ami.name || ' is used.'\n end as reason, \n case\n when is_aws_backup_managed then 0\n when ami.root_device_type <> 'ebs' then 0\n when i.arn is null then (SELECT SUM((select cost from pennywise_cost_estimate AS es WHERE es.resource_type = 'aws::ec2::volumesnapshot' \n AND es.resource_id = s.arn limit 1))\n FROM jsonb_array_elements(ami.block_device_mappings) AS bdm\n LEFT JOIN aws_ebs_snapshot AS s ON s.snapshot_id = bdm -> 'Ebs' ->> 'SnapshotId')\n else 0\n end as cost_optimization,\n ami.region,\n ami.account_id\nfrom\n aws_ec2_ami AS ami\n LEFT JOIN aws_ec2_instance AS i ON ami.image_id = i.image_id\nwhere \n not(exists(select * from dlm_managed dl where dl.og_resource_id = ami.og_resource_id)) \n" - PrimaryTable: aws_ec2_ami ListOfTables: - aws_backup_managed - aws_ebs_snapshot - aws_ec2_ami - aws_ec2_instance Parameters: [] + PrimaryTable: aws_ec2_ami + QueryToExecute: | + WITH dlm_managed AS ( + SELECT + og_resource_id + FROM + aws_ec2_ami + CROSS JOIN + jsonb_each(tags) + WHERE + (key LIKE 'aws:dlm%' OR key = 'dlm:managed') + LIMIT 1 + ) + SELECT + ami.name AS resource, + ami.og_resource_id, + ami.og_account_id, + CASE + WHEN is_aws_backup_managed THEN 'skip' + WHEN ami.root_device_type <> 'ebs' THEN 'skip' + WHEN i.arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN is_aws_backup_managed THEN name || ' is managed by aws' + WHEN ami.root_device_type <> 'ebs' THEN name || ' is not stored in ebs' + WHEN i.arn IS NULL THEN ami.name || ' is unused.' + ELSE ami.name || ' is used.' + END AS reason, + CASE + WHEN is_aws_backup_managed THEN 0 + WHEN ami.root_device_type <> 'ebs' THEN 0 + WHEN i.arn IS NULL THEN ( + SELECT + SUM(( + SELECT cost + FROM pennywise_cost_estimate AS es + WHERE es.resource_type = 'aws::ec2::volumesnapshot' + AND es.resource_id = s.arn + LIMIT 1 + )) + FROM + jsonb_array_elements(ami.block_device_mappings) AS bdm + LEFT JOIN + aws_ebs_snapshot AS s ON s.snapshot_id = bdm -> 'Ebs' ->> 'SnapshotId' + ) + ELSE 0 + END AS cost_optimization, + ami.region, + ami.account_id + FROM + aws_ec2_ami AS ami + LEFT JOIN + aws_ec2_instance AS i ON ami.image_id = i.image_id + WHERE + NOT (EXISTS (SELECT * FROM dlm_managed dl WHERE dl.og_resource_id = ami.og_resource_id)) Severity: low Tags: platform_score_cloud_service_name: @@ -21,5 +76,4 @@ Tags: - AWS EC2 score_tags: - Orphaned Resources -IntegrationType: - - aws_cloud_account +Title: Unused AMI \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unused_aws_ec2_key_pairs.yaml b/compliance/controls/baseline/aws/ec2/aws_unused_aws_ec2_key_pairs.yaml old mode 100755 new mode 100644 index 5c3baba68..8595b1a04 --- a/compliance/controls/baseline/aws/ec2/aws_unused_aws_ec2_key_pairs.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unused_aws_ec2_key_pairs.yaml @@ -1,31 +1,32 @@ +Description: Ensure unused AWS EC2 key pairs are decommissioned to follow AWS security best practices. ID: aws_unused_aws_ec2_key_pairs -Title: "Unused AWS EC2 Key Pairs" -Description: "Ensure unused AWS EC2 key pairs are decommissioned to follow AWS security best practices." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_instance + - aws_ec2_key_pair + Parameters: [] + PrimaryTable: aws_ec2_key_pair QueryToExecute: | - select - k.key_name as resource, + SELECT + k.key_name AS resource, k.og_resource_id, k.og_account_id, - case - when i.arn is null then 'alarm' - else 'ok' - end as status, - case - when i.arn is null then k.key_name || ' is unused.' - else k.key_name || ' is used.' - end as reason, + CASE + WHEN i.arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.arn IS NULL THEN k.key_name || ' is unused.' + ELSE k.key_name || ' is used.' + END AS reason, k.region, k.account_id - from + FROM aws_ec2_key_pair AS k LEFT JOIN aws_ec2_instance AS i ON k.key_name = i.key_name - PrimaryTable: aws_ec2_key_pair - ListOfTables: - - aws_ec2_instance - - aws_ec2_key_pair - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS EC2 score_tags: - Missing Tags -IntegrationType: - - aws_cloud_account +Title: Unused AWS EC2 Key Pairs \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ec2/aws_unused_elastic_network_interfaces.yaml b/compliance/controls/baseline/aws/ec2/aws_unused_elastic_network_interfaces.yaml old mode 100755 new mode 100644 index 72c87274d..a23c77048 --- a/compliance/controls/baseline/aws/ec2/aws_unused_elastic_network_interfaces.yaml +++ b/compliance/controls/baseline/aws/ec2/aws_unused_elastic_network_interfaces.yaml @@ -1,13 +1,30 @@ +Description: Identify and delete any unused Elastic Network Interfaces ID: aws_unused_elastic_network_interfaces -Title: "Unused Elastic Network Interfaces" -Description: "Identify and delete any unused Elastic Network Interfaces" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n network_interface_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN status = 'available' THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN status = 'available' THEN network_interface_id || ' is unused and can be safely removed' \n ELSE network_interface_id || ' is used.'\n END AS reason,\n region,\n account_id\nFROM \n aws_ec2_network_interface\n" - PrimaryTable: aws_ec2_network_interface ListOfTables: - aws_ec2_network_interface Parameters: [] + PrimaryTable: aws_ec2_network_interface + QueryToExecute: | + SELECT + network_interface_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN status = 'available' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN status = 'available' THEN network_interface_id || ' is unused and can be safely removed' + ELSE network_interface_id || ' is used.' + END AS reason, + region, + account_id + FROM + aws_ec2_network_interface Severity: low Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS EC2 score_tags: - Under Utilization -IntegrationType: - - aws_cloud_account +Title: Unused Elastic Network Interfaces \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ecr/aws_ecr_repository_exposed.yaml b/compliance/controls/baseline/aws/ecr/aws_ecr_repository_exposed.yaml old mode 100755 new mode 100644 index a18d47820..8d0bfecaf --- a/compliance/controls/baseline/aws/ecr/aws_ecr_repository_exposed.yaml +++ b/compliance/controls/baseline/aws/ecr/aws_ecr_repository_exposed.yaml @@ -1,42 +1,44 @@ +Description: Ensure that AWS Elastic Container Registry (ECR) repositories are not exposed to everyone. ID: aws_ecr_repository_exposed -Title: "ECR Repository Exposed" -Description: "Ensure that AWS Elastic Container Registry (ECR) repositories are not exposed to everyone." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ecr_repository + Parameters: [] + PrimaryTable: aws_ecr_repository QueryToExecute: | - select - repository_name as resource, + SELECT + repository_name AS resource, og_resource_id, og_account_id, - case - when exists ( - select 1 - from jsonb_array_elements(policy_std -> 'Statement') as p - where p ->> 'Effect' = 'Allow' and p ->> 'Principal' = '*' - ) then 'alarm' - else 'ok' - end as status, - case - when exists ( - select 1 - from jsonb_array_elements(policy_std -> 'Statement') as p - where p ->> 'Effect' = 'Allow' and p ->> 'Principal' = '*' - ) then repository_name || ' repository is exposed to everyone.' - else repository_name || ' repository is not exposed to everyone.' - end as reason, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(policy_std -> 'Statement') AS p + WHERE p ->> 'Effect' = 'Allow' + AND p ->> 'Principal' = '*' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(policy_std -> 'Statement') AS p + WHERE p ->> 'Effect' = 'Allow' + AND p ->> 'Principal' = '*' + ) THEN repository_name || ' repository is exposed to everyone.' + ELSE repository_name || ' repository is not exposed to everyone.' + END AS reason, region, account_id - from + FROM aws_ecr_repository - PrimaryTable: aws_ecr_repository - ListOfTables: - - aws_ecr_repository - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: - Elastic Container Registry (ECR) score_service_name: - Elastic Container Registry (ECR) -IntegrationType: - - aws_cloud_account +Title: ECR Repository Exposed \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ecr/aws_enable_cross_region_replication.yaml b/compliance/controls/baseline/aws/ecr/aws_enable_cross_region_replication.yaml old mode 100755 new mode 100644 index e589352f0..663598283 --- a/compliance/controls/baseline/aws/ecr/aws_enable_cross_region_replication.yaml +++ b/compliance/controls/baseline/aws/ecr/aws_enable_cross_region_replication.yaml @@ -1,48 +1,48 @@ +Description: Ensure that Cross-Region Replication feature is enabled for your Amazon ECR container images. ID: aws_enable_cross_region_replication -Title: "Enable Cross-Region Replication" -Description: "Ensure that Cross-Region Replication feature is enabled for your Amazon ECR container images." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ecr_registry + Parameters: [] + PrimaryTable: aws_ecr_registry QueryToExecute: | - select - account_id || ' backup region setting in ' || region as resource, + SELECT + account_id || ' backup region setting in ' || region AS resource, og_resource_id, og_account_id, - case - when rules::text = '[]' then 'alarm' - when exists ( - select 1 - from jsonb_array_elements(rules) as r, - jsonb_array_elements(r -> 'Destinations') as d - where + CASE + WHEN rules::text = '[]' THEN 'alarm' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(rules) AS r, + jsonb_array_elements(r -> 'Destinations') AS d + WHERE d ->> 'RegistryId' = registry_id - ) then 'ok' - else 'alarm' - end as status, - case - when rules::text = '[]' then 'Cross-Region Replication feature is not enabled' - when exists ( - select 1 - from jsonb_array_elements(rules) as r, - jsonb_array_elements(r -> 'Destinations') as d - where + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN rules::text = '[]' THEN 'Cross-Region Replication feature is not enabled' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(rules) AS r, + jsonb_array_elements(r -> 'Destinations') AS d + WHERE d ->> 'RegistryId' = registry_id - ) then 'Cross-Region Replication feature is enabled' - else 'Cross-Region Replication feature is not enabled' - end as reason, + ) THEN 'Cross-Region Replication feature is enabled' + ELSE 'Cross-Region Replication feature is not enabled' + END AS reason, region, account_id - from + FROM aws_ecr_registry - PrimaryTable: aws_ecr_registry - ListOfTables: - - aws_ecr_registry - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Elastic Container Registry (ECR) score_service_name: - Elastic Container Registry (ECR) -IntegrationType: - - aws_cloud_account +Title: Enable Cross-Region Replication \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ecr/aws_enable_scan_on_push_for_ecr_container_images.yaml b/compliance/controls/baseline/aws/ecr/aws_enable_scan_on_push_for_ecr_container_images.yaml old mode 100755 new mode 100644 index d19a827a9..2c121be80 --- a/compliance/controls/baseline/aws/ecr/aws_enable_scan_on_push_for_ecr_container_images.yaml +++ b/compliance/controls/baseline/aws/ecr/aws_enable_scan_on_push_for_ecr_container_images.yaml @@ -1,34 +1,34 @@ +Description: Ensure that each Amazon ECR container image is automatically scanned for vulnerabilities when pushed to a repository. ID: aws_enable_scan_on_push_for_ecr_container_images -Title: "Enable Scan on Push for ECR Container Images" -Description: "Ensure that each Amazon ECR container image is automatically scanned for vulnerabilities when pushed to a repository." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ecr_repository + Parameters: [] + PrimaryTable: aws_ecr_repository QueryToExecute: | - select - repository_name as resource, + SELECT + repository_name AS resource, og_resource_id, og_account_id, - case - when image_scanning_configuration ->> 'ScanOnPush' = 'true' then 'ok' - else 'alarm' - end as status, - case - when image_scanning_configuration ->> 'ScanOnPush' = 'true' then repository_name || ' container images are not automatically scanned for vulnerabilities' - else repository_name || ' container images are automatically scanned for vulnerabilities' - end as reason, + CASE + WHEN image_scanning_configuration ->> 'ScanOnPush' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN image_scanning_configuration ->> 'ScanOnPush' = 'true' THEN repository_name || ' container images are automatically scanned for vulnerabilities' + ELSE repository_name || ' container images are not automatically scanned for vulnerabilities' + END AS reason, region, account_id - from + FROM aws_ecr_repository - PrimaryTable: aws_ecr_repository - ListOfTables: - - aws_ecr_repository - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Elastic Container Registry (ECR) score_service_name: - Elastic Container Registry (ECR) -IntegrationType: - - aws_cloud_account +Title: Enable Scan on Push for ECR Container Images \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ecr/aws_lifecycle_policy_in_use.yaml b/compliance/controls/baseline/aws/ecr/aws_lifecycle_policy_in_use.yaml old mode 100755 new mode 100644 index bda465716..afd53dc29 --- a/compliance/controls/baseline/aws/ecr/aws_lifecycle_policy_in_use.yaml +++ b/compliance/controls/baseline/aws/ecr/aws_lifecycle_policy_in_use.yaml @@ -1,48 +1,49 @@ +Description: Ensure that each Amazon ECR container image is automatically scanned for vulnerabilities when pushed to a repository. ID: aws_lifecycle_policy_in_use -Title: "Lifecycle Policy in Use" -Description: "Ensure that each Amazon ECR container image is automatically scanned for vulnerabilities when pushed to a repository." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ecr_repository + Parameters: [] + PrimaryTable: aws_ecr_repository QueryToExecute: | - with repo_with_policy as ( - select + WITH repo_with_policy AS ( + SELECT repository_name - from + FROM aws_ecr_repository, - jsonb_array_elements(lifecycle_policy -> 'rules') as r - where + jsonb_array_elements(lifecycle_policy -> 'rules') AS r + WHERE ( (r -> 'selection' ->> 'tagStatus' = 'untagged') - and (r -> 'selection' ->> 'countType' = 'sinceImagePushed') + AND (r -> 'selection' ->> 'countType' = 'sinceImagePushed') ) ) - - select - r.repository_name as resource, + + SELECT + r.repository_name AS resource, og_resource_id, og_account_id, - case - when p.repository_name is not null then 'ok' - else 'alarm' - end as status, - case - when p.repository_name is not null then r.repository_name || ' associated lifecycle policy is configured to remove untagged and old images' - else r.repository_name || ' associated lifecycle policy is not configured to remove untagged and old images' - end as reason, + CASE + WHEN p.repository_name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.repository_name IS NOT NULL THEN r.repository_name || ' associated lifecycle policy is configured to remove untagged and old images' + ELSE r.repository_name || ' associated lifecycle policy is not configured to remove untagged and old images' + END AS reason, region, account_id - from - aws_ecr_repository as r - left join repo_with_policy as p on r.repository_name = p.repository_name - PrimaryTable: aws_ecr_repository - ListOfTables: - - aws_ecr_repository - Parameters: [] + FROM + aws_ecr_repository AS r + LEFT JOIN repo_with_policy AS p + ON r.repository_name = p.repository_name Severity: low Tags: platform_score_cloud_service_name: - Elastic Container Registry (ECR) score_service_name: - Elastic Container Registry (ECR) -IntegrationType: - - aws_cloud_account +Title: Lifecycle Policy in Use \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ecs/aws_check_for_amazon_ecs_service_placement_strategy.yaml b/compliance/controls/baseline/aws/ecs/aws_check_for_amazon_ecs_service_placement_strategy.yaml old mode 100755 new mode 100644 index 67233e517..96496c993 --- a/compliance/controls/baseline/aws/ecs/aws_check_for_amazon_ecs_service_placement_strategy.yaml +++ b/compliance/controls/baseline/aws/ecs/aws_check_for_amazon_ecs_service_placement_strategy.yaml @@ -1,29 +1,34 @@ +Description: Ensure that your Amazon ECS cluster services are using optimal placement strategies. ID: aws_check_for_amazon_ecs_service_placement_strategy -Title: "Check for Amazon ECS Service Placement Strategy" -Description: "Ensure that your Amazon ECS cluster services are using optimal placement strategies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ecs_service + Parameters: [] + PrimaryTable: aws_ecs_service QueryToExecute: | - select - service_name as resource, + SELECT + service_name AS resource, og_resource_id, og_account_id, - case - when (select ARRAY_AGG(ps ->> 'Type') from jsonb_array_elements(placement_strategy) as ps) = ARRAY['spread', 'binpack'] then 'ok' - else 'alarm' - end as status, - case - when (select ARRAY_AGG(ps ->> 'Type') from jsonb_array_elements(placement_strategy) as ps) = ARRAY['spread', 'binpack'] then 'task placement strategy is compliant' - else 'task placement strategy is not compliant' - end as reason, + CASE + WHEN (SELECT ARRAY_AGG(ps ->> 'Type') + FROM jsonb_array_elements(placement_strategy) AS ps) = ARRAY['spread', 'binpack'] + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (SELECT ARRAY_AGG(ps ->> 'Type') + FROM jsonb_array_elements(placement_strategy) AS ps) = ARRAY['spread', 'binpack'] + THEN 'task placement strategy is compliant' + ELSE 'task placement strategy is not compliant' + END AS reason, region, account_id - from + FROM aws_ecs_service - PrimaryTable: aws_ecs_service - ListOfTables: - - aws_ecs_service - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -34,5 +39,4 @@ Tags: - Elastic Container Service (ECS) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Check for Amazon ECS Service Placement Strategy \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ecs/aws_check_for_ecs_container_instance_agent_version.yaml b/compliance/controls/baseline/aws/ecs/aws_check_for_ecs_container_instance_agent_version.yaml old mode 100755 new mode 100644 index 54e591f3f..37e4edf73 --- a/compliance/controls/baseline/aws/ecs/aws_check_for_ecs_container_instance_agent_version.yaml +++ b/compliance/controls/baseline/aws/ecs/aws_check_for_ecs_container_instance_agent_version.yaml @@ -1,31 +1,32 @@ +Description: Ensure that your Amazon ECS instances are using the latest ECS container agent version. ID: aws_check_for_ecs_container_instance_agent_version -Title: "Check for ECS Container Instance Agent Version" -Description: "Ensure that your Amazon ECS instances are using the latest ECS container agent version." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ecs_container_instance + Parameters: + - Key: awsEcsContainerInstanceAgentVersion + Required: true + PrimaryTable: aws_ecs_container_instance QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when version_info ->> 'AgentVersion' < '{{.awsEcsContainerInstanceAgentVersion}}' then 'alarm' - else 'ok' - end as status, - case - when version_info ->> 'AgentVersion' < '{{.awsEcsContainerInstanceAgentVersion}}' then 'Container instance is not using the latest supported version of agent' - else 'Container instance is using the latest supported version of agent' - end as reason, + CASE + WHEN version_info ->> 'AgentVersion' < '{{.awsEcsContainerInstanceAgentVersion}}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN version_info ->> 'AgentVersion' < '{{.awsEcsContainerInstanceAgentVersion}}' THEN 'Container instance is not using the latest supported version of agent' + ELSE 'Container instance is using the latest supported version of agent' + END AS reason, region, account_id - from + FROM aws_ecs_container_instance - PrimaryTable: aws_ecs_container_instance - ListOfTables: - - aws_ecs_container_instance - Parameters: - - Key: awsEcsContainerInstanceAgentVersion - Required: true Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - Elastic Container Service (ECS) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Check for ECS Container Instance Agent Version \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ecs/aws_check_for_fargate_platform_version.yaml b/compliance/controls/baseline/aws/ecs/aws_check_for_fargate_platform_version.yaml old mode 100755 new mode 100644 index 93af2cf56..0c1f91313 --- a/compliance/controls/baseline/aws/ecs/aws_check_for_fargate_platform_version.yaml +++ b/compliance/controls/baseline/aws/ecs/aws_check_for_fargate_platform_version.yaml @@ -1,31 +1,32 @@ +Description: Ensure that your Amazon ECS cluster services are using the latest Fargate platform version. ID: aws_check_for_fargate_platform_version -Title: "Check for Fargate Platform Version" -Description: "Ensure that your Amazon ECS cluster services are using the latest Fargate platform version." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ecs_service + Parameters: + - Key: awsEcsServicePlatformVersion + Required: true + PrimaryTable: aws_ecs_service QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when platform_version < '{{.awsEcsServicePlatformVersion}}' then 'alarm' - else 'ok' - end as status, - case - when platform_version < '{{.awsEcsServicePlatformVersion}}' then 'Service is not using the latest supported version of platform' - else 'Service is using the latest supported version of platform' - end as reason, + CASE + WHEN platform_version < '{{.awsEcsServicePlatformVersion}}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN platform_version < '{{.awsEcsServicePlatformVersion}}' THEN 'Service is not using the latest supported version of platform' + ELSE 'Service is using the latest supported version of platform' + END AS reason, region, account_id - from + FROM aws_ecs_service - PrimaryTable: aws_ecs_service - ListOfTables: - - aws_ecs_service - Parameters: - - Key: awsEcsServicePlatformVersion - Required: true Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - Elastic Container Service (ECS) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Check for Fargate Platform Version \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ecs/aws_ecs_task_log_driver_in_use.yaml b/compliance/controls/baseline/aws/ecs/aws_ecs_task_log_driver_in_use.yaml old mode 100755 new mode 100644 index a958eeaa9..81310f679 --- a/compliance/controls/baseline/aws/ecs/aws_ecs_task_log_driver_in_use.yaml +++ b/compliance/controls/baseline/aws/ecs/aws_ecs_task_log_driver_in_use.yaml @@ -1,30 +1,31 @@ +Description: Ensure that a log driver has been defined for each active Amazon ECS task definition. ID: aws_ecs_task_log_driver_in_use -Title: "Amazon ECS Task Log Driver in Use" -Description: "Ensure that a log driver has been defined for each active Amazon ECS task definition." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ecs_task_definition + Parameters: [] + PrimaryTable: aws_ecs_task_definition QueryToExecute: | - select - td.task_definition_arn || ' - ' || (c ->> 'Name') as resource, + SELECT + td.task_definition_arn || ' - ' || (c ->> 'Name') AS resource, og_resource_id, og_account_id, - case - when (c -> 'LogConfiguration' ->> 'LogDriver') is null then 'alarm' - else 'ok' - end as status, - case - when (c -> 'LogConfiguration' ->> 'LogDriver') is null then td.task_definition_arn || ' - ' || (c ->> 'Name') || ' has no log driver' - else td.task_definition_arn || ' - ' || (c ->> 'Name') || ' has log driver' - end as reason, + CASE + WHEN (c -> 'LogConfiguration' ->> 'LogDriver') IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (c -> 'LogConfiguration' ->> 'LogDriver') IS NULL THEN td.task_definition_arn || ' - ' || (c ->> 'Name') || ' has no log driver' + ELSE td.task_definition_arn || ' - ' || (c ->> 'Name') || ' has log driver' + END AS reason, region, account_id - from - aws_ecs_task_definition as td, - jsonb_array_elements(container_definitions) as c - PrimaryTable: aws_ecs_task_definition - ListOfTables: - - aws_ecs_task_definition - Parameters: [] + FROM + aws_ecs_task_definition AS td, + jsonb_array_elements(container_definitions) AS c Severity: high Tags: platform_score_cloud_service_name: @@ -35,5 +36,4 @@ Tags: - Elastic Container Service (ECS) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Amazon ECS Task Log Driver in Use \ No newline at end of file diff --git a/compliance/controls/baseline/aws/ecs/aws_enable_cloudwatch_container_insights.yaml b/compliance/controls/baseline/aws/ecs/aws_enable_cloudwatch_container_insights.yaml old mode 100755 new mode 100644 index 32fc0dd23..1dc235be9 --- a/compliance/controls/baseline/aws/ecs/aws_enable_cloudwatch_container_insights.yaml +++ b/compliance/controls/baseline/aws/ecs/aws_enable_cloudwatch_container_insights.yaml @@ -1,42 +1,41 @@ +Description: Ensure that CloudWatch Container Insights feature is enabled for your AWS ECS clusters. ID: aws_enable_cloudwatch_container_insights -Title: "Enable CloudWatch Container Insights" -Description: "Ensure that CloudWatch Container Insights feature is enabled for your AWS ECS clusters." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ecs_cluster + Parameters: [] + PrimaryTable: aws_ecs_cluster QueryToExecute: | - select - cluster_arn as resource, + SELECT + cluster_arn AS resource, og_resource_id, og_account_id, - case - when exists ( - select 1 - from jsonb_array_elements(settings) as s - where s ->> 'Name' = 'containerInsights' and s ->> 'Value' = 'enabled' - ) then 'ok' - else 'alarm' - end as status, - case - when exists ( - select 1 - from jsonb_array_elements(settings) as s - where s ->> 'Name' = 'containerInsights' and s ->> 'Value' = 'enabled' - ) then 'Container Insights feature is enabled' - else 'Container Insights feature is not currently enabled' - end as reason, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(settings) AS s + WHERE s ->> 'Name' = 'containerInsights' AND s ->> 'Value' = 'enabled' + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(settings) AS s + WHERE s ->> 'Name' = 'containerInsights' AND s ->> 'Value' = 'enabled' + ) THEN 'Container Insights feature is enabled' + ELSE 'Container Insights feature is not currently enabled' + END AS reason, region, account_id - from - aws_ecs_cluster - PrimaryTable: aws_ecs_cluster - ListOfTables: - - aws_ecs_cluster - Parameters: [] + FROM aws_ecs_cluster Severity: low Tags: platform_score_cloud_service_name: - Elastic Container Service (ECS) score_service_name: - Elastic Container Service (ECS) -IntegrationType: - - aws_cloud_account +Title: Enable CloudWatch Container Insights \ No newline at end of file diff --git a/compliance/controls/baseline/aws/efs/aws_efs_encryption_enabled.yaml b/compliance/controls/baseline/aws/efs/aws_efs_encryption_enabled.yaml old mode 100755 new mode 100644 index 2fa4cbc16..d811a6af5 --- a/compliance/controls/baseline/aws/efs/aws_efs_encryption_enabled.yaml +++ b/compliance/controls/baseline/aws/efs/aws_efs_encryption_enabled.yaml @@ -1,29 +1,30 @@ +Description: Ensure encryption is enabled for AWS EFS file systems to protect your data at rest. ID: aws_efs_encryption_enabled -Title: "EFS Encryption Enabled" -Description: "Ensure encryption is enabled for AWS EFS file systems to protect your data at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_efs_file_system + Parameters: [] + PrimaryTable: aws_efs_file_system QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when encrypted::bool then 'ok' - else 'alarm' - end as status, - case - when encrypted::bool then title || ' encryption enabled.' - else title || ' encryption not enabled.' - end as reason, + CASE + WHEN encrypted::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted::bool THEN title || ' encryption enabled.' + ELSE title || ' encryption not enabled.' + END AS reason, region, account_id - from + FROM aws_efs_file_system - PrimaryTable: aws_efs_file_system - ListOfTables: - - aws_efs_file_system - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - Amazon Elastic File System (EFS) score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: EFS Encryption Enabled \ No newline at end of file diff --git a/compliance/controls/baseline/aws/efs/aws_kms_customer_master_keys_for_efs_encryption.yaml b/compliance/controls/baseline/aws/efs/aws_kms_customer_master_keys_for_efs_encryption.yaml old mode 100755 new mode 100644 index 37dca2db0..7a6fddf11 --- a/compliance/controls/baseline/aws/efs/aws_kms_customer_master_keys_for_efs_encryption.yaml +++ b/compliance/controls/baseline/aws/efs/aws_kms_customer_master_keys_for_efs_encryption.yaml @@ -1,33 +1,34 @@ +Description: Ensure EFS file systems are encrypted with KMS Customer Master Keys (CMKs) in order to have full control over data encryption and decryption. ID: aws_kms_customer_master_keys_for_efs_encryption -Title: "AWS KMS Customer Master Keys for EFS Encryption" -Description: "Ensure EFS file systems are encrypted with KMS Customer Master Keys (CMKs) in order to have full control over data encryption and decryption." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_efs_file_system + - aws_kms_key + Parameters: [] + PrimaryTable: aws_efs_file_system QueryToExecute: | - select - fs.file_system_id as resource, + SELECT + fs.file_system_id AS resource, fs.og_resource_id, fs.og_account_id, - case - when k.arn is null then 'alarm' - when k.key_manager = 'CUSTOMER' then 'ok' - else 'alarm' - end as status, - case - when k.arn is null then fs.file_system_id || ' is not using a master key' - when k.key_manager = 'CUSTOMER' then fs.file_system_id || ' is using a customer master key' - else fs.file_system_id || ' is using a AWS-managed master key' - end as reason, + CASE + WHEN k.arn IS NULL THEN 'alarm' + WHEN k.key_manager = 'CUSTOMER' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN k.arn IS NULL THEN fs.file_system_id || ' is not using a master key' + WHEN k.key_manager = 'CUSTOMER' THEN fs.file_system_id || ' is using a customer master key' + ELSE fs.file_system_id || ' is using an AWS-managed master key' + END AS reason, fs.region, fs.account_id - from - aws_efs_file_system as fs - left join aws_kms_key as k on fs.kms_key_id = k.arn - PrimaryTable: aws_efs_file_system - ListOfTables: - - aws_efs_file_system - - aws_kms_key - Parameters: [] + FROM + aws_efs_file_system AS fs + LEFT JOIN aws_kms_key AS k ON fs.kms_key_id = k.arn Severity: high Tags: platform_score_cloud_service_name: @@ -38,5 +39,4 @@ Tags: - Amazon Elastic File System (EFS) score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: AWS KMS Customer Master Keys for EFS Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_disable_remote_access_to_eks_cluster_node_groups.yaml b/compliance/controls/baseline/aws/eks/aws_disable_remote_access_to_eks_cluster_node_groups.yaml old mode 100755 new mode 100644 index 7c9287355..f21bd51f2 --- a/compliance/controls/baseline/aws/eks/aws_disable_remote_access_to_eks_cluster_node_groups.yaml +++ b/compliance/controls/baseline/aws/eks/aws_disable_remote_access_to_eks_cluster_node_groups.yaml @@ -1,29 +1,30 @@ +Description: Ensure that remote access to EKS cluster node groups is disabled. ID: aws_disable_remote_access_to_eks_cluster_node_groups -Title: "Disable Remote Access to EKS Cluster Node Groups" -Description: "Ensure that remote access to EKS cluster node groups is disabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_eks_node_group + Parameters: [] + PrimaryTable: aws_eks_node_group QueryToExecute: | - select - nodegroup_name as resource, + SELECT + nodegroup_name AS resource, og_account_id, og_resource_id, - case - when remote_access ->> 'Ec2SshKey' is null then 'ok' - else 'alarm' - end as status, - case - when remote_access ->> 'Ec2SshKey' is null then nodegroup_name || ' SSH remote access is disabled.' - else nodegroup_name || ' SSH remote access is not disabled.' - end as reason, + CASE + WHEN remote_access ->> 'Ec2SshKey' IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN remote_access ->> 'Ec2SshKey' IS NULL THEN nodegroup_name || ' SSH remote access is disabled.' + ELSE nodegroup_name || ' SSH remote access is not disabled.' + END AS reason, region, account_id - from + FROM aws_eks_node_group; - PrimaryTable: aws_eks_node_group - ListOfTables: - - aws_eks_node_group - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Disable Remote Access to EKS Cluster Node Groups \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_eks_cluster_endpoint_public_access.yaml b/compliance/controls/baseline/aws/eks/aws_eks_cluster_endpoint_public_access.yaml old mode 100755 new mode 100644 index 115a91359..7b5d43d46 --- a/compliance/controls/baseline/aws/eks/aws_eks_cluster_endpoint_public_access.yaml +++ b/compliance/controls/baseline/aws/eks/aws_eks_cluster_endpoint_public_access.yaml @@ -1,31 +1,34 @@ +Description: Ensure that AWS EKS cluster endpoint access isn't public and prone to security risks. ID: aws_eks_cluster_endpoint_public_access -Title: "EKS Cluster Endpoint Public Access" -Description: "Ensure that AWS EKS cluster endpoint access isn't public and prone to security risks." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_eks_cluster + Parameters: [] + PrimaryTable: aws_eks_cluster QueryToExecute: | - select - name as resource, + SELECT + name AS resource, og_account_id, og_resource_id, - case - when resources_vpc_config ->> 'EndpointPublicAccess' = 'true' and - (resources_vpc_config ->> 'PublicAccessCidrs')::text like '%"0.0.0.0/0"%' then 'alarm' - else 'ok' - end as status, - case - when resources_vpc_config ->> 'EndpointPublicAccess' = 'true' and - (resources_vpc_config ->> 'PublicAccessCidrs')::text like '%"0.0.0.0/0"%' then name || ' Kubernetes API endpoint configured is publicly accessible.' - else name || ' Kubernetes API endpoint configured is not publicly accessible.' - end as reason, + CASE + WHEN resources_vpc_config ->> 'EndpointPublicAccess' = 'true' + AND (resources_vpc_config ->> 'PublicAccessCidrs')::text LIKE '%"0.0.0.0/0"%' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN resources_vpc_config ->> 'EndpointPublicAccess' = 'true' + AND (resources_vpc_config ->> 'PublicAccessCidrs')::text LIKE '%"0.0.0.0/0"%' + THEN name || ' Kubernetes API endpoint configured is publicly accessible.' + ELSE name || ' Kubernetes API endpoint configured is not publicly accessible.' + END AS reason, region, account_id - from + FROM aws_eks_cluster; - PrimaryTable: aws_eks_cluster - ListOfTables: - - aws_eks_cluster - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -36,5 +39,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: EKS Cluster Endpoint Public Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_eks_cluster_node_group_iam_role_policies.yaml b/compliance/controls/baseline/aws/eks/aws_eks_cluster_node_group_iam_role_policies.yaml old mode 100755 new mode 100644 index 18beae16b..45ca1ab18 --- a/compliance/controls/baseline/aws/eks/aws_eks_cluster_node_group_iam_role_policies.yaml +++ b/compliance/controls/baseline/aws/eks/aws_eks_cluster_node_group_iam_role_policies.yaml @@ -1,14 +1,44 @@ +Description: Ensure that EKS Cluster node groups are using appropriate permissions. ID: aws_eks_cluster_node_group_iam_role_policies -Title: "EKS Cluster Node Group IAM Role Policies" -Description: "Ensure that EKS Cluster node groups are using appropriate permissions." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n ng.nodegroup_name as resource,\n ng.og_account_id,\n ng.og_resource_id,\n case\n when exists(\n select 1\n from jsonb_array_elements_text(attached_policy_arns) as p \n where p <> 'arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly' and p <> 'arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy'\n ) then 'alarm'\n when r.inline_policies is not null then 'alarm'\n else 'ok'\n end as status,\n case\n when exists(\n select 1\n from jsonb_array_elements_text(attached_policy_arns) as p \n where p <> 'arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly' and p <> 'arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy'\n ) then 'permissions configured for IAM role are too permissive'\n when r.inline_policies is not null then 'permissions configured for IAM role are too permissive'\n else 'permissions configured for IAM role are not too permissive'\n end as reason,\n ng.region,\n ng.account_id\nfrom\n aws_eks_node_group as ng\n left join aws_iam_role as r on r.arn = ng.node_role\n" - PrimaryTable: aws_eks_node_group ListOfTables: - aws_eks_node_group - aws_iam_role Parameters: [] + PrimaryTable: aws_eks_node_group + QueryToExecute: | + SELECT + ng.nodegroup_name AS resource, + ng.og_account_id, + ng.og_resource_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS p + WHERE p <> 'arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly' + AND p <> 'arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy' + ) THEN 'alarm' + WHEN r.inline_policies IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements_text(attached_policy_arns) AS p + WHERE p <> 'arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly' + AND p <> 'arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy' + ) THEN 'permissions configured for IAM role are too permissive' + WHEN r.inline_policies IS NOT NULL THEN 'permissions configured for IAM role are too permissive' + ELSE 'permissions configured for IAM role are not too permissive' + END AS reason, + ng.region, + ng.account_id + FROM + aws_eks_node_group AS ng + LEFT JOIN aws_iam_role AS r ON r.arn = ng.node_role Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +49,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: EKS Cluster Node Group IAM Role Policies \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_eks_security_groups.yaml b/compliance/controls/baseline/aws/eks/aws_eks_security_groups.yaml old mode 100755 new mode 100644 index 319c899b9..2c4e7a2e3 --- a/compliance/controls/baseline/aws/eks/aws_eks_security_groups.yaml +++ b/compliance/controls/baseline/aws/eks/aws_eks_security_groups.yaml @@ -1,14 +1,41 @@ +Description: Ensure that AWS EKS security groups are configured to allow incoming traffic only on TCP port 443. ID: aws_eks_security_groups -Title: "EKS Security Groups" -Description: "Ensure that AWS EKS security groups are configured to allow incoming traffic only on TCP port 443." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n c.name as resource,\n c.og_account_id,\n c.og_resource_id,\n case\n when exists(\n select 1\n from jsonb_array_elements(ip_permissions) as ips \n where (ips ->> 'FromPort' <> '443') and (ips ->> 'ToPort' <> '443')\n ) then 'alarm'\n else 'ok'\n end as status,\n case\n when exists(\n select 1\n from jsonb_array_elements(ip_permissions) as ips \n where (ips ->> 'FromPort' <> '443') and (ips ->> 'ToPort' <> '443')\n ) then name || ' Amazon EKS security group is not compliant (allow access on ports different than TCP port 443 (HTTPS))'\n else name || ' Amazon EKS security group is compliant'\n end as reason,\n c.region,\n c.account_id\nfrom\n aws_eks_cluster as c\n cross join jsonb_array_elements_text(resources_vpc_config -> 'SecurityGroupIds') as sg_id\n left join aws_vpc_security_group as sg on sg.group_id = sg_id\n" - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_eks_cluster + QueryToExecute: | + SELECT + c.name AS resource, + c.og_account_id, + c.og_resource_id, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS ips + WHERE (ips ->> 'FromPort' <> '443') AND (ips ->> 'ToPort' <> '443') + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements(ip_permissions) AS ips + WHERE (ips ->> 'FromPort' <> '443') AND (ips ->> 'ToPort' <> '443') + ) THEN name || ' Amazon EKS security group is not compliant (allow access on ports different than TCP port 443 (HTTPS))' + ELSE name || ' Amazon EKS security group is compliant' + END AS reason, + c.region, + c.account_id + FROM + aws_eks_cluster AS c + CROSS JOIN jsonb_array_elements_text(resources_vpc_config -> 'SecurityGroupIds') AS sg_id + LEFT JOIN aws_vpc_security_group AS sg ON sg.group_id = sg_id Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +46,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: EKS Security Groups \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_enable_cloudtrail_logging_for_kubernetes_api_calls.yaml b/compliance/controls/baseline/aws/eks/aws_enable_cloudtrail_logging_for_kubernetes_api_calls.yaml old mode 100755 new mode 100644 index b47b131f9..2084ce82b --- a/compliance/controls/baseline/aws/eks/aws_enable_cloudtrail_logging_for_kubernetes_api_calls.yaml +++ b/compliance/controls/baseline/aws/eks/aws_enable_cloudtrail_logging_for_kubernetes_api_calls.yaml @@ -1,38 +1,41 @@ +Description: Ensure that all Kubernetes API calls are logged using Amazon CloudTrail. ID: aws_enable_cloudtrail_logging_for_kubernetes_api_calls -Title: "Enable CloudTrail Logging for Kubernetes API Calls" -Description: "Ensure that all Kubernetes API calls are logged using Amazon CloudTrail." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_account + - aws_cloudtrail_trail + Parameters: [] + PrimaryTable: aws_account QueryToExecute: | - select - account_id as resource, + SELECT + account_id AS resource, og_account_id, og_resource_id, - case - when exists( - select 1 - from aws_cloudtrail_trail as ct - where ct.og_account_id = a.og_account_id and ct.is_logging = 'true' - ) then 'ok' - else 'alarm' - end as status, - case - when exists( - select 1 - from aws_cloudtrail_trail as ct - where ct.og_account_id = a.og_account_id and ct.is_logging = 'true' - ) then 'There are active trails' - else 'There are no active trails' - end as reason, + CASE + WHEN EXISTS ( + SELECT 1 + FROM aws_cloudtrail_trail AS ct + WHERE ct.og_account_id = a.og_account_id + AND ct.is_logging = 'true' + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM aws_cloudtrail_trail AS ct + WHERE ct.og_account_id = a.og_account_id + AND ct.is_logging = 'true' + ) THEN 'There are active trails' + ELSE 'There are no active trails' + END AS reason, region, account_id - from - aws_account as a - PrimaryTable: aws_account - ListOfTables: - - aws_account - - aws_cloudtrail_trail - Parameters: [] + FROM + aws_account AS a Severity: high Tags: platform_score_cloud_service_name: @@ -43,5 +46,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Enable CloudTrail Logging for Kubernetes API Calls \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_enable_envelope_encryption_for_eks_kubernetes_secrets.yaml b/compliance/controls/baseline/aws/eks/aws_enable_envelope_encryption_for_eks_kubernetes_secrets.yaml old mode 100755 new mode 100644 index 5223d4444..4041e4c45 --- a/compliance/controls/baseline/aws/eks/aws_enable_envelope_encryption_for_eks_kubernetes_secrets.yaml +++ b/compliance/controls/baseline/aws/eks/aws_enable_envelope_encryption_for_eks_kubernetes_secrets.yaml @@ -1,37 +1,38 @@ +Description: Ensure that envelope encryption of Kubernetes secrets using Amazon KMS is enabled. ID: aws_enable_envelope_encryption_for_eks_kubernetes_secrets -Title: "Enable Envelope Encryption for EKS Kubernetes Secrets" -Description: "Ensure that envelope encryption of Kubernetes secrets using Amazon KMS is enabled." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_eks_cluster + Parameters: [] + PrimaryTable: aws_eks_cluster QueryToExecute: | - select - name as resource, + SELECT + name AS resource, og_account_id, og_resource_id, - case - when exists ( - select 1 - from jsonb_array_elements(encryption_config) as ec - where ec -> 'Provider' ->> 'KeyArn' is not null - ) then 'ok' - else 'alarm' - end as status, - case - when exists ( - select 1 - from jsonb_array_elements(encryption_config) as ec - where ec -> 'Provider' ->> 'KeyArn' is not null - ) then name || ' KMS Customer Master Keys (CMKs) is not enabled' - else name || ' KMS Customer Master Keys (CMKs) is enabled' - end as reason, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(encryption_config) AS ec + WHERE ec -> 'Provider' ->> 'KeyArn' IS NOT NULL + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(encryption_config) AS ec + WHERE ec -> 'Provider' ->> 'KeyArn' IS NOT NULL + ) THEN name || ' KMS Customer Master Keys (CMKs) is not enabled' + ELSE name || ' KMS Customer Master Keys (CMKs) is enabled' + END AS reason, region, account_id - from + FROM aws_eks_cluster; - PrimaryTable: aws_eks_cluster - ListOfTables: - - aws_eks_cluster - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -42,5 +43,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Enable Envelope Encryption for EKS Kubernetes Secrets \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_kubernetes_cluster_logging.yaml b/compliance/controls/baseline/aws/eks/aws_kubernetes_cluster_logging.yaml old mode 100755 new mode 100644 index c4420765a..7c8004b61 --- a/compliance/controls/baseline/aws/eks/aws_kubernetes_cluster_logging.yaml +++ b/compliance/controls/baseline/aws/eks/aws_kubernetes_cluster_logging.yaml @@ -1,37 +1,38 @@ +Description: Ensure that EKS control plane logging is enabled for your Amazon EKS clusters. ID: aws_kubernetes_cluster_logging -Title: "Kubernetes Cluster Logging" -Description: "Ensure that EKS control plane logging is enabled for your Amazon EKS clusters." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_eks_cluster + Parameters: [] + PrimaryTable: aws_eks_cluster QueryToExecute: | - select - name as resource, + SELECT + name AS resource, og_account_id, og_resource_id, - case - when exists( - select 1 - from jsonb_array_elements(logging -> 'ClusterLogging') as cl - where cl ->> 'Enabled' = 'true' - ) then 'ok' - else 'alarm' - end as status, - case - when exists( - select 1 - from jsonb_array_elements(logging -> 'ClusterLogging') as cl - where cl ->> 'Enabled' = 'true' - ) then name || ' EKS control plane logging is enabled' - else name || ' EKS control plane logging is not enabled' - end as reason, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(logging -> 'ClusterLogging') AS cl + WHERE cl ->> 'Enabled' = 'true' + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(logging -> 'ClusterLogging') AS cl + WHERE cl ->> 'Enabled' = 'true' + ) THEN name || ' EKS control plane logging is enabled' + ELSE name || ' EKS control plane logging is not enabled' + END AS reason, region, account_id - from + FROM aws_eks_cluster; - PrimaryTable: aws_eks_cluster - ListOfTables: - - aws_eks_cluster - Parameters: [] Severity: low Tags: platform_score_cloud_service_name: @@ -42,5 +43,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Kubernetes Cluster Logging \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_kubernetes_cluster_version.yaml b/compliance/controls/baseline/aws/eks/aws_kubernetes_cluster_version.yaml old mode 100755 new mode 100644 index 4214be7f1..9eeceb8f7 --- a/compliance/controls/baseline/aws/eks/aws_kubernetes_cluster_version.yaml +++ b/compliance/controls/baseline/aws/eks/aws_kubernetes_cluster_version.yaml @@ -1,32 +1,32 @@ +Description: Ensure that the latest version of Kubernetes is installed on your Amazon EKS clusters. ID: aws_kubernetes_cluster_version -Title: "Kubernetes Cluster Version" -Description: "Ensure that the latest version of Kubernetes is installed on your Amazon EKS clusters." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |+ - select - arn as resource, - og_account_id, - og_resource_id, - case - when (version) :: decimal >= '{{.awsEksClusterLatestVersion}}' :: decimal then 'ok' - else 'alarm' - end as status, - case - when (version) :: decimal >= '{{.awsEksClusterLatestVersion}}' :: decimal then title || ' runs on a supported kubernetes version.' - else title || ' is running on version ' || version || ' which is not supported. supported versions are >= ' || '{{.awsEksClusterLatestVersion}}' :: decimal - end as reason, - region, - account_id - from - aws_eks_cluster; - - PrimaryTable: aws_eks_cluster ListOfTables: - aws_eks_cluster Parameters: - Key: awsEksClusterLatestVersion Required: true + PrimaryTable: aws_eks_cluster + QueryToExecute: | + SELECT + arn AS resource, + og_account_id, + og_resource_id, + CASE + WHEN (version)::decimal >= '{{.awsEksClusterLatestVersion}}'::decimal THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (version)::decimal >= '{{.awsEksClusterLatestVersion}}'::decimal THEN title || ' runs on a supported kubernetes version.' + ELSE title || ' is running on version ' || version || ' which is not supported. supported versions are >= ' || '{{.awsEksClusterLatestVersion}}'::decimal + END AS reason, + region, + account_id + FROM + aws_eks_cluster; Severity: low Tags: platform_score_cloud_service_name: @@ -37,5 +37,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Kubernetes Cluster Version \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_access_amazon_ecr_repositories.yaml b/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_access_amazon_ecr_repositories.yaml old mode 100755 new mode 100644 index b0e24836b..6edbc9986 --- a/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_access_amazon_ecr_repositories.yaml +++ b/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_access_amazon_ecr_repositories.yaml @@ -1,31 +1,32 @@ +Description: Ensure that EKS cluster node groups implement the "AmazonEC2ContainerRegistryReadOnly" managed policy. ID: aws_use_aws_managed_policy_to_access_amazon_ecr_repositories -Title: "Use AWS-managed policy to access Amazon ECR Repositories" -Description: "Ensure that EKS cluster node groups implement the \"AmazonEC2ContainerRegistryReadOnly\" managed policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_eks_node_group + - aws_iam_role + Parameters: [] + PrimaryTable: aws_eks_node_group QueryToExecute: | - select - ng.nodegroup_name as resource, + SELECT + ng.nodegroup_name AS resource, ng.og_account_id, ng.og_resource_id, - case - when attached_policy_arns::text like '%arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly%' then 'ok' - else 'alarm' - end as status, - case - when attached_policy_arns::text like '%arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly%' then 'node group policies contains AmazonEC2ContainerRegistryReadOnly' - else 'node group policies does not contain AmazonEC2ContainerRegistryReadOnly' - end as reason, + CASE + WHEN attached_policy_arns::text LIKE '%arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN attached_policy_arns::text LIKE '%arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly%' THEN 'node group policies contains AmazonEC2ContainerRegistryReadOnly' + ELSE 'node group policies does not contain AmazonEC2ContainerRegistryReadOnly' + END AS reason, ng.region, ng.account_id - from - aws_eks_node_group as ng - left join aws_iam_role as r on r.arn = ng.node_role - PrimaryTable: aws_eks_node_group - ListOfTables: - - aws_eks_node_group - - aws_iam_role - Parameters: [] + FROM + aws_eks_node_group AS ng + LEFT JOIN aws_iam_role AS r ON r.arn = ng.node_role Severity: high Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Use AWS-managed policy to access Amazon ECR Repositories \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_manage_aws_resources.yaml b/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_manage_aws_resources.yaml old mode 100755 new mode 100644 index 82af4081d..e7c567491 --- a/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_manage_aws_resources.yaml +++ b/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_manage_aws_resources.yaml @@ -1,31 +1,32 @@ +Description: Ensure that Amazon EKS clusters implement the "AmazonEKSClusterPolicy" managed policy. ID: aws_use_aws_managed_policy_to_manage_aws_resources -Title: "Use AWS-managed policy to manage AWS resources" -Description: "Ensure that Amazon EKS clusters implement the \"AmazonEKSClusterPolicy\" managed policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_eks_node_group + - aws_iam_role + Parameters: [] + PrimaryTable: aws_eks_node_group QueryToExecute: | - select - ng.nodegroup_name as resource, + SELECT + ng.nodegroup_name AS resource, ng.og_account_id, ng.og_resource_id, - case - when attached_policy_arns::text like '%arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly%' then 'ok' - else 'alarm' - end as status, - case - when attached_policy_arns::text like '%arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly%' then 'node group policies contains AmazonEC2ContainerRegistryReadOnly' - else 'node group policies does not contain AmazonEC2ContainerRegistryReadOnly' - end as reason, + CASE + WHEN attached_policy_arns::text LIKE '%arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN attached_policy_arns::text LIKE '%arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly%' THEN 'node group policies contain AmazonEC2ContainerRegistryReadOnly' + ELSE 'node group policies do not contain AmazonEC2ContainerRegistryReadOnly' + END AS reason, ng.region, ng.account_id - from - aws_eks_node_group as ng - left join aws_iam_role as r on r.arn = ng.node_role - PrimaryTable: aws_eks_node_group - ListOfTables: - - aws_eks_node_group - - aws_iam_role - Parameters: [] + FROM + aws_eks_node_group AS ng + LEFT JOIN aws_iam_role AS r ON r.arn = ng.node_role Severity: high Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Use AWS-managed policy to manage AWS resources \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_manage_networking_resources.yaml b/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_manage_networking_resources.yaml old mode 100755 new mode 100644 index 123be7dbf..9e908c84a --- a/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_manage_networking_resources.yaml +++ b/compliance/controls/baseline/aws/eks/aws_use_aws_managed_policy_to_manage_networking_resources.yaml @@ -1,31 +1,33 @@ +Description: Ensure that EKS cluster node groups implement the "AmazonEKS_CNI_Policy" managed policy. ID: aws_use_aws_managed_policy_to_manage_networking_resources -Title: "Use AWS-managed policy to Manage Networking Resources" -Description: "Ensure that EKS cluster node groups implement the \"AmazonEKS_CNI_Policy\" managed policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_eks_node_group + - aws_iam_role + Parameters: [] + PrimaryTable: aws_eks_node_group QueryToExecute: | - select - ng.nodegroup_name as resource, + SELECT + ng.nodegroup_name AS resource, ng.og_account_id, ng.og_resource_id, - case - when attached_policy_arns::text like '%arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy%' then 'ok' - else 'alarm' - end as status, - case - when attached_policy_arns::text like '%arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy%' then 'node group policies contains AmazonEKS_CNI_Policy' - else 'node group policies does not contain AmazonEKS_CNI_Policy' - end as reason, + CASE + WHEN attached_policy_arns::TEXT LIKE '%arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN attached_policy_arns::TEXT LIKE '%arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy%' THEN 'node group policies contains AmazonEKS_CNI_Policy' + ELSE 'node group policies does not contain AmazonEKS_CNI_Policy' + END AS reason, ng.region, ng.account_id - from - aws_eks_node_group as ng - left join aws_iam_role as r on r.arn = ng.node_role - PrimaryTable: aws_eks_node_group - ListOfTables: - - aws_eks_node_group - - aws_iam_role - Parameters: [] + FROM + aws_eks_node_group AS ng + LEFT JOIN aws_iam_role AS r + ON r.arn = ng.node_role Severity: high Tags: platform_score_cloud_service_name: @@ -36,5 +38,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Use AWS-managed policy to Manage Networking Resources \ No newline at end of file diff --git a/compliance/controls/baseline/aws/eks/aws_use_oidc_provider_for_authenticating_kubernetes_api_calls.yaml b/compliance/controls/baseline/aws/eks/aws_use_oidc_provider_for_authenticating_kubernetes_api_calls.yaml old mode 100755 new mode 100644 index c5eb1a69d..8c99ee550 --- a/compliance/controls/baseline/aws/eks/aws_use_oidc_provider_for_authenticating_kubernetes_api_calls.yaml +++ b/compliance/controls/baseline/aws/eks/aws_use_oidc_provider_for_authenticating_kubernetes_api_calls.yaml @@ -1,31 +1,33 @@ +Description: Ensure that Amazon EKS clusters are using an OpenID Connect (OIDC) provider. ID: aws_use_oidc_provider_for_authenticating_kubernetes_api_calls -Title: "Use OIDC Provider for Authenticating Kubernetes API Calls" -Description: "Ensure that Amazon EKS clusters are using an OpenID Connect (OIDC) provider." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_eks_cluster + - aws_iam_open_id_connect_provider + Parameters: [] + PrimaryTable: aws_eks_cluster QueryToExecute: | - select - c.name as resource, + SELECT + c.name AS resource, c.og_account_id, c.og_resource_id, - case - when oidc.url is null then 'alarm' - else 'ok' - end as status, - case - when oidc.url is null then 'Amazon EKS cluster is not using an OIDC provider for authenticating Kubernetes API calls.' - else 'Amazon EKS cluster is using an OIDC provider for authenticating Kubernetes API calls.' - end as reason, + CASE + WHEN oidc.url IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN oidc.url IS NULL THEN 'Amazon EKS cluster is not using an OIDC provider for authenticating Kubernetes API calls.' + ELSE 'Amazon EKS cluster is using an OIDC provider for authenticating Kubernetes API calls.' + END AS reason, c.region, c.account_id - from - aws_eks_cluster as c - left join aws_iam_open_id_connect_provider as oidc on 'https://' || oidc.url = c.identity -> 'Oidc' ->> 'Issuer' - PrimaryTable: aws_eks_cluster - ListOfTables: - - aws_eks_cluster - - aws_iam_open_id_connect_provider - Parameters: [] + FROM + aws_eks_cluster AS c + LEFT JOIN aws_iam_open_id_connect_provider AS oidc + ON 'https://' || oidc.url = c.identity -> 'Oidc' ->> 'Issuer' Severity: high Tags: platform_score_cloud_service_name: @@ -36,5 +38,4 @@ Tags: - AWS Elastic Kubernetes Service (EKS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Use OIDC Provider for Authenticating Kubernetes API Calls \ No newline at end of file diff --git a/compliance/controls/baseline/aws/fsx/aws_use_kms_customer_master_keys_for_fsx_windows_file_server_file_systems.yaml b/compliance/controls/baseline/aws/fsx/aws_use_kms_customer_master_keys_for_fsx_windows_file_server_file_systems.yaml old mode 100755 new mode 100644 index 4f172ce79..251f9c98e --- a/compliance/controls/baseline/aws/fsx/aws_use_kms_customer_master_keys_for_fsx_windows_file_server_file_systems.yaml +++ b/compliance/controls/baseline/aws/fsx/aws_use_kms_customer_master_keys_for_fsx_windows_file_server_file_systems.yaml @@ -1,33 +1,34 @@ +Description: Ensure AWS FSx for Windows File Server file systems data is encrypted using AWS KMS CMKs. ID: aws_use_kms_customer_master_keys_for_fsx_windows_file_server_file_systems -Title: "Use KMS Customer Master Keys for FSx Windows File Server File Systems" -Description: "Ensure AWS FSx for Windows File Server file systems data is encrypted using AWS KMS CMKs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - file_system_id as resource, - v.og_resource_id, - v.og_account_id, - case - when kms_key_id is null then 'alarm' - when k.key_manager = 'CUSTOMER' then 'ok' - else 'alarm' - end as status, - case - when kms_key_id is null then file_system_id || ' is not using a master key' - when k.key_manager = 'CUSTOMER' then file_system_id || ' is using a customer master key' - else file_system_id || ' is using a AWS-managed master key' - end as reason, - V.region, - V.account_id - from - aws_fsx_file_system as v - left join aws_kms_key as k on v.kms_key_id = k.arn - PrimaryTable: aws_fsx_file_system ListOfTables: - aws_fsx_file_system - aws_kms_key Parameters: [] + PrimaryTable: aws_fsx_file_system + QueryToExecute: | + SELECT + file_system_id AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN kms_key_id IS NULL THEN 'alarm' + WHEN k.key_manager = 'CUSTOMER' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN kms_key_id IS NULL THEN file_system_id || ' is not using a master key' + WHEN k.key_manager = 'CUSTOMER' THEN file_system_id || ' is using a customer master key' + ELSE file_system_id || ' is using an AWS-managed master key' + END AS reason, + v.region, + v.account_id + FROM + aws_fsx_file_system AS v + LEFT JOIN aws_kms_key AS k ON v.kms_key_id = k.arn Severity: medium Tags: platform_score_cloud_service_name: @@ -38,5 +39,4 @@ Tags: - AWS Elastic Block Store (EBS) score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: Use KMS Customer Master Keys for FSx Windows File Server File Systems \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_configure_http_desync_mitigation_mode_for_application_load_balancers.yaml b/compliance/controls/baseline/aws/load_balancer/aws_configure_http_desync_mitigation_mode_for_application_load_balancers.yaml old mode 100755 new mode 100644 index bc68e8297..f60846481 --- a/compliance/controls/baseline/aws/load_balancer/aws_configure_http_desync_mitigation_mode_for_application_load_balancers.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_configure_http_desync_mitigation_mode_for_application_load_balancers.yaml @@ -1,38 +1,40 @@ +Description: Ensure that the suitable Desync Mitigation mode is configured for your Application Load Balancers. ID: aws_configure_http_desync_mitigation_mode_for_application_load_balancers -Title: "Configure HTTP Desync Mitigation Mode for Application Load Balancers" -Description: "Ensure that the suitable Desync Mitigation mode is configured for your Application Load Balancers." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_application_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer QueryToExecute: | - with app_lb_desync_mitigation_mode as ( - select + WITH app_lb_desync_mitigation_mode AS ( + SELECT arn, l ->> 'Key', - l ->> 'Value' as v - from + l ->> 'Value' AS v + FROM aws_ec2_application_load_balancer, - jsonb_array_elements(load_balancer_attributes) as l - where + jsonb_array_elements(load_balancer_attributes) AS l + WHERE l ->> 'Key' = 'routing.http.desync_mitigation_mode' ) - select - a.arn as resource, + SELECT + a.arn AS resource, og_resource_id, og_account_id, - case - when m.v = any(array [ 'defensive', 'strictest' ]) then 'ok' - else 'alarm' - end as status, - title || ' has ' || m.v || ' desync mitigation mode.' as reason, + CASE + WHEN m.v = ANY(ARRAY ['defensive', 'strictest']) THEN 'ok' + ELSE 'alarm' + END AS status, + title || ' has ' || m.v || ' desync mitigation mode.' AS reason, region, account_id - from - aws_ec2_application_load_balancer as a - left join app_lb_desync_mitigation_mode as m on a.arn = m.arn; - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - Parameters: [] + FROM + aws_ec2_application_load_balancer AS a + LEFT JOIN app_lb_desync_mitigation_mode AS m + ON a.arn = m.arn; Severity: medium Tags: platform_score_cloud_service_name: @@ -43,5 +45,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Configure HTTP Desync Mitigation Mode for Application Load Balancers \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_configure_multiple_availability_zones_for_load_balancers.yaml b/compliance/controls/baseline/aws/load_balancer/aws_configure_multiple_availability_zones_for_load_balancers.yaml old mode 100755 new mode 100644 index de189257a..bc22276c9 --- a/compliance/controls/baseline/aws/load_balancer/aws_configure_multiple_availability_zones_for_load_balancers.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_configure_multiple_availability_zones_for_load_balancers.yaml @@ -1,56 +1,57 @@ +Description: Ensure that Amazon Gateway Load Balancers are using Multi-AZ configurations. ID: aws_configure_multiple_availability_zones_for_load_balancers -Title: "Configure Multiple Availability Zones for Load Balancers" -Description: "Ensure that Amazon Gateway Load Balancers are using Multi-AZ configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_application_load_balancer + - aws_ec2_gateway_load_balancer + - aws_ec2_network_load_balancer + Parameters: [] + PrimaryTable: "" QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when jsonb_array_length(availability_zones) < 2 then 'alarm' - else 'ok' - end as status, - title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason, region, account_id - from + FROM aws_ec2_application_load_balancer - union - select - arn as resource, + UNION + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when jsonb_array_length(availability_zones) < 2 then 'alarm' - else 'ok' - end as status, - title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason, region, account_id - from + FROM aws_ec2_network_load_balancer - union - select - arn as resource, + UNION + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when jsonb_array_length(availability_zones) < 2 then 'alarm' - else 'ok' - end as status, - title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason, region, account_id - from + FROM aws_ec2_gateway_load_balancer; - PrimaryTable: "" - ListOfTables: - - aws_ec2_application_load_balancer - - aws_ec2_gateway_load_balancer - - aws_ec2_network_load_balancer - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -61,5 +62,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Configure Multiple Availability Zones for Load Balancers \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elb_access_log.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elb_access_log.yaml old mode 100755 new mode 100644 index f1c1bd504..77ef1e864 --- a/compliance/controls/baseline/aws/load_balancer/aws_elb_access_log.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elb_access_log.yaml @@ -1,34 +1,34 @@ +Description: Ensure ELB access logging is enabled for security, troubleshooting, and statistical analysis purposes ID: aws_elb_access_log -Title: "ELB Access Log" -Description: "Ensure ELB access logging is enabled for security, troubleshooting, and statistical analysis purposes" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_classic_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer QueryToExecute: | - select - a.arn as resource, + SELECT + a.arn AS resource, a.og_account_id, a.og_resource_id, - case - when og_description -> 'Attributes' -> 'AccessLog' ->> 'Enabled' = 'true' then 'ok' - else 'alarm' - end as status, - case - when og_description -> 'Attributes' -> 'AccessLog' ->> 'Enabled' = 'true' then a.title || ' Access Logging feature is enabled' - else a.title || ' Access Logging feature is not enabled' - end as reason, + CASE + WHEN og_description -> 'Attributes' -> 'AccessLog' ->> 'Enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN og_description -> 'Attributes' -> 'AccessLog' ->> 'Enabled' = 'true' THEN a.title || ' Access Logging feature is enabled' + ELSE a.title || ' Access Logging feature is not enabled' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_classic_load_balancer a - PrimaryTable: aws_ec2_classic_load_balancer - ListOfTables: - - aws_ec2_classic_load_balancer - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: - AWS Elastic Load Balancing (ELB) score_service_name: - AWS Elastic Load Balancing (ELB) -IntegrationType: - - aws_cloud_account +Title: ELB Access Log \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elb_connection_draining_enabled.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elb_connection_draining_enabled.yaml old mode 100755 new mode 100644 index a2b2e3b1a..9f2aa8212 --- a/compliance/controls/baseline/aws/load_balancer/aws_elb_connection_draining_enabled.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elb_connection_draining_enabled.yaml @@ -1,34 +1,34 @@ +Description: Ensure ELB access logging is enabled for security, troubleshooting, and statistical analysis purposes ID: aws_elb_connection_draining_enabled -Title: "ELB Connection Draining Enabled" -Description: "Ensure ELB access logging is enabled for security, troubleshooting, and statistical analysis purposes" +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_classic_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer QueryToExecute: | - select - a.arn as resource, + SELECT + a.arn AS resource, a.og_account_id, a.og_resource_id, - case - when og_description -> 'Attributes' -> 'ConnectionDraining' ->> 'Enabled' = 'true' then 'ok' - else 'alarm' - end as status, - case - when og_description -> 'Attributes' -> 'ConnectionDraining' ->> 'Enabled' = 'true' then a.title || ' Connection Draining feature is enabled' - else a.title || ' Connection Draining feature is not enabled' - end as reason, + CASE + WHEN og_description -> 'Attributes' -> 'ConnectionDraining' ->> 'Enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN og_description -> 'Attributes' -> 'ConnectionDraining' ->> 'Enabled' = 'true' THEN a.title || ' Connection Draining feature is enabled' + ELSE a.title || ' Connection Draining feature is not enabled' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_classic_load_balancer a - PrimaryTable: aws_ec2_classic_load_balancer - ListOfTables: - - aws_ec2_classic_load_balancer - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: - AWS Elastic Load Balancing (ELB) score_service_name: - AWS Elastic Load Balancing (ELB) -IntegrationType: - - aws_cloud_account +Title: ELB Connection Draining Enabled \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elb_cross_zone_load_balancing_enabled.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elb_cross_zone_load_balancing_enabled.yaml old mode 100755 new mode 100644 index 80245110d..8188b2ac6 --- a/compliance/controls/baseline/aws/load_balancer/aws_elb_cross_zone_load_balancing_enabled.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elb_cross_zone_load_balancing_enabled.yaml @@ -1,34 +1,34 @@ +Description: Ensure Cross-Zone Load Balancing is enabled for all load balancers. Also select at least two subnets in different availability zones to provide higher availability. ID: aws_elb_cross_zone_load_balancing_enabled -Title: "ELB Cross-Zone Load Balancing Enabled" -Description: "Ensure Cross-Zone Load Balancing is enabled for all load balancers. Also select at least two subnets in different availability zones to provide higher availability." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_classic_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer QueryToExecute: | - select - a.arn as resource, + SELECT + a.arn AS resource, a.og_account_id, a.og_resource_id, - case - when og_description -> 'Attributes' -> 'CrossZoneLoadBalancing' ->> 'Enabled' = 'true' then 'ok' - else 'alarm' - end as status, - case - when og_description -> 'Attributes' -> 'CrossZoneLoadBalancing' ->> 'Enabled' = 'true' then a.title || ' Cross-Zone Load Balancing feature is enabled' - else a.title || ' Cross-Zone Load Balancing feature is not enabled' - end as reason, + CASE + WHEN og_description -> 'Attributes' -> 'CrossZoneLoadBalancing' ->> 'Enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN og_description -> 'Attributes' -> 'CrossZoneLoadBalancing' ->> 'Enabled' = 'true' THEN a.title || ' Cross-Zone Load Balancing feature is enabled' + ELSE a.title || ' Cross-Zone Load Balancing feature is not enabled' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_classic_load_balancer a - PrimaryTable: aws_ec2_classic_load_balancer - ListOfTables: - - aws_ec2_classic_load_balancer - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - AWS Elastic Load Balancing (ELB) score_service_name: - AWS Elastic Load Balancing (ELB) -IntegrationType: - - aws_cloud_account +Title: ELB Cross-Zone Load Balancing Enabled \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elb_insecure_ssl_protocols.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elb_insecure_ssl_protocols.yaml old mode 100755 new mode 100644 index 02fec71e7..4def0e5b7 --- a/compliance/controls/baseline/aws/load_balancer/aws_elb_insecure_ssl_protocols.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elb_insecure_ssl_protocols.yaml @@ -1,42 +1,43 @@ +Description: Ensure ELBs don't use insecure SSL protocols. ID: aws_elb_insecure_ssl_protocols -Title: "ELB Insecure SSL Protocols" -Description: "Ensure ELBs don't use insecure SSL protocols." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_classic_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer QueryToExecute: | - with detailed_classic_listeners as ( - select + WITH detailed_classic_listeners AS ( + SELECT name - from + FROM aws_ec2_classic_load_balancer, - jsonb_array_elements(listener_descriptions) as listener_description - where - listener_description -> 'Listener' ->> 'Protocol' in ('HTTPS', 'SSL', 'TLS') - and listener_description -> 'Listener' ->> 'SSLCertificateId' like 'arn:aws:acm%' + jsonb_array_elements(listener_descriptions) AS listener_description + WHERE + listener_description -> 'Listener' ->> 'Protocol' IN ('HTTPS', 'SSL', 'TLS') + AND listener_description -> 'Listener' ->> 'SSLCertificateId' LIKE 'arn:aws:acm%' ) - select - 'arn:' || a.partition || ':elasticloadbalancing:' || a.region || ':' || a.account_id || ':loadbalancer/' || a.name as resource, + SELECT + 'arn:' || a.partition || ':elasticloadbalancing:' || a.region || ':' || a.account_id || ':loadbalancer/' || a.name AS resource, og_account_id, og_resource_id, - case - when a.listener_descriptions is null then 'skip' - when b.name is not null then 'alarm' - else 'ok' - end as status, - case - when a.listener_descriptions is null then a.title || ' has no listener.' - when b.name is not null then a.title || ' does not use certificates provided by ACM.' - else a.title || ' uses certificates provided by ACM.' - end as reason, + CASE + WHEN a.listener_descriptions IS NULL THEN 'skip' + WHEN b.name IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.listener_descriptions IS NULL THEN a.title || ' has no listener.' + WHEN b.name IS NOT NULL THEN a.title || ' does not use certificates provided by ACM.' + ELSE a.title || ' uses certificates provided by ACM.' + END AS reason, region, account_id - from - aws_ec2_classic_load_balancer as a - left join detailed_classic_listeners as b on a.name = b.name; - PrimaryTable: aws_ec2_classic_load_balancer - ListOfTables: - - aws_ec2_classic_load_balancer - Parameters: [] + FROM + aws_ec2_classic_load_balancer AS a + LEFT JOIN detailed_classic_listeners AS b ON a.name = b.name; Severity: medium Tags: platform_score_cloud_service_name: @@ -47,5 +48,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Unencrypted Traffic -IntegrationType: - - aws_cloud_account +Title: ELB Insecure SSL Protocols \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_access_log.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_access_log.yaml old mode 100755 new mode 100644 index 351af6cdf..ad27b81e8 --- a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_access_log.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_access_log.yaml @@ -1,37 +1,37 @@ +Description: Ensure that Amazon ALBs have Access Logging feature enabled for security, troubleshooting and statistical analysis purposes. ID: aws_elbv2_access_log -Title: "ELBv2 Access Log" -Description: "Ensure that Amazon ALBs have Access Logging feature enabled for security, troubleshooting and statistical analysis purposes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_application_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer QueryToExecute: | - select - a.arn as resource, + SELECT + a.arn AS resource, a.og_account_id, a.og_resource_id, - case - when lb ->> 'Value' = 'false' then 'alarm' - else 'ok' - end as status, - case - when lb ->> 'Value' = 'false' then a.title || ' deletion protection is not enabled.' - else a.title || ' deletion protection is enabled.' - end as reason, + CASE + WHEN lb ->> 'Value' = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN lb ->> 'Value' = 'false' THEN a.title || ' deletion protection is not enabled.' + ELSE a.title || ' deletion protection is enabled.' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_application_load_balancer a - cross join jsonb_array_elements(load_balancer_attributes) as lb - where + CROSS JOIN jsonb_array_elements(load_balancer_attributes) AS lb + WHERE lb ->> 'Key' = 'access_logs.s3.enabled' - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: - AWS Elastic Load Balancing V2 (ELBv2) score_service_name: - AWS Elastic Load Balancing V2 (ELBv2) -IntegrationType: - - aws_cloud_account +Title: ELBv2 Access Log \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_listener_security.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_listener_security.yaml old mode 100755 new mode 100644 index f297dcc46..caec68741 --- a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_listener_security.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_listener_security.yaml @@ -1,14 +1,42 @@ +Description: Ensure ELBv2 ALBs are using a secure protocol. ID: aws_elbv2_alb_listener_security -Title: "ELBv2 ALB Listener Security" -Description: "Ensure ELBv2 ALBs are using a secure protocol." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n al.arn AS resource,\n al.og_resource_id,\n al.og_account_id,\n CASE\n WHEN STRING_AGG(ll.protocol, ',') ILIKE '%HTTPS%' THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN STRING_AGG(ll.protocol, ',') ILIKE '%HTTPS%' THEN 'alb is using a secure protocol'\n ELSE 'alb is not using a secure protocol'\n END AS reason,\n al.region,\n al.account_id\nFROM \n aws_ec2_application_load_balancer al\nLEFT JOIN aws_ec2_load_balancer_listener ll ON al.arn = ll.load_balancer_arn\nGROUP BY \n al.arn, al.og_resource_id, al.og_account_id, al.title, al.region, al.account_id;\n" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer - aws_ec2_load_balancer_listener Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + SELECT + al.arn AS resource, + al.og_resource_id, + al.og_account_id, + CASE + WHEN STRING_AGG(ll.protocol, ',') ILIKE '%HTTPS%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN STRING_AGG(ll.protocol, ',') ILIKE '%HTTPS%' THEN 'alb is using a secure protocol' + ELSE 'alb is not using a secure protocol' + END AS reason, + al.region, + al.account_id + FROM + aws_ec2_application_load_balancer al + LEFT JOIN + aws_ec2_load_balancer_listener ll + ON + al.arn = ll.load_balancer_arn + GROUP BY + al.arn, + al.og_resource_id, + al.og_account_id, + al.title, + al.region, + al.account_id; Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +47,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Unencrypted Traffic -IntegrationType: - - aws_cloud_account +Title: ELBv2 ALB Listener Security \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_minimum_number_of_ec2_target_instances.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_minimum_number_of_ec2_target_instances.yaml old mode 100755 new mode 100644 index 1b4204871..653f39385 --- a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_minimum_number_of_ec2_target_instances.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_minimum_number_of_ec2_target_instances.yaml @@ -1,14 +1,43 @@ +Description: Ensure there is a minimum number of two healthy target instances associated with each AWS ELBv2 application load balancer. ID: aws_elbv2_alb_minimum_number_of_ec2_target_instances -Title: "ELBv2 ALB Minimum Number of EC2 Target Instances" -Description: "Ensure there is a minimum number of two healthy target instances associated with each AWS ELBv2 application load balancer." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with target_resource as (\nselect \n load_balancer_arn,\n count(*) as c \nfrom \n aws_ec2_target_group, \n jsonb_array_elements_text(load_balancer_arns) as load_balancer_arn \ngroup by load_balancer_arn\n)\nselect\n a.arn as resource,\n a.og_account_id,\n a.og_resource_id,\n case\n when b.load_balancer_arn is null or b.c < 2 then 'alarm'\n else 'ok'\n end as status,\n case\n when b.load_balancer_arn is null or b.c < 2 then a.title || ' is not using a fault-tolerant configuration.'\n else a.title || ' is using a fault-tolerant configuration.'\n end as reason,\n a.region,\n a.account_id\nfrom\n aws_ec2_application_load_balancer a\n left join target_resource b on a.arn = b.load_balancer_arn;\n" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer - aws_ec2_target_group Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + WITH target_resource AS ( + SELECT + load_balancer_arn, + COUNT(*) AS c + FROM + aws_ec2_target_group, + jsonb_array_elements_text(load_balancer_arns) AS load_balancer_arn + GROUP BY + load_balancer_arn + ) + SELECT + a.arn AS resource, + a.og_account_id, + a.og_resource_id, + CASE + WHEN b.load_balancer_arn IS NULL OR b.c < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.load_balancer_arn IS NULL OR b.c < 2 THEN a.title || ' is not using a fault-tolerant configuration.' + ELSE a.title || ' is using a fault-tolerant configuration.' + END AS reason, + a.region, + a.account_id + FROM + aws_ec2_application_load_balancer a + LEFT JOIN target_resource b + ON a.arn = b.load_balancer_arn; Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +48,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: ELBv2 ALB Minimum Number of EC2 Target Instances \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_security_group.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_security_group.yaml old mode 100755 new mode 100644 index 1df233bc9..dbb92a041 --- a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_security_group.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_security_group.yaml @@ -1,15 +1,56 @@ +Description: Ensure ELBv2 load balancers have secure and valid security groups. ID: aws_elbv2_alb_security_group -Title: "ELBv2 ALB Security Group" -Description: "Ensure ELBv2 load balancers have secure and valid security groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "WITH sg AS (\n SELECT\n group_id,\n group_name,\n ARRAY_AGG('(' || (p ->> 'ToPort') || ',' || lower(p ->> 'IpProtocol') || ')') AS ports_and_protocols\n FROM\n aws_vpc_security_group,\n jsonb_array_elements(ip_permissions) as p\n GROUP BY\n group_id, group_name\n), lbl AS (\n SELECT \n load_balancer_arn,\n ARRAY_AGG('(' || port || ',' || lower(protocol) || ')') AS ports_and_protocols\n FROM \n aws_ec2_load_balancer_listener\n GROUP BY \n load_balancer_arn\n)\nSELECT\n al.name as resource,\n al.og_account_id,\n al.og_resource_id,\n sg.ports_and_protocols,\n lbl.ports_and_protocols,\n CASE\n WHEN sg.ports_and_protocols <@ lbl.ports_and_protocols THEN 'ok'\n ELSE 'alarm'\n END as status,\n CASE\n WHEN sg.ports_and_protocols <@ lbl.ports_and_protocols THEN al.name || ' is secure'\n ELSE al.name || ' is not secure'\n END as reason,\n al.region,\n al.account_id\nFROM\n aws_ec2_application_load_balancer as al\n CROSS JOIN LATERAL jsonb_array_elements_text(al.security_groups) as sgid\n LEFT JOIN sg ON sgid = sg.group_id\n LEFT JOIN lbl ON al.arn = lbl.load_balancer_arn;\n" - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer - aws_ec2_load_balancer_listener - aws_vpc_security_group Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + WITH sg AS ( + SELECT + group_id, + group_name, + ARRAY_AGG('(' || (p ->> 'ToPort') || ',' || LOWER(p ->> 'IpProtocol') || ')') AS ports_and_protocols + FROM + aws_vpc_security_group, + JSONB_ARRAY_ELEMENTS(ip_permissions) AS p + GROUP BY + group_id, group_name + ), lbl AS ( + SELECT + load_balancer_arn, + ARRAY_AGG('(' || port || ',' || LOWER(protocol) || ')') AS ports_and_protocols + FROM + aws_ec2_load_balancer_listener + GROUP BY + load_balancer_arn + ) + SELECT + al.name AS resource, + al.og_account_id, + al.og_resource_id, + sg.ports_and_protocols, + lbl.ports_and_protocols, + CASE + WHEN sg.ports_and_protocols <@ lbl.ports_and_protocols THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sg.ports_and_protocols <@ lbl.ports_and_protocols THEN al.name || ' is secure' + ELSE al.name || ' is not secure' + END AS reason, + al.region, + al.account_id + FROM + aws_ec2_application_load_balancer AS al + CROSS JOIN LATERAL JSONB_ARRAY_ELEMENTS_TEXT(al.security_groups) AS sgid + LEFT JOIN sg ON sgid = sg.group_id + LEFT JOIN lbl ON al.arn = lbl.load_balancer_arn Severity: high Tags: platform_score_cloud_service_name: @@ -20,5 +61,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: ELBv2 ALB Security Group \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_security_policy.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_security_policy.yaml old mode 100755 new mode 100644 index 0d101f69b..7f0e8f5fe --- a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_security_policy.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_alb_security_policy.yaml @@ -1,38 +1,39 @@ +Description: Ensure that Amazon ALBs are using the latest predefined security policy for their SSL negotiation configuration in order to follow security best practices and protect their front-end connections against SSL/TLS vulnerabilities. ID: aws_elbv2_alb_security_policy -Title: "ELBv2 ALB Security Policy" -Description: "Ensure that Amazon ALBs are using the latest predefined security policy for their SSL negotiation configuration in order to follow security best practices and protect their front-end connections against SSL/TLS vulnerabilities." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - a.arn as resource, - a.og_account_id, - a.og_resource_id, - case - when '{{.awsLatestPolicies}}' like '%' || li.ssl_policy || '%' then 'ok' - else 'alarm' - end as status, - case - when '{{.awsLatestPolicies}}' like '%' || li.ssl_policy || '%' then a.title || ' is using one of the latest security policies.' - else a.title || ' is not using one of the latest security policies.' - end as reason, - a.region, - a.account_id - from - aws_ec2_application_load_balancer a - left join aws_ec2_load_balancer_listener as li on li.load_balancer_arn = a.arn - PrimaryTable: aws_ec2_application_load_balancer ListOfTables: - aws_ec2_application_load_balancer - aws_ec2_load_balancer_listener Parameters: - Key: awsLatestPolicies Required: true + PrimaryTable: aws_ec2_application_load_balancer + QueryToExecute: | + SELECT + a.arn AS resource, + a.og_account_id, + a.og_resource_id, + CASE + WHEN '{{.awsLatestPolicies}}' LIKE '%' || li.ssl_policy || '%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN '{{.awsLatestPolicies}}' LIKE '%' || li.ssl_policy || '%' THEN a.title || ' is using one of the latest security policies.' + ELSE a.title || ' is not using one of the latest security policies.' + END AS reason, + a.region, + a.account_id + FROM + aws_ec2_application_load_balancer a + LEFT JOIN aws_ec2_load_balancer_listener AS li + ON li.load_balancer_arn = a.arn Severity: medium Tags: platform_score_cloud_service_name: - AWS Elastic Load Balancing V2 (ELBv2) score_service_name: - AWS Elastic Load Balancing V2 (ELBv2) -IntegrationType: - - aws_cloud_account +Title: ELBv2 ALB Security Policy \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_elastic_load_balancing_deletion_protection.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_elastic_load_balancing_deletion_protection.yaml old mode 100755 new mode 100644 index 93675548c..93622d61a --- a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_elastic_load_balancing_deletion_protection.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_elastic_load_balancing_deletion_protection.yaml @@ -1,41 +1,43 @@ +Description: Ensure ELBv2 Load Balancers have Deletion Protection feature enabled in order to protect them from being accidentally deleted. ID: aws_elbv2_elastic_load_balancing_deletion_protection -Title: "ELBv2 Elastic Load Balancing Deletion Protection" -Description: "Ensure ELBv2 Load Balancers have Deletion Protection feature enabled in order to protect them from being accidentally deleted." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_application_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer QueryToExecute: | - with app_lb_desync_mitigation_mode as ( - select + WITH app_lb_desync_mitigation_mode AS ( + SELECT arn, l ->> 'Key', - l ->> 'Value' as v - from + l ->> 'Value' AS v + FROM aws_ec2_application_load_balancer, - jsonb_array_elements(load_balancer_attributes) as l - where + jsonb_array_elements(load_balancer_attributes) AS l + WHERE l ->> 'Key' = 'deletion_protection.enabled' ) - select - a.arn as resource, + SELECT + a.arn AS resource, og_resource_id, og_account_id, - case - when m.v = 'true' then 'ok' - else 'alarm' - end as status, - case - when m.v = 'true' then 'deletion protection enabled' - else 'deletion protection not enabled' - end as reason, + CASE + WHEN m.v = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN m.v = 'true' THEN 'deletion protection enabled' + ELSE 'deletion protection not enabled' + END AS reason, region, account_id - from - aws_ec2_application_load_balancer as a - left join app_lb_desync_mitigation_mode as m on a.arn = m.arn; - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - Parameters: [] + FROM + aws_ec2_application_load_balancer AS a + LEFT JOIN app_lb_desync_mitigation_mode AS m + ON a.arn = m.arn; Severity: medium Tags: platform_score_cloud_service_name: @@ -46,5 +48,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: ELBv2 Elastic Load Balancing Deletion Protection \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_glb_minimum_number_of_ec2_target_instances.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_glb_minimum_number_of_ec2_target_instances.yaml old mode 100755 new mode 100644 index 45724ebc7..be00acdff --- a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_glb_minimum_number_of_ec2_target_instances.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_glb_minimum_number_of_ec2_target_instances.yaml @@ -1,14 +1,43 @@ +Description: Ensure there is a minimum number of two healthy target instances associated with each AWS ELBv2 gateway load balancer. ID: aws_elbv2_glb_minimum_number_of_ec2_target_instances -Title: "ELBv2 GLB Minimum Number of EC2 Target Instances" -Description: "Ensure there is a minimum number of two healthy target instances associated with each AWS ELBv2 gateway load balancer." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with target_resource as (\nselect \n load_balancer_arn,\n count(*) as c \nfrom \n aws_ec2_target_group, \n jsonb_array_elements_text(load_balancer_arns) as load_balancer_arn \ngroup by load_balancer_arn\n)\nselect\n a.arn as resource,\n a.og_account_id,\n a.og_resource_id,\n case\n when b.load_balancer_arn is null or b.c < 2 then 'alarm'\n else 'ok'\n end as status,\n case\n when b.load_balancer_arn is null or b.c < 2 then a.title || ' is not using a fault-tolerant configuration.'\n else a.title || ' is using a fault-tolerant configuration.'\n end as reason,\n a.region,\n a.account_id\nfrom\n aws_ec2_gateway_load_balancer a\n left join target_resource b on a.arn = b.load_balancer_arn;\n" - PrimaryTable: aws_ec2_gateway_load_balancer ListOfTables: - aws_ec2_gateway_load_balancer - aws_ec2_target_group Parameters: [] + PrimaryTable: aws_ec2_gateway_load_balancer + QueryToExecute: | + WITH target_resource AS ( + SELECT + load_balancer_arn, + COUNT(*) AS c + FROM + aws_ec2_target_group, + JSONB_ARRAY_ELEMENTS_TEXT(load_balancer_arns) AS load_balancer_arn + GROUP BY + load_balancer_arn + ) + SELECT + a.arn AS resource, + a.og_account_id, + a.og_resource_id, + CASE + WHEN b.load_balancer_arn IS NULL OR b.c < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.load_balancer_arn IS NULL OR b.c < 2 THEN a.title || ' is not using a fault-tolerant configuration.' + ELSE a.title || ' is using a fault-tolerant configuration.' + END AS reason, + a.region, + a.account_id + FROM + aws_ec2_gateway_load_balancer a + LEFT JOIN + target_resource b ON a.arn = b.load_balancer_arn; Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +48,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: ELBv2 GLB Minimum Number of EC2 Target Instances \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_nlb_listener_security.yaml b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_nlb_listener_security.yaml old mode 100755 new mode 100644 index cfa4b3310..9afe44a92 --- a/compliance/controls/baseline/aws/load_balancer/aws_elbv2_nlb_listener_security.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_elbv2_nlb_listener_security.yaml @@ -1,72 +1,73 @@ +Description: Ensure that your AWS Network Load Balancer listeners are using a secure protocol such as TLS. ID: aws_elbv2_nlb_listener_security -Title: "ELBv2 NLB Listener Security" -Description: "Ensure that your AWS Network Load Balancer listeners are using a secure protocol such as TLS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_load_balancer_listener + - aws_ec2_network_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_network_load_balancer QueryToExecute: | - with tls_listeners as ( - select - distinct load_balancer_arn - from + WITH tls_listeners AS ( + SELECT + DISTINCT load_balancer_arn + FROM aws_ec2_load_balancer_listener - where + WHERE protocol = 'TLS' - and ssl_policy not in ( + AND ssl_policy NOT IN ( 'ELBSecurityPolicy-2016-08', 'ELBSecurityPolicy-FS-2018-0', 'ELBSecurityPolicy-TLS13-1-2-Ext1-2021-06', 'ELBSecurityPolicy-TLS13-1-2-2021-06' ) - group by + GROUP BY load_balancer_arn ), - nwl_without_tls_listener as ( - select + nwl_without_tls_listener AS ( + SELECT load_balancer_arn, - count(*) - from + COUNT(*) + FROM aws_ec2_load_balancer_listener - where + WHERE protocol = 'TLS' - group by + GROUP BY load_balancer_arn ) - select - lb.arn as resource, + SELECT + lb.arn AS resource, og_resource_id, og_account_id, - case - when l.load_balancer_arn is not null - and lb.arn in ( - select + CASE + WHEN l.load_balancer_arn IS NOT NULL + AND lb.arn IN ( + SELECT load_balancer_arn - from + FROM tls_listeners - ) then 'alarm' - when l.load_balancer_arn is not null then 'ok' - else 'info' - end as status, - case - when l.load_balancer_arn is not null - and lb.arn in ( - select + ) THEN 'alarm' + WHEN l.load_balancer_arn IS NOT NULL THEN 'ok' + ELSE 'info' + END AS status, + CASE + WHEN l.load_balancer_arn IS NOT NULL + AND lb.arn IN ( + SELECT load_balancer_arn - from + FROM tls_listeners - ) then lb.title || ' TLS listener security policy not updated.' - when l.load_balancer_arn is not null then lb.title || ' TLS listener security policy updated.' - else lb.title || ' does not use TLS listener.' - end as reason, + ) THEN lb.title || ' TLS listener security policy not updated.' + WHEN l.load_balancer_arn IS NOT NULL THEN lb.title || ' TLS listener security policy updated.' + ELSE lb.title || ' does not use TLS listener.' + END AS reason, lb.region, lb.account_id - from - aws_ec2_network_load_balancer as lb - left join nwl_without_tls_listener as l on l.load_balancer_arn = lb.arn; - PrimaryTable: aws_ec2_network_load_balancer - ListOfTables: - - aws_ec2_load_balancer_listener - - aws_ec2_network_load_balancer - Parameters: [] + FROM + aws_ec2_network_load_balancer AS lb + LEFT JOIN nwl_without_tls_listener AS l ON l.load_balancer_arn = lb.arn; Severity: high Tags: platform_score_cloud_service_name: @@ -77,5 +78,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Unencrypted Traffic -IntegrationType: - - aws_cloud_account +Title: ELBv2 NLB Listener Security \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_enable_amazon_waf_integration_for_application_load_balancers.yaml b/compliance/controls/baseline/aws/load_balancer/aws_enable_amazon_waf_integration_for_application_load_balancers.yaml old mode 100755 new mode 100644 index 82ea9c69d..33577b0d4 --- a/compliance/controls/baseline/aws/load_balancer/aws_enable_amazon_waf_integration_for_application_load_balancers.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_enable_amazon_waf_integration_for_application_load_balancers.yaml @@ -1,38 +1,40 @@ +Description: Use Amazon WAF to protect Application Load Balancers from common web exploits. ID: aws_enable_amazon_waf_integration_for_application_load_balancers -Title: "Enable Amazon WAF Integration for Application Load Balancers" -Description: "Use Amazon WAF to protect Application Load Balancers from common web exploits." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_application_load_balancer + - aws_wafv2_web_acl + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer QueryToExecute: | - with associated_resource as ( - select + WITH associated_resource AS ( + SELECT arns - from + FROM aws_wafv2_web_acl, - jsonb_array_elements_text(associated_resources) as arns + JSONB_ARRAY_ELEMENTS_TEXT(associated_resources) AS arns ) - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when ar.arns is not null then 'ok' - else 'alarm' - end as status, - case - when ar.arns is not null then title || ' WAF enabled.' - else title || ' WAF disabled.' - end as reason, + CASE + WHEN ar.arns IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ar.arns IS NOT NULL THEN title || ' WAF enabled.' + ELSE title || ' WAF disabled.' + END AS reason, region, account_id - from - aws_ec2_application_load_balancer as lb - left join associated_resource as ar on lb.arn = ar.arns; - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - - aws_wafv2_web_acl - Parameters: [] + FROM + aws_ec2_application_load_balancer AS lb + LEFT JOIN associated_resource AS ar + ON lb.arn = ar.arns; Severity: high Tags: platform_score_cloud_service_name: @@ -43,5 +45,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Enable Amazon WAF Integration for Application Load Balancers \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_enable_cross_zone_load_balancing.yaml b/compliance/controls/baseline/aws/load_balancer/aws_enable_cross_zone_load_balancing.yaml old mode 100755 new mode 100644 index 5f77e059f..af269a700 --- a/compliance/controls/baseline/aws/load_balancer/aws_enable_cross_zone_load_balancing.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_enable_cross_zone_load_balancing.yaml @@ -1,37 +1,37 @@ +Description: Ensure fault tolerance for your Amazon Gateway Load Balancers by enabling Cross-Zone Load Balancing. ID: aws_enable_cross_zone_load_balancing -Title: "Enable Cross-Zone Load Balancing" -Description: "Ensure fault tolerance for your Amazon Gateway Load Balancers by enabling Cross-Zone Load Balancing." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_gateway_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_gateway_load_balancer QueryToExecute: | - select - a.arn as resource, + SELECT + a.arn AS resource, a.og_account_id, a.og_resource_id, - case - when lb ->> 'Value' = 'false' then 'alarm' - else 'ok' - end as status, - case - when lb ->> 'Value' = 'false' then a.title || ' deletion protection is not enabled.' - else a.title || ' deletion protection is enabled.' - end as reason, + CASE + WHEN lb ->> 'Value' = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN lb ->> 'Value' = 'false' THEN a.title || ' deletion protection is not enabled.' + ELSE a.title || ' deletion protection is enabled.' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_gateway_load_balancer a - cross join jsonb_array_elements(load_balancer_attributes) as lb - where + CROSS JOIN jsonb_array_elements(load_balancer_attributes) AS lb + WHERE lb ->> 'Key' = 'load_balancing.cross_zone.enabled' - PrimaryTable: aws_ec2_gateway_load_balancer - ListOfTables: - - aws_ec2_gateway_load_balancer - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: - AWS Elastic Load Balancing V2 (ELBv2) score_service_name: - AWS Elastic Load Balancing V2 (ELBv2) -IntegrationType: - - aws_cloud_account +Title: Enable Cross-Zone Load Balancing \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_enable_deletion_protection.yaml b/compliance/controls/baseline/aws/load_balancer/aws_enable_deletion_protection.yaml old mode 100755 new mode 100644 index 7440d3a58..921c151c4 --- a/compliance/controls/baseline/aws/load_balancer/aws_enable_deletion_protection.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_enable_deletion_protection.yaml @@ -1,37 +1,37 @@ +Description: Ensure that Deletion Protection is enabled for Amazon Gateway Load Balancers. ID: aws_enable_deletion_protection -Title: "Enable Deletion Protection" -Description: "Ensure that Deletion Protection is enabled for Amazon Gateway Load Balancers." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_gateway_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_gateway_load_balancer QueryToExecute: | - select - a.arn as resource, + SELECT + a.arn AS resource, a.og_account_id, a.og_resource_id, - case - when lb ->> 'Value' = 'false' then 'alarm' - else 'ok' - end as status, - case - when lb ->> 'Value' = 'false' then a.title || ' deletion protection is not enabled.' - else a.title || ' deletion protection is enabled.' - end as reason, + CASE + WHEN lb ->> 'Value' = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN lb ->> 'Value' = 'false' THEN a.title || ' deletion protection is not enabled.' + ELSE a.title || ' deletion protection is enabled.' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_gateway_load_balancer a - cross join jsonb_array_elements(load_balancer_attributes) as lb - where + CROSS JOIN jsonb_array_elements(load_balancer_attributes) AS lb + WHERE lb ->> 'Key' = 'deletion_protection.enabled' - PrimaryTable: aws_ec2_gateway_load_balancer - ListOfTables: - - aws_ec2_gateway_load_balancer - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: - AWS Elastic Load Balancing V2 (ELBv2) score_service_name: - AWS Elastic Load Balancing V2 (ELBv2) -IntegrationType: - - aws_cloud_account +Title: Enable Deletion Protection \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_enable_http_to_https_redirect_for_application_load_balancers.yaml b/compliance/controls/baseline/aws/load_balancer/aws_enable_http_to_https_redirect_for_application_load_balancers.yaml old mode 100755 new mode 100644 index 13cff8a4b..f85a1388a --- a/compliance/controls/baseline/aws/load_balancer/aws_enable_http_to_https_redirect_for_application_load_balancers.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_enable_http_to_https_redirect_for_application_load_balancers.yaml @@ -1,45 +1,47 @@ +Description: Ensure that your Application Load Balancers have a rule that redirects HTTP traffic to HTTPS. ID: aws_enable_http_to_https_redirect_for_application_load_balancers -Title: "Enable HTTP to HTTPS Redirect for Application Load Balancers" -Description: "Ensure that your Application Load Balancers have a rule that redirects HTTP traffic to HTTPS." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_application_load_balancer + - aws_ec2_load_balancer_listener + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer QueryToExecute: | - with detailed_listeners as ( - select + WITH detailed_listeners AS ( + SELECT arn, load_balancer_arn, protocol - from + FROM aws_ec2_load_balancer_listener, - jsonb_array_elements(default_actions) as ac - where + jsonb_array_elements(default_actions) AS ac + WHERE split_part(arn, '/', 2) = 'app' - and protocol = 'HTTP' - and ac ->> 'Type' = 'redirect' - and ac -> 'RedirectConfig' ->> 'Protocol' = 'HTTPS' + AND protocol = 'HTTP' + AND ac ->> 'Type' = 'redirect' + AND ac -> 'RedirectConfig' ->> 'Protocol' = 'HTTPS' ) - select - a.arn as resource, + SELECT + a.arn AS resource, og_resource_id, og_account_id, - case - when b.load_balancer_arn is null then 'alarm' - else 'ok' - end as status, - case - when b.load_balancer_arn is not null then a.title || ' associated with HTTP redirection.' - else a.title || ' not associated with HTTP redirection.' - end as reason, + CASE + WHEN b.load_balancer_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.load_balancer_arn IS NOT NULL THEN a.title || ' associated with HTTP redirection.' + ELSE a.title || ' not associated with HTTP redirection.' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_application_load_balancer a - left join detailed_listeners b on a.arn = b.load_balancer_arn; - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - - aws_ec2_load_balancer_listener - Parameters: [] + LEFT JOIN detailed_listeners b + ON a.arn = b.load_balancer_arn; Severity: high Tags: platform_score_cloud_service_name: @@ -50,5 +52,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Unencrypted Traffic -IntegrationType: - - aws_cloud_account +Title: Enable HTTP to HTTPS Redirect for Application Load Balancers \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_enable_support_for_grpc_protocol.yaml b/compliance/controls/baseline/aws/load_balancer/aws_enable_support_for_grpc_protocol.yaml old mode 100755 new mode 100644 index ef3f9a637..ed64bfc6a --- a/compliance/controls/baseline/aws/load_balancer/aws_enable_support_for_grpc_protocol.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_enable_support_for_grpc_protocol.yaml @@ -1,36 +1,41 @@ +Description: Ensure that support for gRPC protocol is enabled for Application Load Balancers (ALBs). ID: aws_enable_support_for_grpc_protocol -Title: "Enable Support for gRPC Protocol" -Description: "Ensure that support for gRPC protocol is enabled for Application Load Balancers (ALBs)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_application_load_balancer + - aws_ec2_target_group + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer QueryToExecute: | - select - a.arn as resource, + SELECT + a.arn AS resource, a.og_account_id, a.og_resource_id, - case - when tg.og_description -> 'TargetGroup' ->> 'ProtocolVersion' = 'GRPC' then 'ok' - else 'alarm' - end as status, - case - when tg.og_description -> 'TargetGroup' ->> 'ProtocolVersion' = 'GRPC' then a.title || ' is configured to send requests to targets using the gRPC protocol.' - else a.title || ' is not configured to send requests to targets using the gRPC protocol.' - end as reason, + CASE + WHEN tg.og_description -> 'TargetGroup' ->> 'ProtocolVersion' = 'GRPC' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN tg.og_description -> 'TargetGroup' ->> 'ProtocolVersion' = 'GRPC' THEN + a.title || ' is configured to send requests to targets using the gRPC protocol.' + ELSE + a.title || ' is not configured to send requests to targets using the gRPC protocol.' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_application_load_balancer a - left join aws_ec2_target_group as tg on tg.load_balancer_arns::text like '%' || a.arn || '%' - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - - aws_ec2_target_group - Parameters: [] + LEFT JOIN + aws_ec2_target_group AS tg + ON + tg.load_balancer_arns::text LIKE '%' || a.arn || '%' Severity: medium Tags: platform_score_cloud_service_name: - AWS Elastic Load Balancing V2 (ELBv2) score_service_name: - AWS Elastic Load Balancing V2 (ELBv2) -IntegrationType: - - aws_cloud_account +Title: Enable Support for gRPC Protocol \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_internet_facing_elbs.yaml b/compliance/controls/baseline/aws/load_balancer/aws_internet_facing_elbs.yaml old mode 100755 new mode 100644 index 5ab015dee..e4f6e7085 --- a/compliance/controls/baseline/aws/load_balancer/aws_internet_facing_elbs.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_internet_facing_elbs.yaml @@ -1,34 +1,34 @@ +Description: Ensure Amazon internet-facing ELBs/ALBs are regularly reviewed for security purposes. ID: aws_internet_facing_elbs -Title: "Internet Facing ELBs" -Description: "Ensure Amazon internet-facing ELBs/ALBs are regularly reviewed for security purposes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_classic_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer QueryToExecute: | - select - a.arn as resource, + SELECT + a.arn AS resource, a.og_account_id, a.og_resource_id, - case - when scheme = 'internet-facing' then 'alarm' - else 'ok' - end as status, - case - when scheme = 'internet-facing' then a.title || ' is internet-facing and routes requests from clients over the Internet to the registered EC2 instances.' - else a.title || ' is not internet-facing and routes requests from clients over the Internet to the registered EC2 instances.' - end as reason, + CASE + WHEN scheme = 'internet-facing' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN scheme = 'internet-facing' THEN a.title || ' is internet-facing and routes requests from clients over the Internet to the registered EC2 instances.' + ELSE a.title || ' is not internet-facing and routes requests from clients over the Internet to the registered EC2 instances.' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_classic_load_balancer a - PrimaryTable: aws_ec2_classic_load_balancer - ListOfTables: - - aws_ec2_classic_load_balancer - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - AWS Elastic Load Balancing V2 (ELBv2) score_service_name: - AWS Elastic Load Balancing V2 (ELBv2) -IntegrationType: - - aws_cloud_account +Title: Internet Facing ELBs \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_internet_facing_elbv2s.yaml b/compliance/controls/baseline/aws/load_balancer/aws_internet_facing_elbv2s.yaml old mode 100755 new mode 100644 index ecd3e77ae..d17ad934e --- a/compliance/controls/baseline/aws/load_balancer/aws_internet_facing_elbv2s.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_internet_facing_elbv2s.yaml @@ -1,34 +1,34 @@ +Description: Ensure Amazon internet-facing ELBs/ALBs are regularly reviewed for security purposes. ID: aws_internet_facing_elbv2s -Title: "Internet Facing ELBv2s" -Description: "Ensure Amazon internet-facing ELBs/ALBs are regularly reviewed for security purposes." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_application_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer QueryToExecute: | - select - a.arn as resource, + SELECT + a.arn AS resource, a.og_account_id, a.og_resource_id, - case - when scheme = 'internet-facing' then 'alarm' - else 'ok' - end as status, - case - when scheme = 'internet-facing' then a.title || ' is internet-facing and routes requests from clients over the Internet to the registered EC2 instances.' - else a.title || ' is not internet-facing and routes requests from clients over the Internet to the registered EC2 instances.' - end as reason, + CASE + WHEN scheme = 'internet-facing' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN scheme = 'internet-facing' THEN a.title || ' is internet-facing and routes requests from clients over the Internet to the registered EC2 instances.' + ELSE a.title || ' is not internet-facing and routes requests from clients over the Internet to the registered EC2 instances.' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_application_load_balancer a - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - AWS Elastic Load Balancing V2 (ELBv2) score_service_name: - AWS Elastic Load Balancing V2 (ELBv2) -IntegrationType: - - aws_cloud_account +Title: Internet Facing ELBv2s \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_unused_application_load_balancers.yaml b/compliance/controls/baseline/aws/load_balancer/aws_unused_application_load_balancers.yaml old mode 100755 new mode 100644 index c14f1f5c6..59b9d914c --- a/compliance/controls/baseline/aws/load_balancer/aws_unused_application_load_balancers.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_unused_application_load_balancers.yaml @@ -1,44 +1,51 @@ +Description: Identify unused Applications Load Balancers, and delete them to help lower the cost of your monthly AWS bill. ID: aws_unused_application_load_balancers -Title: "Unused Application Load Balancers" -Description: "Identify unused Applications Load Balancers, and delete them to help lower the cost of your monthly AWS bill." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_application_load_balancer + - aws_ec2_target_group + Parameters: [] + PrimaryTable: aws_ec2_application_load_balancer QueryToExecute: | - with target_resource as ( - select + WITH target_resource AS ( + SELECT load_balancer_arn, target_health_descriptions, target_type - from + FROM aws_ec2_target_group, - jsonb_array_elements_text(load_balancer_arns) as load_balancer_arn + jsonb_array_elements_text(load_balancer_arns) AS load_balancer_arn ) - select - a.arn as resource, + SELECT + a.arn AS resource, og_resource_id, og_account_id, - case - when b.load_balancer_arn is null then 'alarm' - else 'ok' - end as status, - case - when b.load_balancer_arn is null then a.title || ' has no target registered.' - else a.title || ' has registered target of type ' || b.target_type || '.' - end as reason, - case - when b.load_balancer_arn is null then (SELECT cost FROM pennywise_cost_estimate where resource_type = 'aws::elasticloadbalancingv2::loadbalancer' and resource_id = a.og_resource_id limit 1) - else 0 - end as cost_optimization, + CASE + WHEN b.load_balancer_arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.load_balancer_arn IS NULL THEN a.title || ' has no target registered.' + ELSE a.title || ' has registered target of type ' || b.target_type || '.' + END AS reason, + CASE + WHEN b.load_balancer_arn IS NULL THEN ( + SELECT cost + FROM pennywise_cost_estimate + WHERE resource_type = 'aws::elasticloadbalancingv2::loadbalancer' + AND resource_id = a.og_resource_id + LIMIT 1 + ) + ELSE 0 + END AS cost_optimization, a.region, a.account_id - from + FROM aws_ec2_application_load_balancer a - left join target_resource b on a.arn = b.load_balancer_arn; - PrimaryTable: aws_ec2_application_load_balancer - ListOfTables: - - aws_ec2_application_load_balancer - - aws_ec2_target_group - Parameters: [] + LEFT JOIN target_resource b ON a.arn = b.load_balancer_arn; Severity: high Tags: platform_score_cloud_service_name: @@ -49,5 +56,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Orphaned Resources -IntegrationType: - - aws_cloud_account +Title: Unused Application Load Balancers \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_unused_elastic_load_balancers.yaml b/compliance/controls/baseline/aws/load_balancer/aws_unused_elastic_load_balancers.yaml old mode 100755 new mode 100644 index cda98e9cd..f6c6f99ac --- a/compliance/controls/baseline/aws/load_balancer/aws_unused_elastic_load_balancers.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_unused_elastic_load_balancers.yaml @@ -1,33 +1,40 @@ +Description: Identify unused Elastic Load Balancers, and delete them to help lower the cost of your monthly AWS bill. ID: aws_unused_elastic_load_balancers -Title: "Unused Elastic Load Balancers" -Description: "Identify unused Elastic Load Balancers, and delete them to help lower the cost of your monthly AWS bill." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_classic_load_balancer + Parameters: [] + PrimaryTable: aws_ec2_classic_load_balancer QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_account_id, og_resource_id, - case - when jsonb_array_length(instances) > 0 then 0 - else (SELECT cost FROM pennywise_cost_estimate where resource_type = 'aws::elasticloadbalancing::loadbalancer' and resource_id = lb.og_resource_id limit 1) - end as cost_optimization, - case - when jsonb_array_length(instances) > 0 then 'ok' - else 'alarm' - end as status, - case - when jsonb_array_length(instances) > 0 then title || ' has registered instances.' - else title || ' has no instances registered.' - end as reason, + CASE + WHEN jsonb_array_length(instances) > 0 THEN 0 + ELSE ( + SELECT cost + FROM pennywise_cost_estimate + WHERE resource_type = 'aws::elasticloadbalancing::loadbalancer' + AND resource_id = lb.og_resource_id + LIMIT 1 + ) + END AS cost_optimization, + CASE + WHEN jsonb_array_length(instances) > 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(instances) > 0 THEN title || ' has registered instances.' + ELSE title || ' has no instances registered.' + END AS reason, region, account_id - from - aws_ec2_classic_load_balancer as lb - PrimaryTable: aws_ec2_classic_load_balancer - ListOfTables: - - aws_ec2_classic_load_balancer - Parameters: [] + FROM + aws_ec2_classic_load_balancer AS lb Severity: low Tags: platform_score_cloud_service_name: @@ -38,5 +45,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Orphaned Resources -IntegrationType: - - aws_cloud_account +Title: Unused Elastic Load Balancers \ No newline at end of file diff --git a/compliance/controls/baseline/aws/load_balancer/aws_unused_gateway_load_balancers.yaml b/compliance/controls/baseline/aws/load_balancer/aws_unused_gateway_load_balancers.yaml old mode 100755 new mode 100644 index 61c8e545c..46bb29354 --- a/compliance/controls/baseline/aws/load_balancer/aws_unused_gateway_load_balancers.yaml +++ b/compliance/controls/baseline/aws/load_balancer/aws_unused_gateway_load_balancers.yaml @@ -1,44 +1,45 @@ +Description: Identify unused Gateway Load Balancers, and delete them to help lower the cost of your monthly AWS bill. ID: aws_unused_gateway_load_balancers -Title: "Unused Gateway Load Balancers" -Description: "Identify unused Gateway Load Balancers, and delete them to help lower the cost of your monthly AWS bill." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_ec2_gateway_load_balancer + - aws_ec2_target_group + Parameters: [] + PrimaryTable: aws_ec2_gateway_load_balancer QueryToExecute: | - with target_resource as ( - select + WITH target_resource AS ( + SELECT load_balancer_arn, target_health_descriptions, target_type - from + FROM aws_ec2_target_group, - jsonb_array_elements_text(load_balancer_arns) as load_balancer_arn + jsonb_array_elements_text(load_balancer_arns) AS load_balancer_arn ) - select - a.arn as resource, + SELECT + a.arn AS resource, og_resource_id, og_account_id, - case - when jsonb_array_length(b.target_health_descriptions) = 0 then (SELECT cost FROM pennywise_cost_estimate where resource_type = 'aws::elasticloadbalancingv2::loadbalancer' and resource_id = a.og_resource_id limit 1) - else 0 - end as cost_optimization, - case - when jsonb_array_length(b.target_health_descriptions) = 0 then 'alarm' - else 'ok' - end as status, - case - when jsonb_array_length(b.target_health_descriptions) = 0 then a.title || ' has no target registered.' - else a.title || ' has registered target of type' || ' ' || b.target_type || '.' - end as reason, + CASE + WHEN jsonb_array_length(b.target_health_descriptions) = 0 THEN (SELECT cost FROM pennywise_cost_estimate WHERE resource_type = 'aws::elasticloadbalancingv2::loadbalancer' AND resource_id = a.og_resource_id LIMIT 1) + ELSE 0 + END AS cost_optimization, + CASE + WHEN jsonb_array_length(b.target_health_descriptions) = 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN jsonb_array_length(b.target_health_descriptions) = 0 THEN a.title || ' has no target registered.' + ELSE a.title || ' has registered target of type' || ' ' || b.target_type || '.' + END AS reason, a.region, a.account_id - from + FROM aws_ec2_gateway_load_balancer a - left join target_resource b on a.arn = b.load_balancer_arn; - PrimaryTable: aws_ec2_gateway_load_balancer - ListOfTables: - - aws_ec2_gateway_load_balancer - - aws_ec2_target_group - Parameters: [] + LEFT JOIN target_resource b ON a.arn = b.load_balancer_arn; Severity: high Tags: platform_score_cloud_service_name: @@ -49,5 +50,4 @@ Tags: - AWS Elastic Load Balancing V2 (ELBv2) score_tags: - Orphaned Resources -IntegrationType: - - aws_cloud_account +Title: Unused Gateway Load Balancers \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_enable_audit_logs.yaml b/compliance/controls/baseline/aws/opensearch/aws_enable_audit_logs.yaml old mode 100755 new mode 100644 index c7e6c0aec..2e5b38529 --- a/compliance/controls/baseline/aws/opensearch/aws_enable_audit_logs.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_enable_audit_logs.yaml @@ -1,13 +1,30 @@ +Description: Ensure that audit logging is enabled for all your Amazon OpenSearch domains. ID: aws_enable_audit_logs -Title: "Enable Audit Logs" -Description: "Ensure that audit logging is enabled for all your Amazon OpenSearch domains." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN log_publishing_options ->> 'AUDIT_LOGS' is not null THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN log_publishing_options ->> 'AUDIT_LOGS' is not null THEN domain_name || ' CloudWatch Logs are enabled.' \n ELSE domain_name || ' CloudWatch Logs are not enabled.'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN log_publishing_options ->> 'AUDIT_LOGS' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN log_publishing_options ->> 'AUDIT_LOGS' IS NOT NULL THEN domain_name || ' CloudWatch Logs are enabled.' + ELSE domain_name || ' CloudWatch Logs are not enabled.' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS OpenSearch Service score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Enable Audit Logs \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_enable_in_transit_encryption.yaml b/compliance/controls/baseline/aws/opensearch/aws_enable_in_transit_encryption.yaml old mode 100755 new mode 100644 index a8a6f59bb..f9198f3c1 --- a/compliance/controls/baseline/aws/opensearch/aws_enable_in_transit_encryption.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_enable_in_transit_encryption.yaml @@ -1,13 +1,30 @@ +Description: Ensure that in-transit encryption is enabled for your Amazon OpenSearch domains. ID: aws_enable_in_transit_encryption -Title: "Enable In-Transit Encryption" -Description: "Ensure that in-transit encryption is enabled for your Amazon OpenSearch domains." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN (domain_endpoint_options ->> 'EnforceHTTPS')::bool THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN (domain_endpoint_options ->> 'EnforceHTTPS')::bool THEN domain_name || ' in-transit encryption is enabled.' \n ELSE domain_name || ' in-transit encryption is not enabled'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN (domain_endpoint_options ->> 'EnforceHTTPS')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (domain_endpoint_options ->> 'EnforceHTTPS')::bool THEN domain_name || ' in-transit encryption is enabled.' + ELSE domain_name || ' in-transit encryption is not enabled' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS OpenSearch Service score_tags: - Unencrypted Traffic -IntegrationType: - - aws_cloud_account +Title: Enable In-Transit Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_encryption_at_rest.yaml b/compliance/controls/baseline/aws/opensearch/aws_encryption_at_rest.yaml old mode 100755 new mode 100644 index 8ecf9d238..e0746ccc2 --- a/compliance/controls/baseline/aws/opensearch/aws_encryption_at_rest.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_encryption_at_rest.yaml @@ -1,13 +1,30 @@ +Description: Ensure that your Amazon OpenSearch domains are encrypted in order to meet security and compliance requirements. ID: aws_encryption_at_rest -Title: "Encryption At Rest" -Description: "Ensure that your Amazon OpenSearch domains are encrypted in order to meet security and compliance requirements." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN (encryption_at_rest_options ->> 'Enabled')::bool THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN (encryption_at_rest_options ->> 'Enabled')::bool THEN domain_name || ' encryption at rest is not enabled' \n ELSE domain_name || ' encryption at rest is enabled'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN (encryption_at_rest_options ->> 'Enabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (encryption_at_rest_options ->> 'Enabled')::bool THEN domain_name || ' encryption at rest is not enabled' + ELSE domain_name || ' encryption at rest is enabled' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS OpenSearch Service score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: Encryption At Rest \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_opensearch_accessible_only_from_safelisted_ip_addresses.yaml b/compliance/controls/baseline/aws/opensearch/aws_opensearch_accessible_only_from_safelisted_ip_addresses.yaml old mode 100755 new mode 100644 index 0ce0e84ca..4aae6c232 --- a/compliance/controls/baseline/aws/opensearch/aws_opensearch_accessible_only_from_safelisted_ip_addresses.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_opensearch_accessible_only_from_safelisted_ip_addresses.yaml @@ -1,15 +1,54 @@ +Description: Ensure only safelisted IP addresses can access your Amazon OpenSearch domains. ID: aws_opensearch_accessible_only_from_safelisted_ip_addresses -Title: "Opensearch Accessible Only From Safelisted IP Addresses" -Description: "Ensure only safelisted IP addresses can access your Amazon OpenSearch domains." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN EXISTS (\n SELECT 1\n FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') AS statement\n WHERE statement ->> 'Condition' = NULL\n ) THEN 'alarm'\n WHEN EXISTS (SELECT 1\n FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') AS statement,\n jsonb_array_elements((statement -> 'Condition' -> 'IpAddress' ->> 'aws:SourceIp')::jsonb) AS ip\n WHERE '{{.awsSafelistedIPs}}' like '%' || ip.value::text || '%') THEN 'ok'\n WHEN '{{.awsSafelistedIPs}}' = '' THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN EXISTS (\n SELECT 1\n FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') AS statement\n WHERE statement ->> 'Condition' = NULL\n ) THEN domain_name || ' does not include specific IP addresses'\n WHEN EXISTS (SELECT 1\n FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') AS statement,\n jsonb_array_elements((statement -> 'Condition' -> 'IpAddress' ->> 'aws:SourceIp')::jsonb) AS ip\n WHERE '{{.awsSafelistedIPs}}' like '%' || ip.value::text || '%') THEN domain_name || ' includes approved specific IP addresses'\n WHEN '{{.awsSafelistedIPs}}' = '' THEN ' approved IP addresses not defined'\n ELSE domain_name || ' includes not approved specific IP addresses'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain;\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: - Key: awsSafelistedIPs Required: false + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') AS statement + WHERE statement ->> 'Condition' IS NULL + ) THEN 'alarm' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') AS statement, + jsonb_array_elements((statement -> 'Condition' -> 'IpAddress' ->> 'aws:SourceIp')::jsonb) AS ip + WHERE '{{.awsSafelistedIPs}}' LIKE '%' || ip.value::text || '%' + ) THEN 'ok' + WHEN '{{.awsSafelistedIPs}}' = '' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') AS statement + WHERE statement ->> 'Condition' IS NULL + ) THEN domain_name || ' does not include specific IP addresses' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') AS statement, + jsonb_array_elements((statement -> 'Condition' -> 'IpAddress' ->> 'aws:SourceIp')::jsonb) AS ip + WHERE '{{.awsSafelistedIPs}}' LIKE '%' || ip.value::text || '%' + ) THEN domain_name || ' includes approved specific IP addresses' + WHEN '{{.awsSafelistedIPs}}' = '' THEN ' approved IP addresses not defined' + ELSE domain_name || ' includes not approved specific IP addresses' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain; Severity: critical Tags: platform_score_cloud_service_name: @@ -20,5 +59,4 @@ Tags: - AWS OpenSearch Service score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Opensearch Accessible Only From Safelisted IP Addresses \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_opensearch_dedicated_master_enabled.yaml b/compliance/controls/baseline/aws/opensearch/aws_opensearch_dedicated_master_enabled.yaml old mode 100755 new mode 100644 index b80f76870..7a074b79e --- a/compliance/controls/baseline/aws/opensearch/aws_opensearch_dedicated_master_enabled.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_opensearch_dedicated_master_enabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure Amazon OpenSearch clusters are using dedicated master nodes to increase the production environment stability. ID: aws_opensearch_dedicated_master_enabled -Title: "OpenSearch Dedicated Master Enabled" -Description: "Ensure Amazon OpenSearch clusters are using dedicated master nodes to increase the production environment stability." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN (cluster_config ->> 'DedicatedMasterEnabled')::bool THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN (cluster_config ->> 'DedicatedMasterEnabled')::bool THEN domain_name || ' is configured to use dedicated mater nodes.' \n ELSE domain_name || ' is not configured to use dedicated mater nodes'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN (cluster_config ->> 'DedicatedMasterEnabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (cluster_config ->> 'DedicatedMasterEnabled')::bool THEN domain_name || ' is configured to use dedicated master nodes.' + ELSE domain_name || ' is not configured to use dedicated master nodes' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS OpenSearch Service score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: OpenSearch Dedicated Master Enabled \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_encrypted_with_kms_cmks.yaml b/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_encrypted_with_kms_cmks.yaml old mode 100755 new mode 100644 index a8838734a..7dec49e98 --- a/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_encrypted_with_kms_cmks.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_encrypted_with_kms_cmks.yaml @@ -1,14 +1,35 @@ +Description: Ensure that OpenSearch domains are encrypted with KMS Customer Master Keys (CMKs). ID: aws_opensearch_domain_encrypted_with_kms_cmks -Title: "OpenSearch Domain Encrypted with KMS CMKs" -Description: "Ensure that OpenSearch domains are encrypted with KMS Customer Master Keys (CMKs)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN kms.key_manager is NULL THEN 'alarm'\n WHEN kms.key_manager = 'AWS' THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN kms.key_manager is NULL THEN domain_name || ' encryption with kms key not enabled' \n WHEN kms.key_manager = 'AWS' THEN domain_name || ' is not encrypted with CMK' \n ELSE domain_name || ' is encrypted with CMK'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n left join (select arn, key_manager from aws_kms_key) kms on (encryption_at_rest_options ->> 'KmsKeyId') = kms.arn\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_kms_key - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN kms.key_manager IS NULL THEN 'alarm' + WHEN kms.key_manager = 'AWS' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kms.key_manager IS NULL THEN domain_name || ' encryption with kms key not enabled' + WHEN kms.key_manager = 'AWS' THEN domain_name || ' is not encrypted with CMK' + ELSE domain_name || ' is encrypted with CMK' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain + LEFT JOIN (SELECT arn, key_manager FROM aws_kms_key) kms + ON (encryption_at_rest_options ->> 'KmsKeyId') = kms.arn Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +40,4 @@ Tags: - AWS OpenSearch Service score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: OpenSearch Domain Encrypted with KMS CMKs \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_exposed.yaml b/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_exposed.yaml old mode 100755 new mode 100644 index ff45aeae9..b372d2459 --- a/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_exposed.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_exposed.yaml @@ -1,13 +1,46 @@ +Description: Ensure Amazon OpenSearch domains aren't exposed to everyone. ID: aws_opensearch_domain_exposed -Title: "OpenSearch Domain Exposed" -Description: "Ensure Amazon OpenSearch domains aren't exposed to everyone." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') as s\n WHERE (s ->> 'Effect') = 'Allow' and ((s ->> 'Principal')::text = '\"*\"' or\n (s ->> 'Principal')::text = '{\"AWS\": \"*\"}')\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') as s\n WHERE (s ->> 'Effect') = 'Allow' and ((s ->> 'Principal')::text = '\"*\"' or\n (s ->> 'Principal')::text = '{\"AWS\": \"*\"}')\n ) THEN domain_name || ' is publicly accessible' \n ELSE domain_name || ' is not publicly accessible'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') AS s + WHERE (s ->> 'Effect') = 'Allow' + AND ( + (s ->> 'Principal')::text = '"*"' + OR (s ->> 'Principal')::text = '{"AWS": "*"}' + ) + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies::jsonb -> 'Statement') AS s + WHERE (s ->> 'Effect') = 'Allow' + AND ( + (s ->> 'Principal')::text = '"*"' + OR (s ->> 'Principal')::text = '{"AWS": "*"}' + ) + ) THEN domain_name || ' is publicly accessible' + ELSE domain_name || ' is not publicly accessible' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +51,4 @@ Tags: - AWS OpenSearch Service score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: OpenSearch Domain Exposed \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_in_vpc.yaml b/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_in_vpc.yaml old mode 100755 new mode 100644 index 0fd5a30ef..38e39e0dd --- a/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_in_vpc.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_opensearch_domain_in_vpc.yaml @@ -1,60 +1,60 @@ +Description: Ensure that your Amazon OpenSearch domains are accessible only from AWS VPCs. ID: aws_opensearch_domain_in_vpc -Title: "OpenSearch Domain In VPC" -Description: "Ensure that your Amazon OpenSearch domains are accessible only from AWS VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: + - aws_opensearch_domain + - aws_vpc_route_table + Parameters: [] + PrimaryTable: aws_opensearch_domain QueryToExecute: | - with public_subnets as ( - select - distinct a -> 'SubnetId' as SubnetId - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a, - jsonb_array_elements(routes) as r - where + WITH public_subnets AS ( + SELECT + DISTINCT a -> 'SubnetId' AS SubnetId + FROM + aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE r ->> 'DestinationCidrBlock' = '0.0.0.0/0' - and r ->> 'GatewayId' like 'igw-%' + AND r ->> 'GatewayId' LIKE 'igw-%' ), - opensearch_domain_with_public_subnet as ( - select + opensearch_domain_with_public_subnet AS ( + SELECT arn - from + FROM aws_opensearch_domain, - jsonb_array_elements(vpc_options -> 'SubnetIds') as s - where - s in ( - select + jsonb_array_elements(vpc_options -> 'SubnetIds') AS s + WHERE + s IN ( + SELECT SubnetId - from + FROM public_subnets ) ) - select - d.arn as resource, + SELECT + d.arn AS resource, og_resource_id, og_account_id, - case - when d.vpc_options ->> 'VPCId' is null then 'alarm' - when d.vpc_options ->> 'VPCId' is not null - and p.arn is not null then 'alarm' - else 'ok' - end status, - case - when vpc_options ->> 'VPCId' is null then title || ' not in VPC.' - when d.vpc_options ->> 'VPCId' is not null - and p.arn is not null then title || ' attached to public subnet.' - else title || ' in VPC ' || (vpc_options ->> 'VPCId') || '.' - end reason, + CASE + WHEN d.vpc_options ->> 'VPCId' IS NULL THEN 'alarm' + WHEN d.vpc_options ->> 'VPCId' IS NOT NULL AND p.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN vpc_options ->> 'VPCId' IS NULL THEN title || ' not in VPC.' + WHEN d.vpc_options ->> 'VPCId' IS NOT NULL AND p.arn IS NOT NULL THEN title || ' attached to public subnet.' + ELSE title || ' in VPC ' || (vpc_options ->> 'VPCId') || '.' + END reason, d.region, d.account_id - from - aws_opensearch_domain as d - left join opensearch_domain_with_public_subnet as p on d.arn = p.arn; - PrimaryTable: aws_opensearch_domain - ListOfTables: - - aws_opensearch_domain - - aws_vpc_route_table - Parameters: [] + FROM + aws_opensearch_domain AS d + LEFT JOIN opensearch_domain_with_public_subnet AS p + ON d.arn = p.arn; Severity: high Tags: platform_score_cloud_service_name: @@ -65,5 +65,4 @@ Tags: - AWS OpenSearch Service score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: OpenSearch Domain In VPC \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_opensearch_node_to_node_encryption.yaml b/compliance/controls/baseline/aws/opensearch/aws_opensearch_node_to_node_encryption.yaml old mode 100755 new mode 100644 index c234c699f..ec8844347 --- a/compliance/controls/baseline/aws/opensearch/aws_opensearch_node_to_node_encryption.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_opensearch_node_to_node_encryption.yaml @@ -1,13 +1,30 @@ +Description: Ensure that your Amazon OpenSearch clusters are using node to node encryption in order to meet security and compliance requirements. ID: aws_opensearch_node_to_node_encryption -Title: "OpenSearch Node To Node Encryption" -Description: "Ensure that your Amazon OpenSearch clusters are using node to node encryption in order to meet security and compliance requirements." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN not node_to_node_encryption_options_enabled THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN not node_to_node_encryption_options_enabled THEN domain_name || ' node-to-node encryption is not enabled' \n ELSE domain_name || ' node-to-node encryption is enabled'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN NOT node_to_node_encryption_options_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT node_to_node_encryption_options_enabled THEN domain_name || ' node-to-node encryption is not enabled' + ELSE domain_name || ' node-to-node encryption is enabled' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS OpenSearch Service score_tags: - Unencrypted Traffic -IntegrationType: - - aws_cloud_account +Title: OpenSearch Node To Node Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_opensearch_slow_logs.yaml b/compliance/controls/baseline/aws/opensearch/aws_opensearch_slow_logs.yaml old mode 100755 new mode 100644 index 6c5055cde..261a0b49e --- a/compliance/controls/baseline/aws/opensearch/aws_opensearch_slow_logs.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_opensearch_slow_logs.yaml @@ -1,13 +1,32 @@ +Description: Ensure that your AWS OpenSearch domains publish slow logs to AWS CloudWatch Logs. ID: aws_opensearch_slow_logs -Title: "AWS OpenSearch Slow Logs" -Description: "Ensure that your AWS OpenSearch domains publish slow logs to AWS CloudWatch Logs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN (COALESCE((log_publishing_options -> 'INDEX_SLOW_LOGS' ->> 'Enabled')::bool, false)::bool and\n COALESCE((log_publishing_options -> 'SEARCH_SLOW_LOGS' ->> 'Enabled')::bool, false)::bool) THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN (COALESCE((log_publishing_options -> 'INDEX_SLOW_LOGS' ->> 'Enabled')::bool, false)::bool and\n COALESCE((log_publishing_options -> 'SEARCH_SLOW_LOGS' ->> 'Enabled')::bool, false)::bool) THEN domain_name || ' Slow Logs feature is enabled' \n ELSE domain_name || ' Slow Logs feature is not enabled'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN (COALESCE((log_publishing_options -> 'INDEX_SLOW_LOGS' ->> 'Enabled')::bool, false)::bool AND + COALESCE((log_publishing_options -> 'SEARCH_SLOW_LOGS' ->> 'Enabled')::bool, false)::bool) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (COALESCE((log_publishing_options -> 'INDEX_SLOW_LOGS' ->> 'Enabled')::bool, false)::bool AND + COALESCE((log_publishing_options -> 'SEARCH_SLOW_LOGS' ->> 'Enabled')::bool, false)::bool) THEN domain_name || ' Slow Logs feature is enabled' + ELSE domain_name || ' Slow Logs feature is not enabled' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +37,4 @@ Tags: - AWS OpenSearch Service score_tags: - General Efficiency -IntegrationType: - - aws_cloud_account +Title: AWS OpenSearch Slow Logs \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_opensearch_version.yaml b/compliance/controls/baseline/aws/opensearch/aws_opensearch_version.yaml old mode 100755 new mode 100644 index 2f124fe73..cfc0ec0ad --- a/compliance/controls/baseline/aws/opensearch/aws_opensearch_version.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_opensearch_version.yaml @@ -1,15 +1,32 @@ +Description: Ensure that the latest version of OpenSearch engine is used for your OpenSearch domains. ID: aws_opensearch_version -Title: "OpenSearch Version" -Description: "Ensure that the latest version of OpenSearch engine is used for your OpenSearch domains." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN engine_version = '{{.awsOpensearchLatestVersion}}' THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN engine_version = '{{.awsOpensearchLatestVersion}}' THEN domain_name || ' is using the latest engine version' \n ELSE domain_name || ' is not using the latest engine version'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: - Key: awsOpensearchLatestVersion Required: true + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN engine_version = '{{.awsOpensearchLatestVersion}}' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN engine_version = '{{.awsOpensearchLatestVersion}}' THEN domain_name || ' is using the latest engine version' + ELSE domain_name || ' is not using the latest engine version' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain Severity: high Tags: platform_score_cloud_service_name: @@ -20,5 +37,4 @@ Tags: - AWS OpenSearch Service score_tags: - General Efficiency -IntegrationType: - - aws_cloud_account +Title: OpenSearch Version \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_opensearch_zone_awareness_enabled.yaml b/compliance/controls/baseline/aws/opensearch/aws_opensearch_zone_awareness_enabled.yaml old mode 100755 new mode 100644 index 7c82f40bf..71bdeb02e --- a/compliance/controls/baseline/aws/opensearch/aws_opensearch_zone_awareness_enabled.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_opensearch_zone_awareness_enabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure high availability for your Amazon OpenSearch clusters by enabling the Zone Awareness feature. ID: aws_opensearch_zone_awareness_enabled -Title: "OpenSearch Zone Awareness Enabled" -Description: "Ensure high availability for your Amazon OpenSearch clusters by enabling the Zone Awareness feature." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN (cluster_config ->> 'ZoneAwarenessEnabled')::bool THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN (cluster_config ->> 'ZoneAwarenessEnabled')::bool THEN domain_name || ' cross-zone replication is enabled' \n ELSE domain_name || ' cross-zone replication is not enabled'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN (cluster_config ->> 'ZoneAwarenessEnabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (cluster_config ->> 'ZoneAwarenessEnabled')::bool THEN domain_name || ' cross-zone replication is enabled' + ELSE domain_name || ' cross-zone replication is not enabled' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS OpenSearch Service score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: OpenSearch Zone Awareness Enabled \ No newline at end of file diff --git a/compliance/controls/baseline/aws/opensearch/aws_tls_security_policy_version.yaml b/compliance/controls/baseline/aws/opensearch/aws_tls_security_policy_version.yaml old mode 100755 new mode 100644 index 36c7e95f3..39ab23060 --- a/compliance/controls/baseline/aws/opensearch/aws_tls_security_policy_version.yaml +++ b/compliance/controls/baseline/aws/opensearch/aws_tls_security_policy_version.yaml @@ -1,13 +1,30 @@ +Description: Ensure that your OpenSearch domains are using the latest version of the TLS security policy. ID: aws_tls_security_policy_version -Title: "TLS Security Policy Version" -Description: "Ensure that your OpenSearch domains are using the latest version of the TLS security policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "SELECT \n domain_name as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN log_publishing_options is NULL THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN log_publishing_options is NULL THEN domain_name || ' the CloudWatch Logs are not enabled' \n ELSE domain_name || ' the CloudWatch Logs are enabled'\n END AS reason,\n region,\n account_id\nFROM \n aws_opensearch_domain\n" - PrimaryTable: aws_opensearch_domain ListOfTables: - aws_opensearch_domain Parameters: [] + PrimaryTable: aws_opensearch_domain + QueryToExecute: | + SELECT + domain_name AS resource, + og_resource_id, + og_account_id, + CASE + WHEN log_publishing_options IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN log_publishing_options IS NULL THEN domain_name || ' the CloudWatch Logs are not enabled' + ELSE domain_name || ' the CloudWatch Logs are enabled' + END AS reason, + region, + account_id + FROM + aws_opensearch_domain Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +35,4 @@ Tags: - AWS OpenSearch Service score_tags: - Unencrypted Traffic -IntegrationType: - - aws_cloud_account +Title: TLS Security Policy Version \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_aurora_database_cluster_activity_streams.yaml b/compliance/controls/baseline/aws/rds/aws_aurora_database_cluster_activity_streams.yaml old mode 100755 new mode 100644 index abf791ac3..488bfd3e3 --- a/compliance/controls/baseline/aws/rds/aws_aurora_database_cluster_activity_streams.yaml +++ b/compliance/controls/baseline/aws/rds/aws_aurora_database_cluster_activity_streams.yaml @@ -1,42 +1,49 @@ +Description: Ensure that Amazon Aurora clusters are configured to use database activity streams. ID: aws_aurora_database_cluster_activity_streams -Title: "Aurora Database Cluster Activity Streams" -Description: "Ensure that Amazon Aurora clusters are configured to use database activity streams." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: |- - with access_count as ( - select - db_cluster_identifier, count(db_cluster_identifier) - from - aws_rds_db_instance - group by - db_cluster_identifier, publicly_accessible - ) - - select - c.db_cluster_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when a.count = 2 then 'alarm' - else 'ok' - end as status, - case - when a.count = 2 then title || ' cluster database instances dont have the same accessibility' - else title || ' cluster database instances have the same accessibility' - end as reason, - region, - account_id - from - aws_rds_db_cluster c - left join access_count as a on c.db_cluster_identifier = a.db_cluster_identifier - where - c.engine = 'aurora-mysql' or c.engine = 'aurora-postgresql' - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + WITH access_count AS ( + SELECT + db_cluster_identifier, + COUNT(db_cluster_identifier) + FROM + aws_rds_db_instance + GROUP BY + db_cluster_identifier, + publicly_accessible + ) + + SELECT + c.db_cluster_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN a.count = 2 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.count = 2 THEN title || ' cluster database instances dont have the same accessibility' + ELSE title || ' cluster database instances have the same accessibility' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster c + LEFT JOIN + access_count AS a + ON + c.db_cluster_identifier = a.db_cluster_identifier + WHERE + c.engine = 'aurora-mysql' + OR c.engine = 'aurora-postgresql' Severity: medium Tags: platform_score_cloud_service_name: @@ -47,5 +54,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Aurora Database Cluster Activity Streams \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_aurora_database_instance_accessibility.yaml b/compliance/controls/baseline/aws/rds/aws_aurora_database_instance_accessibility.yaml index ea5a10488..594bc717b 100644 --- a/compliance/controls/baseline/aws/rds/aws_aurora_database_instance_accessibility.yaml +++ b/compliance/controls/baseline/aws/rds/aws_aurora_database_instance_accessibility.yaml @@ -1,42 +1,45 @@ +Description: Ensure that all database instances within an Amazon Aurora cluster have the same accessibility. ID: aws_aurora_database_instance_accessibility -Title: "Aurora Database Instance Accessibility" -Description: "Ensure that all database instances within an Amazon Aurora cluster have the same accessibility." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - with access_count as ( - select - db_cluster_identifier, count(db_cluster_identifier) - from - aws_rds_db_instance - group by - db_cluster_identifier, publicly_accessible - ) - - select - c.db_cluster_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when a.count = 2 then 'alarm' - else 'ok' - end as status, - case - when a.count = 2 then title || ' cluster database instances dont have the same accessibility' - else title || ' cluster database instances have the same accessibility' - end as reason, - region, - account_id - from - aws_rds_db_cluster c - left join access_count as a on c.db_cluster_identifier = a.db_cluster_identifier - where - c.engine = 'aurora-mysql' or c.engine = 'aurora-postgresql' - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + WITH access_count AS ( + SELECT + db_cluster_identifier, + COUNT(db_cluster_identifier) + FROM + aws_rds_db_instance + GROUP BY + db_cluster_identifier, + publicly_accessible + ) + + SELECT + c.db_cluster_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN a.count = 2 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.count = 2 THEN title || ' cluster database instances dont have the same accessibility' + ELSE title || ' cluster database instances have the same accessibility' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster c + LEFT JOIN access_count AS a ON c.db_cluster_identifier = a.db_cluster_identifier + WHERE + c.engine = 'aurora-mysql' OR c.engine = 'aurora-postgresql' Severity: medium Tags: platform_score_cloud_service_name: @@ -47,5 +50,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Aurora Database Instance Accessibility \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_backtrack.yaml b/compliance/controls/baseline/aws/rds/aws_backtrack.yaml index d4b09bc58..82a077947 100644 --- a/compliance/controls/baseline/aws/rds/aws_backtrack.yaml +++ b/compliance/controls/baseline/aws/rds/aws_backtrack.yaml @@ -1,31 +1,32 @@ +Description: Enable Amazon Aurora Backtrack. ID: aws_backtrack -Title: "Backtrack" -Description: "Enable Amazon Aurora Backtrack." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_cluster_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when backtrack_window is null then 'alarm' - else 'ok' - end as status, - case - when backtrack_window is null then title || ' Backtrack feature is not enabled' - else title || ' Backtrack feature is enabled' - end as reason, - region, - account_id - from - aws_rds_db_cluster - where - engine = 'aurora-mysql' or engine = 'aurora-postgresql' - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + db_cluster_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN backtrack_window IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN backtrack_window IS NULL THEN title || ' Backtrack feature is not enabled' + ELSE title || ' Backtrack feature is enabled' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster + WHERE + engine = 'aurora-mysql' OR engine = 'aurora-postgresql' Severity: low Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Backtrack \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_cluster_deletion_protection.yaml b/compliance/controls/baseline/aws/rds/aws_cluster_deletion_protection.yaml index 17febd7d8..0bc074656 100644 --- a/compliance/controls/baseline/aws/rds/aws_cluster_deletion_protection.yaml +++ b/compliance/controls/baseline/aws/rds/aws_cluster_deletion_protection.yaml @@ -1,31 +1,32 @@ +Description: Enable AWS RDS Cluster Deletion Protection. ID: aws_cluster_deletion_protection -Title: "Cluster Deletion Protection" -Description: "Enable AWS RDS Cluster Deletion Protection." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_cluster_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not deletion_protection then 'alarm' - else 'ok' - end as status, - case - when not deletion_protection then title || ' Deletion Protection safety feature is not enabled' - else title || ' Deletion Protection safety feature is enabled' - end as reason, - region, - account_id - from - aws_rds_db_cluster - where - engine = 'aurora-mysql' or engine = 'aurora-postgresql' - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + db_cluster_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT deletion_protection THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT deletion_protection THEN title || ' Deletion Protection safety feature is not enabled' + ELSE title || ' Deletion Protection safety feature is enabled' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster + WHERE + engine = 'aurora-mysql' OR engine = 'aurora-postgresql' Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Cluster Deletion Protection \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_db_instance_generation.yaml b/compliance/controls/baseline/aws/rds/aws_db_instance_generation.yaml index a9943ec3f..a45ca99f9 100644 --- a/compliance/controls/baseline/aws/rds/aws_db_instance_generation.yaml +++ b/compliance/controls/baseline/aws/rds/aws_db_instance_generation.yaml @@ -1,43 +1,43 @@ +Description: Ensure you always use the latest generation of DB instances to get better performance with lower cost. ID: aws_db_instance_generation -Title: "DB Instance Generation" -Description: "Ensure you always use the latest generation of DB instances to get better performance with lower cost." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, + ListOfTables: + - aws_rds_db_instance + Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, class, - case - when ARRAY['db.m1.small', 'db.m1.medium', 'db.m1.large', - 'db.m1.xlarge', 'db.m3.medium', 'db.m3.large', 'db.m3.xlarge', - 'db.m3.2xlarge', 'db.m2.xlarge', 'db.m2.2xlarge', 'db.m2.4xlarge', - 'db.r3.large', 'db.r3.xlarge', 'db.r3.2xlarge', 'db.r3.4xlarge', - 'db.r3.8xlarge'] @> ARRAY[class] then 'alarm' - else 'ok' - end as status, - case - when ARRAY['db.m1.small', 'db.m1.medium', 'db.m1.large', - 'db.m1.xlarge', 'db.m3.medium', 'db.m3.large', 'db.m3.xlarge', - 'db.m3.2xlarge', 'db.m2.xlarge', 'db.m2.2xlarge', 'db.m2.4xlarge', - 'db.r3.large', 'db.r3.xlarge', 'db.r3.2xlarge', 'db.r3.4xlarge', - 'db.r3.8xlarge'] @> ARRAY[class] then title || ' RDS Instance is using previous generation class' - else title || ' RDS Instance is using class of latest generation' - end as reason, + CASE + WHEN ARRAY['db.m1.small', 'db.m1.medium', 'db.m1.large', 'db.m1.xlarge', + 'db.m3.medium', 'db.m3.large', 'db.m3.xlarge', 'db.m3.2xlarge', + 'db.m2.xlarge', 'db.m2.2xlarge', 'db.m2.4xlarge', 'db.r3.large', + 'db.r3.xlarge', 'db.r3.2xlarge', 'db.r3.4xlarge', 'db.r3.8xlarge'] + @> ARRAY[class] THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ARRAY['db.m1.small', 'db.m1.medium', 'db.m1.large', 'db.m1.xlarge', + 'db.m3.medium', 'db.m3.large', 'db.m3.xlarge', 'db.m3.2xlarge', + 'db.m2.xlarge', 'db.m2.2xlarge', 'db.m2.4xlarge', 'db.r3.large', + 'db.r3.xlarge', 'db.r3.2xlarge', 'db.r3.4xlarge', 'db.r3.8xlarge'] + @> ARRAY[class] THEN title || ' RDS Instance is using previous generation class' + ELSE title || ' RDS Instance is using class of latest generation' + END AS reason, region, account_id - from + FROM aws_rds_db_instance - PrimaryTable: aws_rds_db_instance - ListOfTables: - - aws_rds_db_instance - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - AWS Relational Database Service (RDS) score_service_name: - AWS Relational Database Service (RDS) -IntegrationType: - - aws_cloud_account +Title: DB Instance Generation \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_enable_aurora_cluster_copy_tags_to_snapshots.yaml b/compliance/controls/baseline/aws/rds/aws_enable_aurora_cluster_copy_tags_to_snapshots.yaml index 3b38ebfa1..affb5891b 100644 --- a/compliance/controls/baseline/aws/rds/aws_enable_aurora_cluster_copy_tags_to_snapshots.yaml +++ b/compliance/controls/baseline/aws/rds/aws_enable_aurora_cluster_copy_tags_to_snapshots.yaml @@ -1,31 +1,32 @@ +Description: Ensure that Amazon Aurora clusters have Copy Tags to Snapshots feature enabled. ID: aws_enable_aurora_cluster_copy_tags_to_snapshots -Title: "Enable Aurora Cluster Copy Tags to Snapshots" -Description: "Ensure that Amazon Aurora clusters have Copy Tags to Snapshots feature enabled." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_cluster_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not copy_tags_to_snapshot then 'alarm' - else 'ok' - end as status, - case - when not copy_tags_to_snapshot then title || ' Copy Tags to Snapshots feature is not enabled' - else title || ' Copy Tags to Snapshots feature is enabled' - end as reason, - region, - account_id - from - aws_rds_db_cluster - where - engine = 'aurora-mysql' or engine = 'aurora-postgresql' - PrimaryTable: aws_rds_db_cluster ListOfTables: - aws_rds_db_cluster Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + db_cluster_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT copy_tags_to_snapshot THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT copy_tags_to_snapshot THEN title || ' Copy Tags to Snapshots feature is not enabled' + ELSE title || ' Copy Tags to Snapshots feature is enabled' + END AS reason, + region, + account_id + FROM + aws_rds_db_cluster + WHERE + engine = 'aurora-mysql' OR engine = 'aurora-postgresql' Severity: high Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Observability -IntegrationType: - - aws_cloud_account +Title: Enable Aurora Cluster Copy Tags to Snapshots \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_enable_aws_rds_transport_encryption.yaml b/compliance/controls/baseline/aws/rds/aws_enable_aws_rds_transport_encryption.yaml index c29e630da..257a7b9d0 100644 --- a/compliance/controls/baseline/aws/rds/aws_enable_aws_rds_transport_encryption.yaml +++ b/compliance/controls/baseline/aws/rds/aws_enable_aws_rds_transport_encryption.yaml @@ -1,12 +1,18 @@ +Description: Ensure AWS RDS SQL Server and Postgre instances have Transport Encryption feature enabled. ID: aws_enable_aws_rds_transport_encryption -Title: "Enable AWS RDS Transport Encryption" -Description: "Ensure AWS RDS SQL Server and Postgre instances have Transport Encryption feature enabled." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - with instance_pg as ( - select - g ->> 'DBParameterGroupName' as pg_name, + ListOfTables: + - aws_rds_db_instance + - aws_rds_db_parameter_group + Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + WITH instance_pg AS ( + SELECT + g ->> 'DBParameterGroupName' AS pg_name, i.og_account_id, i.og_resource_id, i.engine, @@ -16,49 +22,47 @@ Query: i.region, i.account_id, i._ctx - from - aws_rds_db_instance as i, - jsonb_array_elements(db_parameter_groups) as g + FROM + aws_rds_db_instance AS i, + jsonb_array_elements(db_parameter_groups) AS g ), - pg_with_ssl_enabled as ( - select + pg_with_ssl_enabled AS ( + SELECT g.name - from - instance_pg as i, - aws_rds_db_parameter_group as g, - jsonb_array_elements(parameters) as p - where + FROM + instance_pg AS i, + aws_rds_db_parameter_group AS g, + jsonb_array_elements(parameters) AS p + WHERE i.pg_name = g.name - and g.account_id = i.account_id - and g.region = i.region - and p ->> 'ParameterName' = 'rds.force_ssl' - and p ->> 'ParameterValue' = '1' + AND g.account_id = i.account_id + AND g.region = i.region + AND p ->> 'ParameterName' = 'rds.force_ssl' + AND p ->> 'ParameterValue' = '1' ) - select - i.arn as resource, + SELECT + i.arn AS resource, i.engine, i.og_account_id, i.og_resource_id, - case - when i.engine not in ('sqlserver', 'postgres') then 'skip' - when p.name is not null then 'ok' - else 'alarm' - end as status, - case - when i.engine not in ('sqlserver', 'postgres') then title || ' has ' || engine || ' engine type.' - when p.name is not null then title || ' connections are SSL encrypted.' - else title || ' connections are not SSL encrypted.' - end as reason, + CASE + WHEN i.engine NOT IN ('sqlserver', 'postgres') THEN 'skip' + WHEN p.name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN i.engine NOT IN ('sqlserver', 'postgres') THEN title || ' has ' || engine || ' engine type.' + WHEN p.name IS NOT NULL THEN title || ' connections are SSL encrypted.' + ELSE title || ' connections are not SSL encrypted.' + END AS reason, region, account_id - from - instance_pg as i - left join pg_with_ssl_enabled as p on p.name = i.pg_name - PrimaryTable: aws_rds_db_instance - ListOfTables: - - aws_rds_db_instance - - aws_rds_db_parameter_group - Parameters: [] + FROM + instance_pg AS i + LEFT JOIN + pg_with_ssl_enabled AS p + ON + p.name = i.pg_name Severity: high Tags: platform_score_cloud_service_name: @@ -69,5 +73,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Unencrypted Traffic -IntegrationType: - - aws_cloud_account +Title: Enable AWS RDS Transport Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_enable_instance_storage_auto_scaling.yaml b/compliance/controls/baseline/aws/rds/aws_enable_instance_storage_auto_scaling.yaml index 341aa320b..1571c8e17 100644 --- a/compliance/controls/baseline/aws/rds/aws_enable_instance_storage_auto_scaling.yaml +++ b/compliance/controls/baseline/aws/rds/aws_enable_instance_storage_auto_scaling.yaml @@ -1,31 +1,32 @@ +Description: Ensure that the Storage AutoScaling feature is enabled to support unpredictable database workload. ID: aws_enable_instance_storage_auto_scaling -Title: "Enable Instance Storage AutoScaling" -Description: "Ensure that the Storage AutoScaling feature is enabled to support unpredictable database workload." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when max_allocated_storage is null then 'alarm' - else 'ok' - end as status, - case - when max_allocated_storage is null then title || ' Storage AutoScaling feature is not enabled' - else title || ' Storage AutoScaling feature is enabled' - end as reason, - region, - account_id - from - aws_rds_db_instance - where - engine = 'mysql' or engine = 'postgres' - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN max_allocated_storage IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN max_allocated_storage IS NULL THEN title || ' Storage AutoScaling feature is not enabled' + ELSE title || ' Storage AutoScaling feature is enabled' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance + WHERE + engine = 'mysql' OR engine = 'postgres' Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Over Utilization -IntegrationType: - - aws_cloud_account +Title: Enable Instance Storage AutoScaling \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_enable_rds_snapshot_encryption.yaml b/compliance/controls/baseline/aws/rds/aws_enable_rds_snapshot_encryption.yaml index 43890c42f..0123d3cd2 100644 --- a/compliance/controls/baseline/aws/rds/aws_enable_rds_snapshot_encryption.yaml +++ b/compliance/controls/baseline/aws/rds/aws_enable_rds_snapshot_encryption.yaml @@ -1,40 +1,46 @@ +Description: Ensure that AWS RDS snapshots are encrypted to meet security and compliance requirements. ID: aws_enable_rds_snapshot_encryption -Title: "Enable RDS Snapshot Encryption" -Description: "Ensure that AWS RDS snapshots are encrypted to meet security and compliance requirements." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - with snapshots as ( - select distinct - db_instance_identifier, encrypted - from - aws_rds_db_snapshot - where type = 'awsbackup' - ) - select - r.db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when b.db_instance_identifier is null then 'skip' - when not b.encrypted then 'alarm' - else 'ok' - end as status, - case - when b.db_instance_identifier is null then r.title || ' has no RDS database instance snapshots.' - when not b.encrypted then r.title || ' snapshots not encrypted.' - else r.title || ' snapshots encrypted.' - end as reason, - r.region, - r.account_id - from - aws_rds_db_instance as r - left join snapshots as b on r.db_instance_identifier = b.db_instance_identifier; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance - aws_rds_db_snapshot Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + WITH snapshots AS ( + SELECT DISTINCT + db_instance_identifier, + encrypted + FROM + aws_rds_db_snapshot + WHERE + type = 'awsbackup' + ) + SELECT + r.db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN b.db_instance_identifier IS NULL THEN 'skip' + WHEN NOT b.encrypted THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN b.db_instance_identifier IS NULL THEN r.title || ' has no RDS database instance snapshots.' + WHEN NOT b.encrypted THEN r.title || ' snapshots not encrypted.' + ELSE r.title || ' snapshots encrypted.' + END AS reason, + r.region, + r.account_id + FROM + aws_rds_db_instance AS r + LEFT JOIN + snapshots AS b + ON + r.db_instance_identifier = b.db_instance_identifier; Severity: medium Tags: platform_score_cloud_service_name: @@ -45,5 +51,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: Enable RDS Snapshot Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_enable_serverless_log_exports.yaml b/compliance/controls/baseline/aws/rds/aws_enable_serverless_log_exports.yaml index af5ad3e3c..f9bed21c3 100644 --- a/compliance/controls/baseline/aws/rds/aws_enable_serverless_log_exports.yaml +++ b/compliance/controls/baseline/aws/rds/aws_enable_serverless_log_exports.yaml @@ -1,31 +1,32 @@ +Description: Ensure Log Exports feature is enabled for your Amazon Aurora Serverless databases. ID: aws_enable_serverless_log_exports -Title: "Enable Serverless Log Exports" -Description: "Ensure Log Exports feature is enabled for your Amazon Aurora Serverless databases." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_cluster_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when enabled_cloudwatch_logs_exports is null then 'alarm' - else 'ok' - end as status, - case - when enabled_cloudwatch_logs_exports is null then title || ' Log Exports feature is not enabled' - else title || ' Log Exports feature is enabled' - end as reason, + ListOfTables: + - aws_rds_db_cluster + Parameters: [] + PrimaryTable: aws_rds_db_cluster + QueryToExecute: | + SELECT + db_cluster_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enabled_cloudwatch_logs_exports IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN enabled_cloudwatch_logs_exports IS NULL THEN title || ' Log Exports feature is not enabled' + ELSE title || ' Log Exports feature is enabled' + END AS reason, region, account_id - from + FROM aws_rds_db_cluster - where + WHERE engine_mode = 'serverless' - PrimaryTable: aws_rds_db_cluster - ListOfTables: - - aws_rds_db_cluster - Parameters: [] Severity: low Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Enable Serverless Log Exports \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_instance_deletion_protection.yaml b/compliance/controls/baseline/aws/rds/aws_instance_deletion_protection.yaml index 0490f7481..2c03bf330 100644 --- a/compliance/controls/baseline/aws/rds/aws_instance_deletion_protection.yaml +++ b/compliance/controls/baseline/aws/rds/aws_instance_deletion_protection.yaml @@ -1,31 +1,32 @@ +Description: Enable AWS RDS Instance Deletion Protection. ID: aws_instance_deletion_protection -Title: "Instance Deletion Protection" -Description: "Enable AWS RDS Instance Deletion Protection." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when engine like any(array [ 'aurora%', 'docdb', 'neptune' ]) then 'skip' - when deletion_protection then 'ok' - else 'alarm' - end status, - case - when engine like any(array [ 'aurora%', 'docdb', 'neptune' ]) then title || ' has engine ' || engine || ' cluster, deletion protection is set at cluster level.' - when deletion_protection then title || ' deletion protection enabled.' - else title || ' deletion protection not enabled.' - end reason, - region, - account_id - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN engine LIKE ANY(ARRAY ['aurora%', 'docdb', 'neptune']) THEN 'skip' + WHEN deletion_protection THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN engine LIKE ANY(ARRAY ['aurora%', 'docdb', 'neptune']) THEN title || ' has engine ' || engine || ' cluster, deletion protection is set at cluster level.' + WHEN deletion_protection THEN title || ' deletion protection enabled.' + ELSE title || ' deletion protection not enabled.' + END reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: Instance Deletion Protection \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_instance_level_events_subscriptions.yaml b/compliance/controls/baseline/aws/rds/aws_instance_level_events_subscriptions.yaml index d8508b8c9..5d22ea3d1 100644 --- a/compliance/controls/baseline/aws/rds/aws_instance_level_events_subscriptions.yaml +++ b/compliance/controls/baseline/aws/rds/aws_instance_level_events_subscriptions.yaml @@ -1,14 +1,33 @@ +Description: Enable Event Subscriptions for Instance Level Events. ID: aws_instance_level_events_subscriptions -Title: "Instance Level Events Subscriptions" -Description: "Enable Event Subscriptions for Instance Level Events." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: "select distinct\n a.og_account_id,\n a.og_resource_id,\n case\n when s.arn\n is null then 'alarm'\n else 'ok'\n end status,\n case\n when s.arn is\n null then 'Event notifications is not enabled for Amazon RDS instance level events'\n\n else 'Event notifications is enabled for Amazon RDS instance level events'\n\n end reason,\n a.account_id\nfrom \n aws_account a\n left join (select * from\n aws_rds_db_event_subscription where source_type = 'db-instance') s on s.og_account_id\n = a.og_account_id\n" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT DISTINCT + a.og_account_id, + a.og_resource_id, + CASE + WHEN s.arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.arn IS NULL THEN 'Event notifications is not enabled for Amazon RDS instance level events' + ELSE 'Event notifications is enabled for Amazon RDS instance level events' + END AS reason, + a.account_id + FROM + aws_account a + LEFT JOIN ( + SELECT * FROM aws_rds_db_event_subscription + WHERE source_type = 'db-instance' + ) s ON s.og_account_id = a.og_account_id Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +38,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - General Efficiency -IntegrationType: - - aws_cloud_account +Title: Instance Level Events Subscriptions \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_log_exports.yaml b/compliance/controls/baseline/aws/rds/aws_log_exports.yaml index d7deff54e..a4bf95f14 100644 --- a/compliance/controls/baseline/aws/rds/aws_log_exports.yaml +++ b/compliance/controls/baseline/aws/rds/aws_log_exports.yaml @@ -1,31 +1,32 @@ +Description: Enable AWS RDS Log Exports. ID: aws_log_exports -Title: "Log Exports" -Description: "Enable AWS RDS Log Exports." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when enabled_cloudwatch_logs_exports is null then 'alarm' - else 'ok' - end as status, - case - when enabled_cloudwatch_logs_exports is null then title || ' Log Exports feature is not enabled' - else title || ' Log Exports feature is enabled' - end as reason, - region, - account_id - from - aws_rds_db_instance - where - engine = 'mysql' or engine = 'mariadb' - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN enabled_cloudwatch_logs_exports IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN enabled_cloudwatch_logs_exports IS NULL THEN title || ' Log Exports feature is not enabled' + ELSE title || ' Log Exports feature is enabled' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance + WHERE + engine = 'mysql' OR engine = 'mariadb' Severity: low Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Observability -IntegrationType: - - aws_cloud_account +Title: Log Exports \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_performance_insights.yaml b/compliance/controls/baseline/aws/rds/aws_performance_insights.yaml index e2dec6942..87190bf89 100644 --- a/compliance/controls/baseline/aws/rds/aws_performance_insights.yaml +++ b/compliance/controls/baseline/aws/rds/aws_performance_insights.yaml @@ -1,31 +1,35 @@ +Description: Enable AWS RDS Performance Insights. ID: aws_performance_insights -Title: "Performance Insights" -Description: "Enable AWS RDS Performance Insights." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not performance_insights_enabled then 'alarm' - else 'ok' - end as status, - case - when not performance_insights_enabled then title || ' Performance Insights feature is not enabled' - else title || ' Performance Insights feature is enabled' - end as reason, - region, - account_id - from - aws_rds_db_instance - where - engine = 'aurora-mysql' or engine = 'aurora-postgresql' or engine = 'mysql' or engine = 'postgres' - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT performance_insights_enabled THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT performance_insights_enabled THEN title || ' Performance Insights feature is not enabled' + ELSE title || ' Performance Insights feature is enabled' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance + WHERE + engine = 'aurora-mysql' + OR engine = 'aurora-postgresql' + OR engine = 'mysql' + OR engine = 'postgres' Severity: low Tags: platform_score_cloud_service_name: @@ -36,5 +40,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: Performance Insights \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_automated_backups_enabled.yaml b/compliance/controls/baseline/aws/rds/aws_rds_automated_backups_enabled.yaml index 283727f64..4275c1352 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_automated_backups_enabled.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_automated_backups_enabled.yaml @@ -1,30 +1,31 @@ +Description: Ensure automated backups are enabled for RDS instances. This feature of Amazon RDS enables point-in-time recovery of your database instance. ID: aws_rds_automated_backups_enabled -Title: "RDS Automated Backups Enabled" -Description: "Ensure automated backups are enabled for RDS instances. This feature of Amazon RDS enables point-in-time recovery of your database instance." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when backup_retention_period < 1 then 'alarm' - else 'ok' - end as status, - case - when backup_retention_period < 1 then title || ' backups not enabled.' - else title || ' backups enabled.' - end as reason, + ListOfTables: + - aws_rds_db_instance + Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN backup_retention_period < 1 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN backup_retention_period < 1 THEN title || ' backups not enabled.' + ELSE title || ' backups enabled.' + END AS reason, region, account_id, backup_retention_period - from + FROM aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance - ListOfTables: - - aws_rds_db_instance - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -35,5 +36,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: RDS Automated Backups Enabled \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_db_instance_no_public_subnet.yaml b/compliance/controls/baseline/aws/rds/aws_rds_db_instance_no_public_subnet.yaml index 0ac4af632..200376806 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_db_instance_no_public_subnet.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_db_instance_no_public_subnet.yaml @@ -1,109 +1,109 @@ +Description: Ensure that no AWS RDS database instances are provisioned inside VPC public subnets. ID: aws_rds_db_instance_no_public_subnet -Title: "RDS Instance Not In Public Subnet" -Description: "Ensure that no AWS RDS database instances are provisioned inside VPC public subnets." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |+ - with subnets_with_explicit_route as ( - select - distinct (a ->> 'SubnetId') as all_sub - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a - where - a ->> 'SubnetId' is not null + ListOfTables: + - aws_rds_db_instance + - aws_rds_db_subnet_group + - aws_vpc_route_table + - aws_vpc_subnet + Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + WITH subnets_with_explicit_route AS ( + SELECT + DISTINCT (a ->> 'SubnetId') AS all_sub + FROM + aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a + WHERE + a ->> 'SubnetId' IS NOT NULL ), - public_subnets_with_explicit_route as ( - select - distinct a ->> 'SubnetId' as SubnetId - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a, - jsonb_array_elements(routes) as r - where + public_subnets_with_explicit_route AS ( + SELECT + DISTINCT a ->> 'SubnetId' AS SubnetId + FROM + aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE r ->> 'DestinationCidrBlock' = '0.0.0.0/0' - and ( - r ->> 'GatewayId' like 'igw-%' - or r ->> 'NatGatewayId' like 'nat-%' + AND ( + r ->> 'GatewayId' LIKE 'igw-%' + OR r ->> 'NatGatewayId' LIKE 'nat-%' ) - and a ->> 'SubnetId' is not null + AND a ->> 'SubnetId' IS NOT NULL ), - public_subnets_with_implicit_route as ( - select - distinct route_table_id, + public_subnets_with_implicit_route AS ( + SELECT + DISTINCT route_table_id, vpc_id, region - from - aws_vpc_route_table as t, - jsonb_array_elements(associations) as a, - jsonb_array_elements(routes) as r - where + FROM + aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE a ->> 'Main' = 'true' - and r ->> 'DestinationCidrBlock' = '0.0.0.0/0' - and ( - r ->> 'GatewayId' like 'igw-%' - or r ->> 'NatGatewayId' like 'nat-%' + AND r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND ( + r ->> 'GatewayId' LIKE 'igw-%' + OR r ->> 'NatGatewayId' LIKE 'nat-%' ) ), - subnet_accessibility as ( - select + subnet_accessibility AS ( + SELECT subnet_id, vpc_id, - case - when s.subnet_id in ( - select + CASE + WHEN s.subnet_id IN ( + SELECT SubnetId - from + FROM public_subnets_with_explicit_route - ) then 'private' - when p.SubnetId is not null or s.vpc_id in ( - select + ) THEN 'private' + WHEN p.SubnetId IS NOT NULL OR s.vpc_id IN ( + SELECT vpc_id - from + FROM public_subnets_with_implicit_route - ) then 'public' - else 'private' - end as access - from - aws_vpc_subnet as s - left join public_subnets_with_explicit_route as p on p.SubnetId = s.subnet_id + ) THEN 'public' + ELSE 'private' + END AS access + FROM + aws_vpc_subnet AS s + LEFT JOIN public_subnets_with_explicit_route AS p ON p.SubnetId = s.subnet_id ), - cluster_public_subnet as ( - select - distinct arn, - name as subnet_group_name - from + cluster_public_subnet AS ( + SELECT + DISTINCT arn, + name AS subnet_group_name + FROM aws_rds_db_subnet_group, - jsonb_array_elements(subnets) as s - left join subnet_accessibility as a on a.subnet_id = s ->> 'SubnetIdentifier' - where + jsonb_array_elements(subnets) AS s + LEFT JOIN subnet_accessibility AS a ON a.subnet_id = s ->> 'SubnetIdentifier' + WHERE a.access = 'public' ) - select - c.arn as resource, + SELECT + c.arn AS resource, og_resource_id, og_account_id, - case - when s.subnet_group_name is not null then 'alarm' - else 'ok' - end as status, - case - when s.subnet_group_name is not null then c.title || ' has public subnet.' - else c.title || ' has private subnet.' - end as reason, + CASE + WHEN s.subnet_group_name IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.subnet_group_name IS NOT NULL THEN c.title || ' has public subnet.' + ELSE c.title || ' has private subnet.' + END AS reason, region, account_id - from - aws_rds_db_instance as c - left join cluster_public_subnet as s on s.subnet_group_name = c.db_subnet_group_name; - - PrimaryTable: aws_rds_db_instance - ListOfTables: - - aws_rds_db_instance - - aws_rds_db_subnet_group - - aws_vpc_route_table - - aws_vpc_subnet - Parameters: [] + FROM + aws_rds_db_instance AS c + LEFT JOIN cluster_public_subnet AS s ON s.subnet_group_name = c.db_subnet_group_name; Severity: medium Tags: platform_score_cloud_service_name: @@ -114,5 +114,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: RDS Instance Not In Public Subnet \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_default_port.yaml b/compliance/controls/baseline/aws/rds/aws_rds_default_port.yaml index ca07c62cd..807dd9cf7 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_default_port.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_default_port.yaml @@ -1,13 +1,40 @@ +Description: Ensure Amazon RDS database instances aren't using the default ports. ID: aws_rds_default_port -Title: "RDS Default Port" -Description: "Ensure Amazon RDS database instances aren't using the default ports." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: "select\n db_instance_identifier as resource,\n og_account_id\n as og_account_id,\n og_resource_id as og_resource_id,\n case\n when\n \n endpoint_port = 3306 and engine in ('mysql', 'mariadb', 'aurora-mysql')\n or\n endpoint_port = 5431 and engine in ('postres', 'postgres-ee', 'aurora-postgresql')\n or\n endpoint_port = 1433 and engine like 'sqlserver%' or\n endpoint_port\n = 1521 and engine = 'oracle-ee'\n then 'alarm'\n else 'ok'\n end as status,\n\n case\n when \n endpoint_port = 3306 and engine in ('mysql', 'mariadb',\n 'aurora-mysql') or\n endpoint_port = 5431 and engine in ('postres', 'postgres-ee',\n 'aurora-postgresql') or\n endpoint_port = 1433 and engine like 'sqlserver%'\n or\n endpoint_port = 1521 and engine = 'oracle-ee'\n then title || ' port\n is set to default'\n else title || ' port is not set to default'\n end as\n reason,\n region,\n account_id\nfrom\n aws_rds_db_instance\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN + endpoint_port = 3306 AND engine IN ('mysql', 'mariadb', 'aurora-mysql') OR + endpoint_port = 5431 AND engine IN ('postres', 'postgres-ee', 'aurora-postgresql') OR + endpoint_port = 1433 AND engine LIKE 'sqlserver%' OR + endpoint_port = 1521 AND engine = 'oracle-ee' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + endpoint_port = 3306 AND engine IN ('mysql', 'mariadb', 'aurora-mysql') OR + endpoint_port = 5431 AND engine IN ('postres', 'postgres-ee', 'aurora-postgresql') OR + endpoint_port = 1433 AND engine LIKE 'sqlserver%' OR + endpoint_port = 1521 AND engine = 'oracle-ee' + THEN title || ' port is set to default' + ELSE title || ' port is not set to default' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance Severity: low Tags: platform_score_cloud_service_name: @@ -18,5 +45,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: RDS Default Port \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_desired_instance_type.yaml b/compliance/controls/baseline/aws/rds/aws_rds_desired_instance_type.yaml index eac180a04..3f5685c00 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_desired_instance_type.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_desired_instance_type.yaml @@ -1,36 +1,36 @@ +Description: Ensure fewer Amazon RDS instances than the established limit in your AWS account. ID: aws_rds_desired_instance_type -Title: "RDS Desired Instance Type" -Description: "Ensure fewer Amazon RDS instances than the established limit in your AWS account." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when '{{.awsRdsInstanceDesiredClasses}}' like '%' || class || '%' then 'ok' - else 'alarm' - end as status, - case - when '{{.awsRdsInstanceDesiredClasses}}' like '%' || class || '%' then title || ' RDS Instance is using desired class' - else title || ' RDS Instance is not using desired class' - end as reason, - region, - account_id - from - aws_rds_db_instance - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: - Key: awsRdsInstanceDesiredClasses Required: true + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN '{{.awsRdsInstanceDesiredClasses}}' LIKE '%' || class || '%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN '{{.awsRdsInstanceDesiredClasses}}' LIKE '%' || class || '%' THEN title || ' RDS Instance is using desired class' + ELSE title || ' RDS Instance is not using desired class' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance Severity: medium Tags: platform_score_cloud_service_name: - AWS Relational Database Service (RDS) score_service_name: - AWS Relational Database Service (RDS) -IntegrationType: - - aws_cloud_account +Title: RDS Desired Instance Type \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_encrypted_with_kms_customer_master_keys.yaml b/compliance/controls/baseline/aws/rds/aws_rds_encrypted_with_kms_customer_master_keys.yaml index 7dbb789e1..83e37c5fd 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_encrypted_with_kms_customer_master_keys.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_encrypted_with_kms_customer_master_keys.yaml @@ -1,40 +1,40 @@ +Description: Ensure RDS instances are encrypted with CMKs to have full control over encrypting and decrypting data. ID: aws_rds_encrypted_with_kms_customer_master_keys -Title: "RDS Encrypted With KMS Customer Master Keys" -Description: "Ensure RDS instances are encrypted with CMKs to have full control over encrypting and decrypting data." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_instance_identifier as resource, - v.og_resource_id, - v.og_account_id, - case - when storage_encrypted = 'false' then 'alarm' - when k.arn is null then 'alarm' - when k.key_manager = 'CUSTOMER' then 'ok' - else 'alarm' - end as status, - case - when storage_encrypted = 'false' then db_instance_identifier || ' is not encrypted' - when k.arn is null then db_instance_identifier || ' is not using a master key' - when k.key_manager = 'CUSTOMER' then db_instance_identifier || ' is using a customer master key' - else db_instance_identifier || ' is using a AWS-managed master key' - end as reason, - V.region, - V.account_id - from - aws_rds_db_instance as v - left join aws_kms_key as k on v.kms_key_id = k.arn - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_kms_key - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN storage_encrypted = 'false' THEN 'alarm' + WHEN k.arn IS NULL THEN 'alarm' + WHEN k.key_manager = 'CUSTOMER' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted = 'false' THEN db_instance_identifier || ' is not encrypted' + WHEN k.arn IS NULL THEN db_instance_identifier || ' is not using a master key' + WHEN k.key_manager = 'CUSTOMER' THEN db_instance_identifier || ' is using a customer master key' + ELSE db_instance_identifier || ' is using a AWS-managed master key' + END AS reason, + v.region, + v.account_id + FROM + aws_rds_db_instance AS v + LEFT JOIN aws_kms_key AS k ON v.kms_key_id = k.arn Severity: medium Tags: platform_score_cloud_service_name: - AWS Relational Database Service (RDS) score_service_name: - AWS Relational Database Service (RDS) -IntegrationType: - - aws_cloud_account +Title: RDS Encrypted With KMS Customer Master Keys \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_encryption_enabled.yaml b/compliance/controls/baseline/aws/rds/aws_rds_encryption_enabled.yaml index 6489fdf70..366d6d6f8 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_encryption_enabled.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_encryption_enabled.yaml @@ -1,29 +1,30 @@ +Description: Ensure encryption is setup for RDS instances to fulfill compliance requirements for data-at-rest encryption. ID: aws_rds_encryption_enabled -Title: "RDS Encryption Enabled" -Description: "Ensure encryption is setup for RDS instances to fulfill compliance requirements for data-at-rest encryption." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when storage_encrypted then 'ok' - else 'alarm' - end as status, - case - when storage_encrypted then title || ' encrypted at rest.' - else title || ' not encrypted at rest.' - end as reason, - region, - account_id - from - aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason, + region, + account_id + FROM + aws_rds_db_instance; Severity: high Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Unencrypted Storage -IntegrationType: - - aws_cloud_account +Title: RDS Encryption Enabled \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_event_notifications.yaml b/compliance/controls/baseline/aws/rds/aws_rds_event_notifications.yaml index 959e8d858..c9ddc6dfd 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_event_notifications.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_event_notifications.yaml @@ -1,33 +1,30 @@ +Description: Enable event notifications for RDS. ID: aws_rds_event_notifications -Title: "RDS Event Notifications" -Description: "Enable event notifications for RDS." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select distinct - a.og_account_id, - a.og_resource_id, - case - when s.arn - is null then 'alarm' - else 'ok' - end status, - case - when s.arn is - null then 'Event notifications is not enabled for Amazon RDS' - else 'Event - notifications is enabled for Amazon RDS' - end reason, - a.account_id - from - aws_account a - left join aws_rds_db_event_subscription s on s.og_account_id - = a.og_account_id - PrimaryTable: aws_account ListOfTables: - aws_account - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT DISTINCT + a.og_account_id, + a.og_resource_id, + CASE + WHEN s.arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.arn IS NULL THEN 'Event notifications is not enabled for Amazon RDS' + ELSE 'Event notifications is enabled for Amazon RDS' + END AS reason, + a.account_id + FROM aws_account a + LEFT JOIN aws_rds_db_event_subscription s + ON s.og_account_id = a.og_account_id Severity: high Tags: platform_score_cloud_service_name: @@ -38,5 +35,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: RDS Event Notifications \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_instance_counts.yaml b/compliance/controls/baseline/aws/rds/aws_rds_instance_counts.yaml index 6cf40ea28..a3b1ed2b2 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_instance_counts.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_instance_counts.yaml @@ -1,13 +1,33 @@ +Description: Ensure fewer Amazon RDS instances than the established limit in your AWS account. ID: aws_rds_instance_counts -Title: "RDS Instance Counts" -Description: "Ensure fewer Amazon RDS instances than the established limit in your AWS account." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: "select \n og_account_id as og_account_id,\n og_resource_id as og_resource_id,\n count(*) RDS_Instances_Count,\n case\n when count(*) > 10 then 'alarm'\n else 'ok'\n end status,\n case\n when count(*) > 10 then 'The limit the number of RDS instances exceeded'\n else 'The limit the number of RDS instances not exceeded'\n end reason,\n account_id\nfrom \n aws_rds_db_instance \ngroup by \n og_account_id, og_resource_id, account_id;\n" - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + COUNT(*) AS RDS_Instances_Count, + CASE + WHEN COUNT(*) > 10 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COUNT(*) > 10 THEN 'The limit the number of RDS instances exceeded' + ELSE 'The limit the number of RDS instances not exceeded' + END AS reason, + account_id + FROM + aws_rds_db_instance + GROUP BY + og_account_id, + og_resource_id, + account_id; Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +38,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Problem Identities -IntegrationType: - - aws_cloud_account +Title: RDS Instance Counts \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_multi_az.yaml b/compliance/controls/baseline/aws/rds/aws_rds_multi_az.yaml index d0b550d6d..3068214b5 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_multi_az.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_multi_az.yaml @@ -1,29 +1,30 @@ +Description: Ensure RDS instances are launched into Multi-AZ. ID: aws_rds_multi_az -Title: "RDS Multi-AZ" -Description: "Ensure RDS instances are launched into Multi-AZ." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 + ListOfTables: + - aws_rds_db_instance + Parameters: [] + PrimaryTable: aws_rds_db_instance QueryToExecute: | - select - db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when not multi_az then 'alarm' - else 'ok' - end as status, - case - when not multi_az then title || ' Multi-AZ feature is not enabled' - else title || ' Multi-AZ feature is enabled' - end as reason, + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN NOT multi_az THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT multi_az THEN title || ' Multi-AZ feature is not enabled' + ELSE title || ' Multi-AZ feature is enabled' + END AS reason, region, account_id - from + FROM aws_rds_db_instance - PrimaryTable: aws_rds_db_instance - ListOfTables: - - aws_rds_db_instance - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Lacking High Availability -IntegrationType: - - aws_cloud_account +Title: RDS Multi-AZ \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_public_snapshots.yaml b/compliance/controls/baseline/aws/rds/aws_rds_public_snapshots.yaml index 473f1ee87..f22d1f8a8 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_public_snapshots.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_public_snapshots.yaml @@ -1,13 +1,42 @@ +Description: Ensure that your Amazon RDS database snapshots are not accessible to all AWS accounts. ID: aws_rds_public_snapshots -Title: "Amazon RDS Public Snapshots" -Description: "Ensure that your Amazon RDS database snapshots are not accessible to all AWS accounts." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: "WITH restore_values AS (\n SELECT \n db_snapshot_identifier,\n \n attr ->> 'AttributeValues' AS attrValues \n FROM \n aws_rds_db_snapshot,\n \n jsonb_array_elements(db_snapshot_attributes) attr \n WHERE \n attr ->>\n 'AttributeName' = 'restore'\n)\nSELECT \n s.db_snapshot_identifier AS resource,\n\n s.og_account_id AS og_account_id,\n s.og_resource_id AS og_resource_id,\n\n CASE\n WHEN rv.attrValues LIKE '%all%'\n THEN 'alarm'\n ELSE 'ok'\n\n END AS status,\n CASE\n WHEN rv.attrValues LIKE '%all%'\n THEN s.db_snapshot_identifier\n || ' is open to all accounts'\n ELSE s.db_snapshot_identifier || ' is not open\n to all accounts'\n END AS reason\nFROM\n aws_rds_db_snapshot AS s\n LEFT JOIN\n restore_values AS rv ON s.db_snapshot_identifier = rv.db_snapshot_identifier\n" - PrimaryTable: aws_rds_db_snapshot ListOfTables: - aws_rds_db_snapshot Parameters: [] + PrimaryTable: aws_rds_db_snapshot + QueryToExecute: | + WITH restore_values AS ( + SELECT + db_snapshot_identifier, + attr ->> 'AttributeValues' AS attrValues + FROM + aws_rds_db_snapshot, + jsonb_array_elements(db_snapshot_attributes) attr + WHERE + attr ->> 'AttributeName' = 'restore' + ) + SELECT + s.db_snapshot_identifier AS resource, + s.og_account_id AS og_account_id, + s.og_resource_id AS og_resource_id, + CASE + WHEN rv.attrValues LIKE '%all%' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN rv.attrValues LIKE '%all%' + THEN s.db_snapshot_identifier || ' is open to all accounts' + ELSE s.db_snapshot_identifier || ' is not open to all accounts' + END AS reason + FROM + aws_rds_db_snapshot AS s + LEFT JOIN restore_values AS rv + ON s.db_snapshot_identifier = rv.db_snapshot_identifier Severity: high Tags: platform_score_cloud_service_name: @@ -18,5 +47,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Amazon RDS Public Snapshots \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rds_publicly_accessible.yaml b/compliance/controls/baseline/aws/rds/aws_rds_publicly_accessible.yaml index d07735e70..0f0375355 100644 --- a/compliance/controls/baseline/aws/rds/aws_rds_publicly_accessible.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rds_publicly_accessible.yaml @@ -1,29 +1,30 @@ +Description: Ensure RDS instances aren't public facing to minimise security risks. ID: aws_rds_publicly_accessible -Title: "RDS Publicly Accessible" -Description: "Ensure RDS instances aren't public facing to minimise security risks." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 + ListOfTables: + - aws_rds_db_instance + Parameters: [] + PrimaryTable: aws_rds_db_instance QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_resource_id, og_account_id, - case - when publicly_accessible then 'alarm' - else 'ok' - end status, - case - when publicly_accessible then title || ' publicly accessible.' - else title || ' not publicly accessible.' - end reason, + CASE + WHEN publicly_accessible THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN publicly_accessible THEN title || ' publicly accessible.' + ELSE title || ' not publicly accessible.' + END AS reason, region, account_id - from + FROM aws_rds_db_instance; - PrimaryTable: aws_rds_db_instance - ListOfTables: - - aws_rds_db_instance - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -34,5 +35,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: RDS Publicly Accessible \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_rotate_ssltls_certificates_for_database_instances.yaml b/compliance/controls/baseline/aws/rds/aws_rotate_ssltls_certificates_for_database_instances.yaml index 430367520..c1adf9839 100644 --- a/compliance/controls/baseline/aws/rds/aws_rotate_ssltls_certificates_for_database_instances.yaml +++ b/compliance/controls/baseline/aws/rds/aws_rotate_ssltls_certificates_for_database_instances.yaml @@ -1,30 +1,33 @@ +Description: Ensure that SSL/TLS certificates for RDS database instances are rotated according to the AWS schedule. ID: aws_rotate_ssltls_certificates_for_database_instances -Title: "Rotate SSL/TLS Certificates for Database Instances" -Description: "Ensure that SSL/TLS certificates for RDS database instances are rotated according to the AWS schedule." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - select - db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when ((c ->> 'ValidTill')::DATE - CURRENT_DATE)::INT < 15 then 'alarm' - else 'ok' - end as status, - case - when ((c ->> 'ValidTill')::DATE - CURRENT_DATE)::INT < 15 then title || ' certificate is going to expire in ' || ((c ->> 'ValidTill')::DATE - CURRENT_DATE)::TEXT || ' days' - else title || ' certificate is ok' || master_user_name - end as reason, - region, - account_id - from - aws_rds_db_instance, - json_array_elements(certificate::json) as c; - PrimaryTable: aws_rds_db_instance ListOfTables: - aws_rds_db_instance Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + SELECT + db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN ((c ->> 'ValidTill')::DATE - CURRENT_DATE)::INT < 15 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ((c ->> 'ValidTill')::DATE - CURRENT_DATE)::INT < 15 THEN + title || ' certificate is going to expire in ' || ((c ->> 'ValidTill')::DATE - CURRENT_DATE)::TEXT || ' days' + ELSE + title || ' certificate is ok' || master_user_name + END AS reason, + region, + account_id + FROM + aws_rds_db_instance, + json_array_elements(certificate::json) AS c; Severity: high Tags: platform_score_cloud_service_name: @@ -35,5 +38,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Unencrypted Traffic -IntegrationType: - - aws_cloud_account +Title: Rotate SSL/TLS Certificates for Database Instances \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_security_groups_events_subscriptions.yaml b/compliance/controls/baseline/aws/rds/aws_security_groups_events_subscriptions.yaml index 8d6388797..f5039271e 100644 --- a/compliance/controls/baseline/aws/rds/aws_security_groups_events_subscriptions.yaml +++ b/compliance/controls/baseline/aws/rds/aws_security_groups_events_subscriptions.yaml @@ -1,14 +1,34 @@ +Description: Enable Event Subscriptions for DB Security Groups Events. ID: aws_security_groups_events_subscriptions -Title: "Security Groups Events Subscriptions" -Description: "Enable Event Subscriptions for DB Security Groups Events." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: "select distinct\n a.og_account_id,\n a.og_resource_id,\n case\n when s.arn\n is null then 'alarm'\n else 'ok'\n end status,\n case\n when s.arn is\n null then 'Event subscription is not enabled for database security groups'\n else\n 'Event subscription is enabled for database security groups'\n end reason,\n\n a.account_id\nfrom \n aws_account a\n left join (select * from aws_rds_db_event_subscription\n where source_type = 'db-security-group') s on s.og_account_id = a.og_account_id\n" - PrimaryTable: aws_account ListOfTables: - aws_account - aws_rds_db_event_subscription Parameters: [] + PrimaryTable: aws_account + QueryToExecute: | + SELECT DISTINCT + a.og_account_id, + a.og_resource_id, + CASE + WHEN s.arn IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.arn IS NULL THEN 'Event subscription is not enabled for database security groups' + ELSE 'Event subscription is enabled for database security groups' + END AS reason, + a.account_id + FROM + aws_account a + LEFT JOIN ( + SELECT * FROM aws_rds_db_event_subscription + WHERE source_type = 'db-security-group' + ) s + ON s.og_account_id = a.og_account_id Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +39,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - General Efficiency -IntegrationType: - - aws_cloud_account +Title: Security Groups Events Subscriptions \ No newline at end of file diff --git a/compliance/controls/baseline/aws/rds/aws_use_aws_backup_service_in_use_for_amazon_rds.yaml b/compliance/controls/baseline/aws/rds/aws_use_aws_backup_service_in_use_for_amazon_rds.yaml index 9e6b36475..ea7fa4331 100644 --- a/compliance/controls/baseline/aws/rds/aws_use_aws_backup_service_in_use_for_amazon_rds.yaml +++ b/compliance/controls/baseline/aws/rds/aws_use_aws_backup_service_in_use_for_amazon_rds.yaml @@ -1,38 +1,40 @@ +Description: Ensure that Amazon Backup service is used to manage AWS RDS database snapshots. ID: aws_use_aws_backup_service_in_use_for_amazon_rds -Title: "Use AWS Backup Service in Use for Amazon RDS" -Description: "Ensure that Amazon Backup service is used to manage AWS RDS database snapshots." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: |- - with snapshots as ( - select distinct + ListOfTables: + - aws_rds_db_instance + - aws_rds_db_snapshot + Parameters: [] + PrimaryTable: aws_rds_db_instance + QueryToExecute: | + WITH snapshots AS ( + SELECT DISTINCT db_instance_identifier - from + FROM aws_rds_db_snapshot - where type = 'awsbackup' + WHERE + type = 'awsbackup' ) - select - r.db_instance_identifier as resource, - og_account_id as og_account_id, - og_resource_id as og_resource_id, - case - when b.db_instance_identifier is not null then 'ok' - else 'alarm' - end as status, - case - when b.db_instance_identifier is not null then r.title || ' has RDS database instance snapshots.' - else r.title || ' has no RDS database instance snapshots.' - end as reason, + SELECT + r.db_instance_identifier AS resource, + og_account_id AS og_account_id, + og_resource_id AS og_resource_id, + CASE + WHEN b.db_instance_identifier IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN b.db_instance_identifier IS NOT NULL THEN r.title || ' has RDS database instance snapshots.' + ELSE r.title || ' has no RDS database instance snapshots.' + END AS reason, r.region, r.account_id - from - aws_rds_db_instance as r - left join snapshots as b on r.db_instance_identifier = b.db_instance_identifier; - PrimaryTable: aws_rds_db_instance - ListOfTables: - - aws_rds_db_instance - - aws_rds_db_snapshot - Parameters: [] + FROM + aws_rds_db_instance AS r + LEFT JOIN snapshots AS b ON r.db_instance_identifier = b.db_instance_identifier; Severity: low Tags: platform_score_cloud_service_name: @@ -43,5 +45,4 @@ Tags: - AWS Relational Database Service (RDS) score_tags: - Missing Backup -IntegrationType: - - aws_cloud_account +Title: Use AWS Backup Service in Use for Amazon RDS \ No newline at end of file diff --git a/compliance/controls/baseline/aws/vpc/aws_managed_nat_gateway_in_use.yaml b/compliance/controls/baseline/aws/vpc/aws_managed_nat_gateway_in_use.yaml index e57b8fa5c..bef24b0ce 100644 --- a/compliance/controls/baseline/aws/vpc/aws_managed_nat_gateway_in_use.yaml +++ b/compliance/controls/baseline/aws/vpc/aws_managed_nat_gateway_in_use.yaml @@ -1,34 +1,38 @@ +Description: Ensure that the Managed NAT Gateway service is enabled for high availability (HA). ID: aws_managed_nat_gateway_in_use -Title: "Managed NAT Gateway in Use" -Description: "Ensure that the Managed NAT Gateway service is enabled for high availability (HA)." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 + ListOfTables: + - aws_vpc + - aws_vpc_nat_gateway + Parameters: [] + PrimaryTable: aws_vpc QueryToExecute: | - with available_nat_gateways as ( - select vpc_id, arn from aws_vpc_nat_gateway where state = 'available' + WITH available_nat_gateways AS ( + SELECT vpc_id, arn + FROM aws_vpc_nat_gateway + WHERE state = 'available' ) - select - v.arn as resource, + SELECT + v.arn AS resource, v.og_account_id, v.og_resource_id, - case - when ng.arn is not null then 'ok' - else 'alarm' - end as status, - case - when ng.arn is not null then v.vpc_id || ' is using Managed NAT Gateways.' - else v.vpc_id || ' is not using Managed NAT Gateways.' - end as reason, + CASE + WHEN ng.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ng.arn IS NOT NULL THEN v.vpc_id || ' is using Managed NAT Gateways.' + ELSE v.vpc_id || ' is not using Managed NAT Gateways.' + END AS reason, v.region, v.account_id - from - aws_vpc as v - left join available_nat_gateways as ng on ng.vpc_id = v.vpc_id - PrimaryTable: aws_vpc - ListOfTables: - - aws_vpc - - aws_vpc_nat_gateway - Parameters: [] + FROM + aws_vpc AS v + LEFT JOIN available_nat_gateways AS ng + ON ng.vpc_id = v.vpc_id Severity: medium Tags: platform_score_cloud_service_name: @@ -39,5 +43,4 @@ Tags: - AWS Virtual Private Cloud (VPC) score_tags: - Over Utilization -IntegrationType: - - aws_cloud_account +Title: Managed NAT Gateway in Use \ No newline at end of file diff --git a/compliance/controls/baseline/aws/vpc/aws_unrestricted_inbound_traffic_on_remote_server_administration_ports.yaml b/compliance/controls/baseline/aws/vpc/aws_unrestricted_inbound_traffic_on_remote_server_administration_ports.yaml index 2676549ce..91fa41ff9 100644 --- a/compliance/controls/baseline/aws/vpc/aws_unrestricted_inbound_traffic_on_remote_server_administration_ports.yaml +++ b/compliance/controls/baseline/aws/vpc/aws_unrestricted_inbound_traffic_on_remote_server_administration_ports.yaml @@ -1,14 +1,67 @@ +Description: Ensure that no Network ACL (NACL) allows unrestricted inbound traffic on TCP ports 22 and 3389. ID: aws_unrestricted_inbound_traffic_on_remote_server_administration_ports -Title: "Unrestricted Inbound Traffic on Remote Server Administration Ports" -Description: "Ensure that no Network ACL (NACL) allows unrestricted inbound traffic on TCP ports 22 and 3389." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: "with bad_rules as (\n select\n network_acl_id,\n count(*) as num_bad_rules\n from\n aws_vpc_network_acl,\n jsonb_array_elements(entries) as att\n where\n att ->> 'Egress' = 'false' -- as per aws egress = false indicates the ingress\n and (\n att ->> 'CidrBlock' = '0.0.0.0/0'\n or att ->> 'Ipv6CidrBlock' = '::/0'\n )\n and att ->> 'RuleAction' = 'allow'\n and (\n (\n att ->> 'Protocol' = '-1' -- all traffic\n and att ->> 'PortRange' is null\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 22\n and (att -> 'PortRange' ->> 'To') :: int >= 22\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 3389\n and (att -> 'PortRange' ->> 'To') :: int >= 3389\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n )\n group by\n network_acl_id\n)\nselect\n 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id as resource,\n acl.og_resource_id,\n acl.og_account_id,\n case\n when bad_rules.network_acl_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when bad_rules.network_acl_id is null then acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n else acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n end as reason,\n acl.region,\n acl.account_id\nfrom\n aws_vpc_network_acl as acl\n left join bad_rules on bad_rules.network_acl_id = acl.network_acl_id \n inner join aws_vpc vpc on acl.vpc_id = vpc.vpc_id\n where jsonb_array_length(acl.associations) > 0 and vpc.is_default = false;\n\n" - PrimaryTable: aws_vpc_network_acl ListOfTables: - aws_vpc - aws_vpc_network_acl Parameters: [] + PrimaryTable: aws_vpc_network_acl + QueryToExecute: | + WITH bad_rules AS ( + SELECT + network_acl_id, + COUNT(*) AS num_bad_rules + FROM + aws_vpc_network_acl, + jsonb_array_elements(entries) AS att + WHERE + att ->> 'Egress' = 'false' + AND ( + att ->> 'CidrBlock' = '0.0.0.0/0' + OR att ->> 'Ipv6CidrBlock' = '::/0' + ) + AND att ->> 'RuleAction' = 'allow' + AND ( + ( + att ->> 'Protocol' = '-1' + AND att ->> 'PortRange' IS NULL + ) + OR ( + (att -> 'PortRange' ->> 'From')::int <= 22 + AND (att -> 'PortRange' ->> 'To')::int >= 22 + AND att ->> 'Protocol' IN('6', '17') + ) + OR ( + (att -> 'PortRange' ->> 'From')::int <= 3389 + AND (att -> 'PortRange' ->> 'To')::int >= 3389 + AND att ->> 'Protocol' IN('6', '17') + ) + ) + GROUP BY + network_acl_id + ) + SELECT + 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id AS resource, + acl.og_resource_id, + acl.og_account_id, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason, + acl.region, + acl.account_id + FROM + aws_vpc_network_acl AS acl + LEFT JOIN bad_rules ON bad_rules.network_acl_id = acl.network_acl_id + INNER JOIN aws_vpc vpc ON acl.vpc_id = vpc.vpc_id + WHERE jsonb_array_length(acl.associations) > 0 AND vpc.is_default = FALSE; Severity: high Tags: platform_score_cloud_service_name: @@ -19,5 +72,4 @@ Tags: - AWS Virtual Private Cloud (VPC) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted Inbound Traffic on Remote Server Administration Ports \ No newline at end of file diff --git a/compliance/controls/baseline/aws/vpc/aws_unrestricted_network_acl_inbound_traffic.yaml b/compliance/controls/baseline/aws/vpc/aws_unrestricted_network_acl_inbound_traffic.yaml index 98e38157b..09f2bd7b7 100644 --- a/compliance/controls/baseline/aws/vpc/aws_unrestricted_network_acl_inbound_traffic.yaml +++ b/compliance/controls/baseline/aws/vpc/aws_unrestricted_network_acl_inbound_traffic.yaml @@ -1,39 +1,44 @@ +Description: Ensure that no Network ACL (NACL) allows inbound/ingress traffic from all ports. ID: aws_unrestricted_network_acl_inbound_traffic -Title: "Unrestricted Network ACL Inbound Traffic" -Description: "Ensure that no Network ACL (NACL) allows inbound/ingress traffic from all ports." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 + ListOfTables: + - aws_vpc_network_acl + Parameters: [] + PrimaryTable: aws_vpc_network_acl QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_account_id, og_resource_id, - case - when exists ( - select 1 - from jsonb_array_elements(entries) as e - where (e ->> 'Egress')::bool = false and e ->> 'PortRange' is null and e ->> 'CidrBlock' = '0.0.0.0/0' - and e ->> 'RuleAction' = 'allow' - ) then 'alarm' - else 'ok' - end as status, - case - when exists ( - select 1 - from jsonb_array_elements(entries) as e - where (e ->> 'Egress')::bool = false and e ->> 'PortRange' is null and e ->> 'CidrBlock' = '0.0.0.0/0' - and e ->> 'RuleAction' = 'allow' - ) then 'the access to the VPC subnets associated with the Network ACL (NACL) is not restricted.' - else 'the access to the VPC subnets associated with the Network ACL (NACL) is restricted.' - end as reason, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(entries) AS e + WHERE (e ->> 'Egress')::bool = FALSE + AND e ->> 'PortRange' IS NULL + AND e ->> 'CidrBlock' = '0.0.0.0/0' + AND e ->> 'RuleAction' = 'allow' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(entries) AS e + WHERE (e ->> 'Egress')::bool = FALSE + AND e ->> 'PortRange' IS NULL + AND e ->> 'CidrBlock' = '0.0.0.0/0' + AND e ->> 'RuleAction' = 'allow' + ) THEN 'the access to the VPC subnets associated with the Network ACL (NACL) is not restricted.' + ELSE 'the access to the VPC subnets associated with the Network ACL (NACL) is restricted.' + END AS reason, region, account_id - from + FROM aws_vpc_network_acl - PrimaryTable: aws_vpc_network_acl - ListOfTables: - - aws_vpc_network_acl - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -44,5 +49,4 @@ Tags: - AWS Virtual Private Cloud (VPC) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted Network ACL Inbound Traffic \ No newline at end of file diff --git a/compliance/controls/baseline/aws/vpc/aws_unrestricted_network_acl_outbound_traffic.yaml b/compliance/controls/baseline/aws/vpc/aws_unrestricted_network_acl_outbound_traffic.yaml index 769f8ca10..c5f1a2ccd 100644 --- a/compliance/controls/baseline/aws/vpc/aws_unrestricted_network_acl_outbound_traffic.yaml +++ b/compliance/controls/baseline/aws/vpc/aws_unrestricted_network_acl_outbound_traffic.yaml @@ -1,39 +1,44 @@ +Description: Ensure that no Network ACL (NACL) allows outbound/egress traffic to all ports. ID: aws_unrestricted_network_acl_outbound_traffic -Title: "Unrestricted Network ACL Outbound Traffic" -Description: "Ensure that no Network ACL (NACL) allows outbound/egress traffic to all ports." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 + ListOfTables: + - aws_vpc_network_acl + Parameters: [] + PrimaryTable: aws_vpc_network_acl QueryToExecute: | - select - arn as resource, + SELECT + arn AS resource, og_account_id, og_resource_id, - case - when exists ( - select 1 - from jsonb_array_elements(entries) as e - where (e ->> 'Egress')::bool = true and e ->> 'PortRange' is null and e ->> 'CidrBlock' = '0.0.0.0/0' - and e ->> 'RuleAction' = 'allow' - ) then 'alarm' - else 'ok' - end as status, - case - when exists ( - select 1 - from jsonb_array_elements(entries) as e - where (e ->> 'Egress')::bool = true and e ->> 'PortRange' is null and e ->> 'CidrBlock' = '0.0.0.0/0' - and e ->> 'RuleAction' = 'allow' - ) then 'the access to the VPC subnets associated with the Network ACL (NACL) is not restricted.' - else 'the access to the VPC subnets associated with the Network ACL (NACL) is restricted.' - end as reason, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(entries) AS e + WHERE (e ->> 'Egress')::bool = TRUE + AND e ->> 'PortRange' IS NULL + AND e ->> 'CidrBlock' = '0.0.0.0/0' + AND e ->> 'RuleAction' = 'allow' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(entries) AS e + WHERE (e ->> 'Egress')::bool = TRUE + AND e ->> 'PortRange' IS NULL + AND e ->> 'CidrBlock' = '0.0.0.0/0' + AND e ->> 'RuleAction' = 'allow' + ) THEN 'the access to the VPC subnets associated with the Network ACL (NACL) is not restricted.' + ELSE 'the access to the VPC subnets associated with the Network ACL (NACL) is restricted.' + END AS reason, region, account_id - from + FROM aws_vpc_network_acl - PrimaryTable: aws_vpc_network_acl - ListOfTables: - - aws_vpc_network_acl - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -44,5 +49,4 @@ Tags: - AWS Virtual Private Cloud (VPC) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: Unrestricted Network ACL Outbound Traffic \ No newline at end of file diff --git a/compliance/controls/baseline/aws/vpc/aws_vpc_endpoint_cross_account_access.yaml b/compliance/controls/baseline/aws/vpc/aws_vpc_endpoint_cross_account_access.yaml index d45a7d70d..545dc215c 100644 --- a/compliance/controls/baseline/aws/vpc/aws_vpc_endpoint_cross_account_access.yaml +++ b/compliance/controls/baseline/aws/vpc/aws_vpc_endpoint_cross_account_access.yaml @@ -1,13 +1,60 @@ +Description: Ensure Amazon VPC endpoints don't allow unknown cross account access. ID: aws_vpc_endpoint_cross_account_access -Title: "VPC Endpoint Cross Account Access" -Description: "Ensure Amazon VPC endpoints don't allow unknown cross account access." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: "SELECT \n vpc_endpoint_id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(policy::jsonb -> 'Statement') as s\n WHERE (s ->> 'Effect') = 'Allow' and ((s ->> 'Principal')::text = '\"*\"' or\n (s ->> 'Principal')::text = '{\"AWS\": \"*\"}')\n ) THEN 'alarm'\n WHEN '{{.awsTrustedAccounts}}' = '' THEN 'ok'\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(policy::jsonb -> 'Statement') as s\n WHERE (s ->> 'Effect') = 'Allow' and not('{{.awsTrustedAccounts}}' LIKE ('%'||((s ->> 'Principal')::text) || '%'))\n ) THEN 'alarm'\n ELSE 'ok'\n END AS status,\n CASE\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(policy::jsonb -> 'Statement') as s\n WHERE (s ->> 'Effect') = 'Allow' and ((s ->> 'Principal')::text = '\"*\"' or\n (s ->> 'Principal')::text = '{\"AWS\": \"*\"}')\n ) THEN vpc_endpoint_id || ' is publicly accessible' \n WHEN '{{.awsTrustedAccounts}}' = '' THEN 'trusted AWS accounts are not defined'\n WHEN EXISTS (\n SELECT 1 FROM jsonb_array_elements(policy::jsonb -> 'Statement') as s\n WHERE (s ->> 'Effect') = 'Allow' and not('{{.awsTrustedAccounts}}' LIKE ('%'||((s ->> 'Principal')::text) || '%'))\n ) THEN vpc_endpoint_id || ' is not configured to allow access only to trusted AWS accounts'\n ELSE vpc_endpoint_id || ' is configured to allow access only to trusted AWS accounts'\n END AS reason,\n region,\n account_id\nFROM \naws_vpc_endpoint\n" - PrimaryTable: aws_vpc_endpoint ListOfTables: - aws_vpc_endpoint Parameters: [] + PrimaryTable: aws_vpc_endpoint + QueryToExecute: | + SELECT + vpc_endpoint_id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(policy::jsonb -> 'Statement') AS s + WHERE (s ->> 'Effect') = 'Allow' + AND ( + (s ->> 'Principal')::text = '"*"' + OR (s ->> 'Principal')::text = '{"AWS": "*"}' + ) + ) THEN 'alarm' + WHEN '{{.awsTrustedAccounts}}' = '' THEN 'ok' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(policy::jsonb -> 'Statement') AS s + WHERE (s ->> 'Effect') = 'Allow' + AND NOT ('{{.awsTrustedAccounts}}' LIKE ('%'||((s ->> 'Principal')::text)||'%')) + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(policy::jsonb -> 'Statement') AS s + WHERE (s ->> 'Effect') = 'Allow' + AND ( + (s ->> 'Principal')::text = '"*"' + OR (s ->> 'Principal')::text = '{"AWS": "*"}' + ) + ) THEN vpc_endpoint_id || ' is publicly accessible' + WHEN '{{.awsTrustedAccounts}}' = '' THEN 'trusted AWS accounts are not defined' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(policy::jsonb -> 'Statement') AS s + WHERE (s ->> 'Effect') = 'Allow' + AND NOT ('{{.awsTrustedAccounts}}' LIKE ('%'||((s ->> 'Principal')::text)||'%')) + ) THEN vpc_endpoint_id || ' is not configured to allow access only to trusted AWS accounts' + ELSE vpc_endpoint_id || ' is configured to allow access only to trusted AWS accounts' + END AS reason, + region, + account_id + FROM + aws_vpc_endpoint Severity: medium Tags: platform_score_cloud_service_name: @@ -18,5 +65,4 @@ Tags: - AWS Virtual Private Cloud (VPC) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: VPC Endpoint Cross Account Access \ No newline at end of file diff --git a/compliance/controls/baseline/aws/vpc/aws_vpc_endpoint_exposed.yaml b/compliance/controls/baseline/aws/vpc/aws_vpc_endpoint_exposed.yaml index 5b3536f28..135c70044 100644 --- a/compliance/controls/baseline/aws/vpc/aws_vpc_endpoint_exposed.yaml +++ b/compliance/controls/baseline/aws/vpc/aws_vpc_endpoint_exposed.yaml @@ -1,32 +1,34 @@ +Description: Ensure Amazon VPC endpoints aren't exposed to everyone. ID: aws_vpc_endpoint_exposed -Title: "VPC Endpoint Exposed" -Description: "Ensure Amazon VPC endpoints aren't exposed to everyone." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 + ListOfTables: + - aws_vpc + - aws_vpc_endpoint + Parameters: [] + PrimaryTable: aws_vpc QueryToExecute: | - select - distinct arn as resource, + SELECT DISTINCT + arn AS resource, v.og_resource_id, v.og_account_id, - case - when p ->> 'Principal' = '*' or p ->> 'Principal' = '{"AWS": ["*"]}' then 'alarm' - else 'ok' - end as status, - case - when p ->> 'Principal' = '*' or p ->> 'Principal' = '{"AWS": ["*"]}' then v.vpc_id || ' endpoint is fully accessible..' - else v.vpc_id || ' endpoint is not fully accessible..' - end as reason, + CASE + WHEN p ->> 'Principal' = '*' OR p ->> 'Principal' = '{"AWS": ["*"]}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN p ->> 'Principal' = '*' OR p ->> 'Principal' = '{"AWS": ["*"]}' THEN v.vpc_id || ' endpoint is fully accessible.' + ELSE v.vpc_id || ' endpoint is not fully accessible.' + END AS reason, v.region, v.account_id - from - aws_vpc as v - left join aws_vpc_endpoint as e on v.vpc_id = e.vpc_id, - jsonb_array_elements(e.policy -> 'Statement') as p - PrimaryTable: aws_vpc - ListOfTables: - - aws_vpc - - aws_vpc_endpoint - Parameters: [] + FROM + aws_vpc AS v + LEFT JOIN + aws_vpc_endpoint AS e ON v.vpc_id = e.vpc_id, + jsonb_array_elements(e.policy -> 'Statement') AS p Severity: medium Tags: platform_score_cloud_service_name: @@ -37,5 +39,4 @@ Tags: - AWS Virtual Private Cloud (VPC) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: VPC Endpoint Exposed \ No newline at end of file diff --git a/compliance/controls/baseline/aws/vpc/aws_vpc_endpoints_in_use.yaml b/compliance/controls/baseline/aws/vpc/aws_vpc_endpoints_in_use.yaml index 2cbc71d50..a3ad2c20b 100644 --- a/compliance/controls/baseline/aws/vpc/aws_vpc_endpoints_in_use.yaml +++ b/compliance/controls/baseline/aws/vpc/aws_vpc_endpoints_in_use.yaml @@ -1,14 +1,37 @@ +Description: Ensure that VPC endpoints are being used to connect your VPC to another AWS cloud service. ID: aws_vpc_endpoints_in_use -Title: "VPC Endpoints In Use" -Description: "Ensure that VPC endpoints are being used to connect your VPC to another AWS cloud service." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: "SELECT \n v.vpc_id as resource,\n v.og_resource_id,\n v.og_account_id,\n CASE\n WHEN EXISTS (\n select 1 from aws_vpc_endpoint as e where e.vpc_id = v.vpc_id\n ) THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN EXISTS (\n select 1 from aws_vpc_endpoint as e where e.vpc_id = v.vpc_id\n ) THEN v.vpc_id || ' has VPC endpoints'\n ELSE ' there are no Amazon VPC endpoints deployed for ' || v.vpc_id\n END AS reason,\n v.region,\n v.account_id\nFROM \naws_vpc as v\nWHERE is_default = false;\n" - PrimaryTable: aws_vpc ListOfTables: - aws_vpc - aws_vpc_endpoint Parameters: [] + PrimaryTable: aws_vpc + QueryToExecute: | + SELECT + v.vpc_id AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 FROM aws_vpc_endpoint AS e WHERE e.vpc_id = v.vpc_id + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 FROM aws_vpc_endpoint AS e WHERE e.vpc_id = v.vpc_id + ) THEN v.vpc_id || ' has VPC endpoints' + ELSE 'there are no Amazon VPC endpoints deployed for ' || v.vpc_id + END AS reason, + v.region, + v.account_id + FROM + aws_vpc AS v + WHERE + is_default = FALSE; Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +42,4 @@ Tags: - AWS Virtual Private Cloud (VPC) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: VPC Endpoints In Use \ No newline at end of file diff --git a/compliance/controls/baseline/aws/vpc/aws_vpc_flow_logs_enabled.yaml b/compliance/controls/baseline/aws/vpc/aws_vpc_flow_logs_enabled.yaml index e7a2864c3..62268b625 100644 --- a/compliance/controls/baseline/aws/vpc/aws_vpc_flow_logs_enabled.yaml +++ b/compliance/controls/baseline/aws/vpc/aws_vpc_flow_logs_enabled.yaml @@ -1,33 +1,37 @@ +Description: Ensure VPC flow logging is enabled in all VPCs. ID: aws_vpc_flow_logs_enabled -Title: "VPC Flow Logs Enabled" -Description: "Ensure VPC flow logging is enabled in all VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 + ListOfTables: + - aws_vpc + - aws_vpc_flow_log + Parameters: [] + PrimaryTable: aws_vpc QueryToExecute: | - select - distinct arn as resource, + SELECT + DISTINCT arn AS resource, v.og_resource_id, v.og_account_id, - case - when v.account_id <> v.owner_id then 'skip' - when f.resource_id is not null then 'ok' - else 'alarm' - end as status, - case - when v.account_id <> v.owner_id then vpc_id || ' is a shared VPC.' - when f.resource_id is not null then vpc_id || ' flow logging enabled.' - else vpc_id || ' flow logging disabled.' - end as reason, + CASE + WHEN v.account_id <> v.owner_id THEN 'skip' + WHEN f.resource_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.account_id <> v.owner_id THEN vpc_id || ' is a shared VPC.' + WHEN f.resource_id IS NOT NULL THEN vpc_id || ' flow logging enabled.' + ELSE vpc_id || ' flow logging disabled.' + END AS reason, v.region, v.account_id - from - aws_vpc as v - left join aws_vpc_flow_log as f on v.vpc_id = f.resource_id; - PrimaryTable: aws_vpc - ListOfTables: - - aws_vpc - - aws_vpc_flow_log - Parameters: [] + FROM + aws_vpc AS v + LEFT JOIN + aws_vpc_flow_log AS f + ON + v.vpc_id = f.resource_id; Severity: low Tags: platform_score_cloud_service_name: @@ -38,5 +42,4 @@ Tags: - AWS Virtual Private Cloud (VPC) score_tags: - Unencrypted Traffic -IntegrationType: - - aws_cloud_account +Title: VPC Flow Logs Enabled \ No newline at end of file diff --git a/compliance/controls/baseline/aws/vpc/aws_vpc_peering_connections_to_accounts_outside_aws_organization.yaml b/compliance/controls/baseline/aws/vpc/aws_vpc_peering_connections_to_accounts_outside_aws_organization.yaml index bd0ecfcbe..126152826 100644 --- a/compliance/controls/baseline/aws/vpc/aws_vpc_peering_connections_to_accounts_outside_aws_organization.yaml +++ b/compliance/controls/baseline/aws/vpc/aws_vpc_peering_connections_to_accounts_outside_aws_organization.yaml @@ -1,15 +1,51 @@ +Description: Ensure VPC peering communication is only between AWS accounts, members of the same AWS Organization. ID: aws_vpc_peering_connections_to_accounts_outside_aws_organization -Title: "VPC Peering Connections To Accounts Outside AWS Organization" -Description: "Ensure VPC peering communication is only between AWS accounts, members of the same AWS Organization." +IntegrationType: + - aws_cloud_account Query: Engine: odysseus-v0.0.1 - QueryToExecute: "WITH account_org AS (\n SELECT \n og_account_id,\n organization_id\n FROM\n aws_account\n), vpc_org AS (\n SELECT\n vpc.vpc_id,\n ao.organization_id as org\n FROM\n aws_vpc AS vpc\n LEFT JOIN account_org AS ao ON ao.og_account_id = vpc.og_account_id\n)\n\nSELECT \n c.id as resource,\n og_resource_id,\n og_account_id,\n CASE\n WHEN accepter_org.org = requester_org.org THEN 'ok'\n ELSE 'alarm'\n END AS status,\n CASE\n WHEN accepter_org.org = requester_org.org THEN c.id || ' connections are ok'\n ELSE c.id || ' connects to accounts outside organization'\n END AS reason,\n region,\n account_id\nFROM \n aws_vpc_peering_connection AS c\n LEFT JOIN vpc_org AS accepter_org ON c.accepter_vpc_id = accepter_org.vpc_id\n LEFT JOIN vpc_org AS requester_org ON c.requester_vpc_id = accepter_org.vpc_id\nWHERE\n status_code = 'active'\n" - PrimaryTable: aws_vpc_peering_connection ListOfTables: - aws_account - aws_vpc - aws_vpc_peering_connection Parameters: [] + PrimaryTable: aws_vpc_peering_connection + QueryToExecute: | + WITH account_org AS ( + SELECT + og_account_id, + organization_id + FROM + aws_account + ), vpc_org AS ( + SELECT + vpc.vpc_id, + ao.organization_id AS org + FROM + aws_vpc AS vpc + LEFT JOIN account_org AS ao ON ao.og_account_id = vpc.og_account_id + ) + + SELECT + c.id AS resource, + og_resource_id, + og_account_id, + CASE + WHEN accepter_org.org = requester_org.org THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN accepter_org.org = requester_org.org THEN c.id || ' connections are ok' + ELSE c.id || ' connects to accounts outside organization' + END AS reason, + region, + account_id + FROM + aws_vpc_peering_connection AS c + LEFT JOIN vpc_org AS accepter_org ON c.accepter_vpc_id = accepter_org.vpc_id + LEFT JOIN vpc_org AS requester_org ON c.requester_vpc_id = accepter_org.vpc_id + WHERE + status_code = 'active' Severity: medium Tags: platform_score_cloud_service_name: @@ -20,5 +56,4 @@ Tags: - AWS Virtual Private Cloud (VPC) score_tags: - Exposed Endpoints -IntegrationType: - - aws_cloud_account +Title: VPC Peering Connections To Accounts Outside AWS Organization \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_app_tier_customer_managed_key_in_use.yaml b/compliance/controls/baseline/azure/KeyVault/azure_app_tier_customer_managed_key_in_use.yaml index 7271554ad..0c1cb830e 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_app_tier_customer_managed_key_in_use.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_app_tier_customer_managed_key_in_use.yaml @@ -1,45 +1,51 @@ +Description: Ensure that a Customer-Managed Key is created for your Azure cloud application tier. ID: azure_app_tier_customer_managed_key_in_use -Title: "App Tier Customer-Managed Key In Use" -Description: "Ensure that a Customer-Managed Key is created for your Azure cloud application tier." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_key_vault_key + - azure_subscription + Parameters: + - Key: azureAppTierTags + Required: true + PrimaryTable: azure_subscription QueryToExecute: | - select - display_name as resource, + SELECT + display_name AS resource, sub.og_resource_id, sub.og_account_id, - case - when exists( - select 1 from azure_key_vault_key as k where (k.subscription_id = sub.subscription_id) and - k.tags is not null and - (k.tags::text like '%' || REPLACE(REPLACE(( + CASE + WHEN EXISTS( + SELECT 1 + FROM azure_key_vault_key AS k + WHERE (k.subscription_id = sub.subscription_id) + AND k.tags IS NOT NULL + AND (k.tags::text LIKE '%' || REPLACE(REPLACE(( SELECT jsonb_object_agg(key, value)::text FROM jsonb_each_text('{{.azureAppTierTags}}'::jsonb) - ), '{', ''), '}', '') || '%') and enabled - ) then 'ok' - else 'alarm' - end as status, - case - when exists( - select 1 from azure_key_vault_key as k where (k.subscription_id = sub.subscription_id) and - k.tags is not null and - (k.tags::text like '%' || REPLACE(REPLACE(( + ), '{', ''), '}', '') || '%') + AND enabled + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS( + SELECT 1 + FROM azure_key_vault_key AS k + WHERE (k.subscription_id = sub.subscription_id) + AND k.tags IS NOT NULL + AND (k.tags::text LIKE '%' || REPLACE(REPLACE(( SELECT jsonb_object_agg(key, value)::text FROM jsonb_each_text('{{.azureAppTierTags}}'::jsonb) - ), '{', ''), '}', '') || '%') and enabled - ) then 'subscription has an app-tier cmk' - else 'subscription does not have any app-tier cmk' - end as reason, - sub.display_name as subscription - from - azure_subscription as sub - PrimaryTable: azure_subscription - ListOfTables: - - azure_key_vault_key - - azure_subscription - Parameters: - - Key: azureAppTierTags - Required: true + ), '{', ''), '}', '') || '%') + AND enabled + ) THEN 'subscription has an app-tier cmk' + ELSE 'subscription does not have any app-tier cmk' + END AS reason, + sub.display_name AS subscription + FROM azure_subscription AS sub Severity: high Tags: platform_score_cloud_service_name: @@ -50,5 +56,4 @@ Tags: - Azure KeyVault score_tags: - Unencrypted Storage -IntegrationType: - - azure_subscription +Title: App Tier Customer-Managed Key In Use \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_check_for_allowed_certificate_key_types.yaml b/compliance/controls/baseline/azure/KeyVault/azure_check_for_allowed_certificate_key_types.yaml index 3f20d190a..cf6fdb133 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_check_for_allowed_certificate_key_types.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_check_for_allowed_certificate_key_types.yaml @@ -1,33 +1,34 @@ +Description: Ensure that Azure Key Vault certificates are using the appropriate key type(s). ID: azure_check_for_allowed_certificate_key_types -Title: "Check for Allowed Certificate Key Types" -Description: "Ensure that Azure Key Vault certificates are using the appropriate key type(s)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - k.og_resource_id, - k.og_account_id, - case - when '{{.azureAllowedKeyTypes}}' ILIKE '%' || k.key_type || '%' then 'alarm' - else 'ok' - end as status, - case - when '{{.azureAllowedKeyTypes}}' ILIKE '%' || k.key_type || '%' then k.key_type || ' type is not allowed' - else k.key_type || ' is allowed' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault_key as k - left join azure_subscription as sub on k.subscription_id = sub.subscription_id - PrimaryTable: azure_key_vault_key ListOfTables: - azure_key_vault_key - azure_subscription Parameters: - Key: azureAllowedKeyTypes Required: true + PrimaryTable: azure_key_vault_key + QueryToExecute: | + SELECT + name AS resource, + k.og_resource_id, + k.og_account_id, + CASE + WHEN '{{.azureAllowedKeyTypes}}' ILIKE '%' || k.key_type || '%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN '{{.azureAllowedKeyTypes}}' ILIKE '%' || k.key_type || '%' THEN k.key_type || ' type is not allowed' + ELSE k.key_type || ' is allowed' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_key AS k + LEFT JOIN azure_subscription AS sub ON k.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -38,5 +39,4 @@ Tags: - Azure KeyVault score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Check for Allowed Certificate Key Types \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_check_for_azure_key_vault_keys_expiration_date.yaml b/compliance/controls/baseline/azure/KeyVault/azure_check_for_azure_key_vault_keys_expiration_date.yaml index 48de019fc..d021379d6 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_check_for_azure_key_vault_keys_expiration_date.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_check_for_azure_key_vault_keys_expiration_date.yaml @@ -1,16 +1,53 @@ +Description: Ensure that your Azure Key Vault encryption keys are renewed prior to their expiration date. ID: azure_check_for_azure_key_vault_keys_expiration_date -Title: "Check for Azure Key Vault Keys Expiration Date" -Description: "Ensure that your Azure Key Vault encryption keys are renewed prior to their expiration date." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: "select\n name as resource,\n k.og_resource_id,\n k.og_account_id,\n case\n when expires_at is null then 'skip'\n when '{{.azureKeyVaultKeyExpirationDateDays}}' = '' then\n case \n when expires_at - now() > '30 days'::interval then 'ok'\n else 'alarm'\n end\n else\n case\n when expires_at - now() > '{{.azureKeyVaultKeyExpirationDateDays}} days'::interval then 'ok'\n else 'alarm'\n end\n end as status,\n case\n when expires_at is null then 'expires at is not specified'\n when expires_at < now() then 'key has been expired'\n when '{{.azureKeyVaultKeyExpirationDateDays}}' = '' then\n case\n when expires_at - now() > '30 days'::interval then 'key does not expire soon'\n else 'key expires soon'\n end\n else\n case\n when expires_at - now() > '{{.azureKeyVaultKeyExpirationDateDays}} days'::interval then 'key does not expire soon'\n else 'key expires soon'\n end\n end as reason,\n resource_group as resource_group,\n sub.display_name as subscription\nfrom\n azure_key_vault_key as k\n left join azure_subscription as sub on k.subscription_id = sub.subscription_id\n" - PrimaryTable: azure_key_vault_key ListOfTables: - azure_key_vault_key - azure_subscription Parameters: - Key: azureKeyVaultKeyExpirationDateDays Required: true + PrimaryTable: azure_key_vault_key + QueryToExecute: | + SELECT + name AS resource, + k.og_resource_id, + k.og_account_id, + CASE + WHEN expires_at IS NULL THEN 'skip' + WHEN '{{.azureKeyVaultKeyExpirationDateDays}}' = '' THEN + CASE + WHEN expires_at - now() > '30 days'::interval THEN 'ok' + ELSE 'alarm' + END + ELSE + CASE + WHEN expires_at - now() > '{{.azureKeyVaultKeyExpirationDateDays}} days'::interval THEN 'ok' + ELSE 'alarm' + END + END AS status, + CASE + WHEN expires_at IS NULL THEN 'expires at is not specified' + WHEN expires_at < now() THEN 'key has been expired' + WHEN '{{.azureKeyVaultKeyExpirationDateDays}}' = '' THEN + CASE + WHEN expires_at - now() > '30 days'::interval THEN 'key does not expire soon' + ELSE 'key expires soon' + END + ELSE + CASE + WHEN expires_at - now() > '{{.azureKeyVaultKeyExpirationDateDays}} days'::interval THEN 'key does not expire soon' + ELSE 'key expires soon' + END + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_key AS k + LEFT JOIN azure_subscription AS sub ON k.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -21,5 +58,4 @@ Tags: - Azure KeyVault score_tags: - Problem Identities -IntegrationType: - - azure_subscription +Title: Check for Azure Key Vault Keys Expiration Date \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_check_for_azure_key_vault_secrets_expiration_date.yaml b/compliance/controls/baseline/azure/KeyVault/azure_check_for_azure_key_vault_secrets_expiration_date.yaml index c2f5318a9..59e88f82c 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_check_for_azure_key_vault_secrets_expiration_date.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_check_for_azure_key_vault_secrets_expiration_date.yaml @@ -1,34 +1,35 @@ +Description: Ensure that your Azure Key Vault secrets are renewed prior to their expiration date. ID: azure_check_for_azure_key_vault_secrets_expiration_date -Title: "Check for Azure Key Vault Secrets Expiration Date" -Description: "Ensure that your Azure Key Vault secrets are renewed prior to their expiration date." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - s.name as resource, - s.og_resource_id, - s.og_account_id, - case - when now() + '{{.azureCmkSecretExpireDays}} days'::interval < expires_at then 'ok' - else 'alarm' - end as status, - case - when expires_at < now() then 'secret has been expired' - when now() + '{{.azureCmkSecretExpireDays}} days'::interval < expires_at then 'secret is not going to be expired soon' - else 'secret is going to be expired soon' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault_secret as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - PrimaryTable: azure_key_vault_secret ListOfTables: - azure_key_vault_secret - azure_subscription Parameters: - Key: azureCmkSecretExpireDays Required: true + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + SELECT + s.name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN NOW() + '{{.azureCmkSecretExpireDays}} days'::interval < expires_at THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN expires_at < NOW() THEN 'secret has been expired' + WHEN NOW() + '{{.azureCmkSecretExpireDays}} days'::interval < expires_at THEN 'secret is not going to be expired soon' + ELSE 'secret is going to be expired soon' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_secret AS s + LEFT JOIN azure_subscription AS sub ON s.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -39,5 +40,4 @@ Tags: - Azure KeyVault score_tags: - Problem Identities -IntegrationType: - - azure_subscription +Title: Check for Azure Key Vault Secrets Expiration Date \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_check_for_certificate_minimum_key_size.yaml b/compliance/controls/baseline/azure/KeyVault/azure_check_for_certificate_minimum_key_size.yaml index 58606be50..84b48b308 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_check_for_certificate_minimum_key_size.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_check_for_certificate_minimum_key_size.yaml @@ -1,35 +1,39 @@ +Description: Ensure that Azure Key Vault RSA certificates are using the appropriate key size. ID: azure_check_for_certificate_minimum_key_size -Title: "Check for Certificate Minimum Key Size" -Description: "Ensure that Azure Key Vault RSA certificates are using the appropriate key size." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - k.name as resource, - k.og_resource_id, - k.og_account_id, - case - when not (key_type = 'RSA') then 'skip' - when key_size::INT < '{{.azureRsaCertificateMinSize}}'::INT then 'alarm' - else 'ok' - end as status, - case - when not (key_type = 'RSA') then 'skip' - when key_size::INT < '{{.azureRsaCertificateMinSize}}'::INT then 'alarm' - else 'RSA certificate size is ok' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault_key as k - left join azure_subscription as sub on k.subscription_id = sub.subscription_id - PrimaryTable: azure_key_vault_key ListOfTables: - azure_key_vault_key - azure_subscription Parameters: - Key: azureRsaCertificateMinSize Required: true + PrimaryTable: azure_key_vault_key + QueryToExecute: | + SELECT + k.name AS resource, + k.og_resource_id, + k.og_account_id, + CASE + WHEN NOT (key_type = 'RSA') THEN 'skip' + WHEN key_size::INT < '{{.azureRsaCertificateMinSize}}'::INT THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (key_type = 'RSA') THEN 'skip' + WHEN key_size::INT < '{{.azureRsaCertificateMinSize}}'::INT THEN 'alarm' + ELSE 'RSA certificate size is ok' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_key AS k + LEFT JOIN + azure_subscription AS sub + ON + k.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -40,5 +44,4 @@ Tags: - Azure KeyVault score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Check for Certificate Minimum Key Size \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_check_for_key_vault_full_administrator_permissions.yaml b/compliance/controls/baseline/azure/KeyVault/azure_check_for_key_vault_full_administrator_permissions.yaml index 76f0ca941..26baf3ca4 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_check_for_key_vault_full_administrator_permissions.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_check_for_key_vault_full_administrator_permissions.yaml @@ -1,60 +1,79 @@ +Description: Ensure that no Azure user, group or application has full permissions to access and manage Key Vaults. ID: azure_check_for_key_vault_full_administrator_permissions -Title: "Check for Key Vault Full Administrator Permissions" -Description: "Ensure that no Azure user, group or application has full permissions to access and manage Key Vaults." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_key_vault + - azure_subscription + Parameters: [] + PrimaryTable: azure_key_vault QueryToExecute: | WITH secrets AS ( - SELECT unnest(ARRAY ['Get','List','Set','Delete','Recover','Backup','Restore','Purge']) AS s + SELECT UNNEST(ARRAY ['Get', 'List', 'Set', 'Delete', 'Recover', 'Backup', 'Restore', 'Purge']) AS s ), keys AS ( - SELECT unnest(ARRAY ['Get','List','Update','Create','Import','Delete','Recover','Backup','Restore','Decrypt', - 'Encrypt','UnwrapKey','WrapKey','Verify','Sign','Purge']) AS k + SELECT UNNEST(ARRAY ['Get', 'List', 'Update', 'Create', 'Import', 'Delete', 'Recover', 'Backup', 'Restore', 'Decrypt', + 'Encrypt', 'UnwrapKey', 'WrapKey', 'Verify', 'Sign', 'Purge']) AS k ), certificates AS ( - SELECT unnest(ARRAY ['Get','List', - 'Update','Create','Import','Delete','Recover','Backup','Restore','ManageContacts', - 'ManageIssuers','GetIssuers','ListIssuers','SetIssuers','DeleteIssuers','Purge']) AS c + SELECT UNNEST(ARRAY ['Get', 'List', 'Update', 'Create', 'Import', 'Delete', 'Recover', 'Backup', 'Restore', + 'ManageContacts', 'ManageIssuers', 'GetIssuers', 'ListIssuers', 'SetIssuers', 'DeleteIssuers', 'Purge']) AS c ) - select - v.name as resource, + SELECT + v.name AS resource, v.og_resource_id, v.og_account_id, - case - when EXISTS ( - SELECT 1 FROM jsonb_array_elements(access_policies) as p - WHERE (SELECT COUNT(*) FROM secrets AS s WHERE lower(p ->> 'permissionsSecrets') ILIKE '%' || lower(s.s) || '%') = (SELECT COUNT(*) FROM secrets) - ) and EXISTS ( - SELECT 1 FROM jsonb_array_elements(access_policies) as p - WHERE (SELECT COUNT(*) FROM keys AS k WHERE lower(p ->> 'permissionsKeys') ILIKE '%' || lower(k.k) || '%') = (SELECT COUNT(*) FROM keys) - ) and EXISTS ( - SELECT 1 FROM jsonb_array_elements(access_policies) as p - WHERE (SELECT COUNT(*) FROM certificates AS c WHERE lower(p ->> 'permissionsCertificates') ILIKE '%' || lower(c.c) || '%') = (SELECT COUNT(*) FROM certificates) - ) then 'alarm' - else 'ok' - end as status, - case - when EXISTS ( - SELECT 1 FROM jsonb_array_elements(access_policies) as p - WHERE (SELECT COUNT(*) FROM secrets AS s WHERE lower(p ->> 'permissionsSecrets') ILIKE '%' || lower(s.s) || '%') = (SELECT COUNT(*) FROM secrets) - ) and EXISTS ( - SELECT 1 FROM jsonb_array_elements(access_policies) as p - WHERE (SELECT COUNT(*) FROM keys AS k WHERE lower(p ->> 'permissionsKeys') ILIKE '%' || lower(k.k) || '%') = (SELECT COUNT(*) FROM keys) - ) and EXISTS ( - SELECT 1 FROM jsonb_array_elements(access_policies) as p - WHERE (SELECT COUNT(*) FROM certificates AS c WHERE lower(p ->> 'permissionsCertificates') ILIKE '%' || lower(c.c) || '%') = (SELECT COUNT(*) FROM certificates) - ) then v.name || ' has full permissions to access and manage the selected Azure Key Vault.' - else v.name || ' does not have full permissions to access and manage the selected Azure Key Vault.' - end as reason, - v.resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault as v - left join azure_subscription as sub on v.subscription_id = sub.subscription_id - PrimaryTable: azure_key_vault - ListOfTables: - - azure_key_vault - - azure_subscription - Parameters: [] + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies) AS p + WHERE (SELECT COUNT(*) + FROM secrets AS s + WHERE LOWER(p ->> 'permissionsSecrets') ILIKE '%' || LOWER(s.s) || '%') = (SELECT COUNT(*) FROM secrets) + ) AND EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies) AS p + WHERE (SELECT COUNT(*) + FROM keys AS k + WHERE LOWER(p ->> 'permissionsKeys') ILIKE '%' || LOWER(k.k) || '%') = (SELECT COUNT(*) FROM keys) + ) AND EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies) AS p + WHERE (SELECT COUNT(*) + FROM certificates AS c + WHERE LOWER(p ->> 'permissionsCertificates') ILIKE '%' || LOWER(c.c) || '%') = (SELECT COUNT(*) FROM certificates) + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies) AS p + WHERE (SELECT COUNT(*) + FROM secrets AS s + WHERE LOWER(p ->> 'permissionsSecrets') ILIKE '%' || LOWER(s.s) || '%') = (SELECT COUNT(*) FROM secrets) + ) AND EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies) AS p + WHERE (SELECT COUNT(*) + FROM keys AS k + WHERE LOWER(p ->> 'permissionsKeys') ILIKE '%' || LOWER(k.k) || '%') = (SELECT COUNT(*) FROM keys) + ) AND EXISTS ( + SELECT 1 + FROM jsonb_array_elements(access_policies) AS p + WHERE (SELECT COUNT(*) + FROM certificates AS c + WHERE LOWER(p ->> 'permissionsCertificates') ILIKE '%' || LOWER(c.c) || '%') = (SELECT COUNT(*) FROM certificates) + ) THEN v.name || ' has full permissions to access and manage the selected Azure Key Vault.' + ELSE v.name || ' does not have full permissions to access and manage the selected Azure Key Vault.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault AS v + LEFT JOIN azure_subscription AS sub + ON v.subscription_id = sub.subscription_id Severity: high Tags: platform_score_cloud_service_name: @@ -65,5 +84,4 @@ Tags: - Azure KeyVault score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Check for Key Vault Full Administrator Permissions \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_check_for_sufficient_certificate_auto_renewal_period.yaml b/compliance/controls/baseline/azure/KeyVault/azure_check_for_sufficient_certificate_auto_renewal_period.yaml index 518118e90..76b814ae4 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_check_for_sufficient_certificate_auto_renewal_period.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_check_for_sufficient_certificate_auto_renewal_period.yaml @@ -1,34 +1,37 @@ +Description: Ensure there is a sufficient period configured for the SSL certificates auto-renewal. ID: azure_check_for_sufficient_certificate_auto_renewal_period -Title: "Check for Sufficient Certificate Auto-Renewal Period" -Description: "Ensure there is a sufficient period configured for the SSL certificates auto-renewal." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.id as resource, - c.og_resource_id, - c.og_account_id, - case - when (la -> 'Trigger' ->> 'DaysBeforeExpiry')::int < '{{.azureSufficientDaysBeforeCertificateExpiry}}'::int then 'alarm' - else 'ok' - end as status, - case - when (la -> 'Trigger' ->> 'DaysBeforeExpiry')::int < '{{.azureSufficientDaysBeforeCertificateExpiry}}'::int then 'SSL certificate does not have a sufficient period of time before expiration to trigger the auto-renewal process, configured for the issuance policy.' - else 'SSL certificate has a sufficient period of time before expiration to trigger the auto-renewal process, configured for the issuance policy.' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault_certificate as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id, - jsonb_array_elements(lifetime_actions) as la - PrimaryTable: azure_key_vault_certificate ListOfTables: - azure_key_vault_certificate - azure_subscription Parameters: - Key: azureSufficientDaysBeforeCertificateExpiry Required: true + PrimaryTable: azure_key_vault_certificate + QueryToExecute: | + SELECT + c.id AS resource, + c.og_resource_id, + c.og_account_id, + CASE + WHEN (la -> 'Trigger' ->> 'DaysBeforeExpiry')::int < '{{.azureSufficientDaysBeforeCertificateExpiry}}'::int THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (la -> 'Trigger' ->> 'DaysBeforeExpiry')::int < '{{.azureSufficientDaysBeforeCertificateExpiry}}'::int THEN + 'SSL certificate does not have a sufficient period of time before expiration to trigger the auto-renewal process, configured for the issuance policy.' + ELSE + 'SSL certificate has a sufficient period of time before expiration to trigger the auto-renewal process, configured for the issuance policy.' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_certificate AS c + LEFT JOIN azure_subscription AS sub ON c.subscription_id = sub.subscription_id, + jsonb_array_elements(lifetime_actions) AS la Severity: high Tags: platform_score_cloud_service_name: @@ -39,5 +42,4 @@ Tags: - Azure KeyVault score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Check for Sufficient Certificate Auto-Renewal Period \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_database_tier_customer_managed_key_in_use.yaml b/compliance/controls/baseline/azure/KeyVault/azure_database_tier_customer_managed_key_in_use.yaml index 9dd7b01f2..4843b3992 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_database_tier_customer_managed_key_in_use.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_database_tier_customer_managed_key_in_use.yaml @@ -1,45 +1,52 @@ +Description: Ensure that a Customer-Managed Key is created for your Azure cloud database tier. ID: azure_database_tier_customer_managed_key_in_use -Title: "Database Tier Customer-Managed Key In Use" -Description: "Ensure that a Customer-Managed Key is created for your Azure cloud database tier." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - display_name as resource, - sub.og_resource_id, - sub.og_account_id, - case - when exists( - select 1 from azure_key_vault_key as k where (k.subscription_id = sub.subscription_id) and - k.tags is not null and - (k.tags::text like '%' || REPLACE(REPLACE(( - SELECT jsonb_object_agg(key, value)::text - FROM jsonb_each_text('{{.azureDatabaseTierTags}}'::jsonb) - ), '{', ''), '}', '') || '%') and enabled - ) then 'ok' - else 'alarm' - end as status, - case - when exists( - select 1 from azure_key_vault_key as k where (k.subscription_id = sub.subscription_id) and - k.tags is not null and - (k.tags::text like '%' || REPLACE(REPLACE(( - SELECT jsonb_object_agg(key, value)::text - FROM jsonb_each_text('{{.azureDatabaseTierTags}}'::jsonb) - ), '{', ''), '}', '') || '%') and enabled - ) then 'subscription has an app-tier cmk' - else 'subscription does not have any app-tier cmk' - end as reason, - sub.display_name as subscription - from - azure_subscription as sub - PrimaryTable: azure_subscription ListOfTables: - azure_key_vault_key - azure_subscription Parameters: - Key: azureDatabaseTierTags Required: true + PrimaryTable: azure_subscription + QueryToExecute: | + SELECT + display_name AS resource, + sub.og_resource_id, + sub.og_account_id, + CASE + WHEN EXISTS( + SELECT 1 FROM azure_key_vault_key AS k + WHERE (k.subscription_id = sub.subscription_id) + AND k.tags IS NOT NULL + AND (k.tags::TEXT LIKE '%' || REPLACE( + REPLACE(( + SELECT jsonb_object_agg(key, value)::TEXT + FROM jsonb_each_text('{{.azureDatabaseTierTags}}'::jsonb) + ), '{', ''), '}', '') || '%') + AND enabled + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS( + SELECT 1 FROM azure_key_vault_key AS k + WHERE (k.subscription_id = sub.subscription_id) + AND k.tags IS NOT NULL + AND (k.tags::TEXT LIKE '%' || REPLACE( + REPLACE(( + SELECT jsonb_object_agg(key, value)::TEXT + FROM jsonb_each_text('{{.azureDatabaseTierTags}}'::jsonb) + ), '{', ''), '}', '') || '%') + AND enabled + ) THEN 'subscription has an app-tier cmk' + ELSE 'subscription does not have any app-tier cmk' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription AS sub Severity: high Tags: platform_score_cloud_service_name: @@ -50,5 +57,4 @@ Tags: - Azure KeyVault score_tags: - Unencrypted Storage -IntegrationType: - - azure_subscription +Title: Database Tier Customer-Managed Key In Use \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_enable_auditevent_logging_for_azure_key_vaults.yaml b/compliance/controls/baseline/azure/KeyVault/azure_enable_auditevent_logging_for_azure_key_vaults.yaml index fe071a5ab..4c10042ed 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_enable_auditevent_logging_for_azure_key_vaults.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_enable_auditevent_logging_for_azure_key_vaults.yaml @@ -1,14 +1,46 @@ +Description: Ensure that logging for Azure KeyVault is 'Enabled' ID: azure_enable_auditevent_logging_for_azure_key_vaults -Title: "Enable AuditEvent Logging for Azure Key Vaults" -Description: "Ensure that logging for Azure KeyVault is 'Enabled'" +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: "select\n name as resource,\n v.og_resource_id,\n v.og_account_id,\n case\n when exists(\n select 1\n from \n jsonb_array_elements(diagnostic_settings) as ds,\n jsonb_array_elements(ds -> 'properties' -> 'logs') as l\n where\n (l ->> 'category' = 'AuditEvent') and (l ->> 'enabled' = 'true')\n ) then 'ok'\n else 'alarm'\n end as status,\n case\n when exists(\n select 1\n from \n jsonb_array_elements(diagnostic_settings) as ds,\n jsonb_array_elements(ds -> 'properties' -> 'logs') as l\n where\n (l ->> 'category' = 'AuditEvent') and (l ->> 'enabled' = 'true')\n ) then 'subscription has an app-tier cmk'\n else 'subscription does not have any app-tier cmk'\n end as reason,\n resource_group as resource_group,\n sub.display_name as subscription\nfrom\n azure_key_vault as v\n left join azure_subscription as sub on v.subscription_id = sub.subscription_id\n" - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + name AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM + jsonb_array_elements(diagnostic_settings) AS ds, + jsonb_array_elements(ds -> 'properties' -> 'logs') AS l + WHERE + (l ->> 'category' = 'AuditEvent') AND (l ->> 'enabled' = 'true') + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM + jsonb_array_elements(diagnostic_settings) AS ds, + jsonb_array_elements(ds -> 'properties' -> 'logs') AS l + WHERE + (l ->> 'category' = 'AuditEvent') AND (l ->> 'enabled' = 'true') + ) THEN 'subscription has an app-tier cmk' + ELSE 'subscription does not have any app-tier cmk' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault AS v + LEFT JOIN azure_subscription AS sub ON v.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -19,5 +51,4 @@ Tags: - Azure KeyVault score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Enable AuditEvent Logging for Azure Key Vaults \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_enable_certificate_transparency.yaml b/compliance/controls/baseline/azure/KeyVault/azure_enable_certificate_transparency.yaml index ff0cb463a..10b669f67 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_enable_certificate_transparency.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_enable_certificate_transparency.yaml @@ -1,31 +1,33 @@ +Description: Ensure there is a sufficient period configured for the SSL certificates auto-renewal. ID: azure_enable_certificate_transparency -Title: "Enable Certificate Transparency" -Description: "Ensure there is a sufficient period configured for the SSL certificates auto-renewal." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.id as resource, - c.og_resource_id, - c.og_account_id, - case - when c.issuer_parameters ->> 'CertificateTransparency' = 'true' then 'ok' - else 'alarm' - end as status, - case - when c.issuer_parameters ->> 'CertificateTransparency' = 'true' then 'Certificate transparency is not enabled for the certificate' - else 'Certificate transparency is enabled for the certificate' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault_certificate as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id - PrimaryTable: azure_key_vault_certificate ListOfTables: - azure_key_vault_certificate - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_certificate + QueryToExecute: | + SELECT + c.id AS resource, + c.og_resource_id, + c.og_account_id, + CASE + WHEN c.issuer_parameters ->> 'CertificateTransparency' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN c.issuer_parameters ->> 'CertificateTransparency' = 'true' THEN 'Certificate transparency is not enabled for the certificate' + ELSE 'Certificate transparency is enabled for the certificate' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_certificate AS c + LEFT JOIN azure_subscription AS sub + ON c.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +38,4 @@ Tags: - Azure KeyVault score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Enable Certificate Transparency \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_enable_key_vault_recoverability.yaml b/compliance/controls/baseline/azure/KeyVault/azure_enable_key_vault_recoverability.yaml index 35252a7d9..4e9c2d07c 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_enable_key_vault_recoverability.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_enable_key_vault_recoverability.yaml @@ -1,31 +1,32 @@ +Description: Ensure that your Microsoft Azure Key Vault instances are recoverable. ID: azure_enable_key_vault_recoverability -Title: "Enable Key Vault Recoverability" -Description: "Ensure that your Microsoft Azure Key Vault instances are recoverable." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - v.og_resource_id, - v.og_account_id, - case - when soft_delete_enabled and purge_protection_enabled then 'ok' - else 'alarm' - end as status, - case - when soft_delete_enabled and purge_protection_enabled then name || ' objects are recoverable' - else name || ' objects are not recoverable' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault as v - left join azure_subscription as sub on v.subscription_id = sub.subscription_id - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + name AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN soft_delete_enabled AND purge_protection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN soft_delete_enabled AND purge_protection_enabled THEN name || ' objects are recoverable' + ELSE name || ' objects are not recoverable' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault AS v + LEFT JOIN azure_subscription AS sub ON v.subscription_id = sub.subscription_id Severity: high Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - Azure KeyVault score_tags: - Problem Identities -IntegrationType: - - azure_subscription +Title: Enable Key Vault Recoverability \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_enable_ssl_certificate_auto_renewal.yaml b/compliance/controls/baseline/azure/KeyVault/azure_enable_ssl_certificate_auto_renewal.yaml index e6e9ae7d5..8ae4e61bb 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_enable_ssl_certificate_auto_renewal.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_enable_ssl_certificate_auto_renewal.yaml @@ -1,32 +1,33 @@ +Description: Ensure that Auto-Renewal feature is enabled for your Azure Key Vault SSL certificates. ID: azure_enable_ssl_certificate_auto_renewal -Title: "Enable SSL Certificate Auto-Renewal" -Description: "Ensure that Auto-Renewal feature is enabled for your Azure Key Vault SSL certificates." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.id as resource, - c.og_resource_id, - c.og_account_id, - case - when la -> 'Action' ->> 'ActionType' = 'EmailContacts' then 'alarm' - else 'ok' - end as status, - case - when la -> 'Action' ->> 'ActionType' = 'EmailContacts' then 'Auto-Renewal feature is not enabled' - else 'Auto-Renewal feature is enabled' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault_certificate as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id, - jsonb_array_elements(lifetime_actions) as la - PrimaryTable: azure_key_vault_certificate ListOfTables: - azure_key_vault_certificate - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_certificate + QueryToExecute: | + SELECT + c.id AS resource, + c.og_resource_id, + c.og_account_id, + CASE + WHEN la -> 'Action' ->> 'ActionType' = 'EmailContacts' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN la -> 'Action' ->> 'ActionType' = 'EmailContacts' THEN 'Auto-Renewal feature is not enabled' + ELSE 'Auto-Renewal feature is enabled' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_certificate AS c + LEFT JOIN azure_subscription AS sub ON c.subscription_id = sub.subscription_id, + jsonb_array_elements(lifetime_actions) AS la Severity: high Tags: platform_score_cloud_service_name: @@ -37,5 +38,4 @@ Tags: - Azure KeyVault score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Enable SSL Certificate Auto-Renewal \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_enable_trusted_microsoft_services_for_key_vault_access.yaml b/compliance/controls/baseline/azure/KeyVault/azure_enable_trusted_microsoft_services_for_key_vault_access.yaml index 4e00dc62b..aefa91c0e 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_enable_trusted_microsoft_services_for_key_vault_access.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_enable_trusted_microsoft_services_for_key_vault_access.yaml @@ -1,33 +1,34 @@ +Description: Allow trusted Microsoft services to access your Azure Key Vault resources (i.e. encryption keys, secrets and certificates). ID: azure_enable_trusted_microsoft_services_for_key_vault_access -Title: "Enable Trusted Microsoft Services for Key Vault Access" -Description: "Allow trusted Microsoft services to access your Azure Key Vault resources (i.e. encryption keys, secrets and certificates)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.name as resource, - c.og_resource_id, - c.og_account_id, - case - when network_acls is null then 'alarm' - when network_acls ->> 'bypass' = 'None' then 'alarm' - else 'ok' - end as status, - case - when network_acls is null then 'no trusted Microsoft Azure cloud services are allowed to access the resources (keys, secrets and certificates) available in the Azure Key Vault' - when network_acls ->> 'bypass' = 'None' then 'no trusted Microsoft Azure cloud services are allowed to access the resources (keys, secrets and certificates) available in the Azure Key Vault' - else 'trusted Microsoft Azure cloud services are allowed to access the resources (keys, secrets and certificates) available in the Azure Key Vault' - end as reason, - c.resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + c.name AS resource, + c.og_resource_id, + c.og_account_id, + CASE + WHEN network_acls IS NULL THEN 'alarm' + WHEN network_acls ->> 'bypass' = 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_acls IS NULL THEN 'no trusted Microsoft Azure cloud services are allowed to access the resources (keys, secrets and certificates) available in the Azure Key Vault' + WHEN network_acls ->> 'bypass' = 'None' THEN 'no trusted Microsoft Azure cloud services are allowed to access the resources (keys, secrets and certificates) available in the Azure Key Vault' + ELSE 'trusted Microsoft Azure cloud services are allowed to access the resources (keys, secrets and certificates) available in the Azure Key Vault' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault AS c + LEFT JOIN azure_subscription AS sub ON c.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -38,5 +39,4 @@ Tags: - Azure KeyVault score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Enable Trusted Microsoft Services for Key Vault Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_restrict_default_network_access_for_azure_key_vaults.yaml b/compliance/controls/baseline/azure/KeyVault/azure_restrict_default_network_access_for_azure_key_vaults.yaml index cbf825a2f..51fe60f24 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_restrict_default_network_access_for_azure_key_vaults.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_restrict_default_network_access_for_azure_key_vaults.yaml @@ -1,31 +1,34 @@ +Description: Ensure that default network access (i.e. public access) rule is set to "Deny" within your Azure Key Vaults configuration. ID: azure_restrict_default_network_access_for_azure_key_vaults -Title: "Restrict Default Network Access for Azure Key Vaults" -Description: "Ensure that default network access (i.e. public access) rule is set to \"Deny\" within your Azure Key Vaults configuration." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - v.og_resource_id, - v.og_account_id, - case - when network_acls is null or network_acls ->> 'defaultAction' = 'Allow' then 'alarm' - else 'ok' - end as status, - case - when network_acls is null or network_acls ->> 'defaultAction' = 'Allow' then name || ' access configuration is not compliant' - else name || ' access configuration is compliant' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault as v - left join azure_subscription as sub on v.subscription_id = sub.subscription_id - PrimaryTable: azure_key_vault ListOfTables: - azure_key_vault - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault + QueryToExecute: | + SELECT + name AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' = 'Allow' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' = 'Allow' THEN name || ' access configuration is not compliant' + ELSE name || ' access configuration is compliant' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault AS v + LEFT JOIN + azure_subscription AS sub + ON v.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +39,4 @@ Tags: - Azure KeyVault score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Restrict Default Network Access for Azure Key Vaults \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_set_azure_secret_key_expiration.yaml b/compliance/controls/baseline/azure/KeyVault/azure_set_azure_secret_key_expiration.yaml index 4abf0dc61..860dcf359 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_set_azure_secret_key_expiration.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_set_azure_secret_key_expiration.yaml @@ -1,31 +1,33 @@ +Description: Ensure that an expiration date is set for all your Microsoft Azure secret keys. ID: azure_set_azure_secret_key_expiration -Title: "Set Azure Secret Key Expiration" -Description: "Ensure that an expiration date is set for all your Microsoft Azure secret keys." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.name as resource, - c.og_resource_id, - c.og_account_id, - case - when expires_at is null then 'alarm' - else 'ok' - end as status, - case - when expires_at is null then c.name || ' does not have an expiration date configured.' - else c.name || ' has an expiration date configured.' - end as reason, - c.resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault_secret as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id - PrimaryTable: azure_key_vault_secret ListOfTables: - azure_key_vault_secret - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_secret + QueryToExecute: | + SELECT + c.name AS resource, + c.og_resource_id, + c.og_account_id, + CASE + WHEN expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expires_at IS NULL THEN c.name || ' does not have an expiration date configured.' + ELSE c.name || ' has an expiration date configured.' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_secret AS c + LEFT JOIN azure_subscription AS sub + ON c.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +38,4 @@ Tags: - Azure KeyVault score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Set Azure Secret Key Expiration \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_set_encryption_key_expiration.yaml b/compliance/controls/baseline/azure/KeyVault/azure_set_encryption_key_expiration.yaml index 5ada081c3..100e2058e 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_set_encryption_key_expiration.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_set_encryption_key_expiration.yaml @@ -1,31 +1,35 @@ +Description: Ensure that an expiration date is configured for all your Microsoft Azure encryption keys. ID: azure_set_encryption_key_expiration -Title: "Set Encryption Key Expiration" -Description: "Ensure that an expiration date is configured for all your Microsoft Azure encryption keys." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - k.name as resource, - k.og_resource_id, - k.og_account_id, - case - when expires_at is null then 'alarm' - else 'ok' - end as status, - case - when expires_at is null then 'key does not have an expiration time set' - else 'key has an expiration time set' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_key_vault_key as k - left join azure_subscription as sub on k.subscription_id = sub.subscription_id - PrimaryTable: azure_key_vault_key ListOfTables: - azure_key_vault_key - azure_subscription Parameters: [] + PrimaryTable: azure_key_vault_key + QueryToExecute: | + SELECT + k.name AS resource, + k.og_resource_id, + k.og_account_id, + CASE + WHEN expires_at IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN expires_at IS NULL THEN 'key does not have an expiration time set' + ELSE 'key has an expiration time set' + END AS reason, + k.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_key_vault_key AS k + LEFT JOIN + azure_subscription AS sub + ON + k.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +40,4 @@ Tags: - Azure KeyVault score_tags: - Problem Identities -IntegrationType: - - azure_subscription +Title: Set Encryption Key Expiration \ No newline at end of file diff --git a/compliance/controls/baseline/azure/KeyVault/azure_web_tier_customer_managed_key_in_use.yaml b/compliance/controls/baseline/azure/KeyVault/azure_web_tier_customer_managed_key_in_use.yaml index 2b17d8425..b3126f1c5 100644 --- a/compliance/controls/baseline/azure/KeyVault/azure_web_tier_customer_managed_key_in_use.yaml +++ b/compliance/controls/baseline/azure/KeyVault/azure_web_tier_customer_managed_key_in_use.yaml @@ -1,44 +1,46 @@ +Description: Ensure that a Customer-Managed Key is created for your Microsoft Azure cloud web tier. ID: azure_web_tier_customer_managed_key_in_use -Title: "Web Tier Customer-Managed Key In Use" -Description: "Ensure that a Customer-Managed Key is created for your Microsoft Azure cloud web tier." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - with web_tier_keys as ( - select - name, subscription_id - from - azure_key_vault_key - where - tags::text like '%' || REPLACE(REPLACE(( - SELECT jsonb_object_agg(key, value)::text - FROM jsonb_each_text('{{.azureWebTierTags}}'::jsonb) - ), '{', ''), '}', '') || '%' - ) - - select - sub.display_name as resource, - sub.og_resource_id, - sub.og_account_id, - case - when wtk.name is null then 'alarm' - else 'ok' - end as status, - case - when wtk.name is null then 'there is no web tier key in the subscription.' - else 'subscription has web tier keys.' - end as reason, - sub.display_name as subscription - from - azure_subscription as sub - left join web_tier_keys as wtk on sub.subscription_id = wtk.subscription_id - PrimaryTable: azure_subscription ListOfTables: - azure_key_vault_key - azure_subscription Parameters: - Key: azureWebTierTags Required: true + PrimaryTable: azure_subscription + QueryToExecute: | + WITH web_tier_keys AS ( + SELECT + name, subscription_id + FROM + azure_key_vault_key + WHERE + tags::text LIKE '%' || REPLACE(REPLACE(( + SELECT jsonb_object_agg(key, value)::text + FROM jsonb_each_text('{{.azureWebTierTags}}'::jsonb) + ), '{', ''), '}', '') || '%' + ) + + SELECT + sub.display_name AS resource, + sub.og_resource_id, + sub.og_account_id, + CASE + WHEN wtk.name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN wtk.name IS NULL THEN 'there is no web tier key in the subscription.' + ELSE 'subscription has web tier keys.' + END AS reason, + sub.display_name AS subscription + FROM + azure_subscription AS sub + LEFT JOIN web_tier_keys AS wtk + ON sub.subscription_id = wtk.subscription_id Severity: high Tags: platform_score_cloud_service_name: @@ -49,5 +51,4 @@ Tags: - Azure KeyVault score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Web Tier Customer-Managed Key In Use \ No newline at end of file diff --git a/compliance/controls/baseline/azure/aks/azure_check_for_kubernetes_version.yaml b/compliance/controls/baseline/azure/aks/azure_check_for_kubernetes_version.yaml index 0373fe764..b1177649c 100644 --- a/compliance/controls/baseline/azure/aks/azure_check_for_kubernetes_version.yaml +++ b/compliance/controls/baseline/azure/aks/azure_check_for_kubernetes_version.yaml @@ -1,33 +1,34 @@ +Description: Ensure that AKS clusters are using the latest available version of Kubernetes software. ID: azure_check_for_kubernetes_version -Title: "Check for Kubernetes Version" -Description: "Ensure that AKS clusters are using the latest available version of Kubernetes software." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.name as resource, - c.og_resource_id, - c.og_account_id, - case - when kubernetes_version < '{{.azureAksLatestVersion}}' then 'alarm' - else 'ok' - end as status, - case - when kubernetes_version < '{{.azureAksLatestVersion}}' then c.name || ' is not using the latest available version of Kubernetes software' - else c.name || ' is using the latest available version of Kubernetes software' - end as reason, - c.resource_group as resource_group, - sub.display_name as subscription - from - azure_kubernetes_cluster as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: - Key: azureAksLatestVersion Required: true + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.name AS resource, + c.og_resource_id, + c.og_account_id, + CASE + WHEN kubernetes_version < '{{.azureAksLatestVersion}}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kubernetes_version < '{{.azureAksLatestVersion}}' THEN c.name || ' is not using the latest available version of Kubernetes software' + ELSE c.name || ' is using the latest available version of Kubernetes software' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS c + LEFT JOIN azure_subscription AS sub ON c.subscription_id = sub.subscription_id Severity: low Tags: platform_score_cloud_service_name: @@ -38,5 +39,4 @@ Tags: - Azure Kubernetes (AKS) score_tags: - Lacking High Availability -IntegrationType: - - azure_subscription +Title: Check for Kubernetes Version \ No newline at end of file diff --git a/compliance/controls/baseline/azure/aks/azure_enable_defender_for_cloud_for_aks_clusters.yaml b/compliance/controls/baseline/azure/aks/azure_enable_defender_for_cloud_for_aks_clusters.yaml index 0f14a6b59..9df742f31 100644 --- a/compliance/controls/baseline/azure/aks/azure_enable_defender_for_cloud_for_aks_clusters.yaml +++ b/compliance/controls/baseline/azure/aks/azure_enable_defender_for_cloud_for_aks_clusters.yaml @@ -1,31 +1,32 @@ +Description: Ensure that Microsoft Defender for Cloud is enabled for AKS clusters. ID: azure_enable_defender_for_cloud_for_aks_clusters -Title: "Enable Defender for Cloud for AKS Clusters" -Description: "Ensure that Microsoft Defender for Cloud is enabled for AKS clusters." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.name as resource, - c.og_resource_id, - c.og_account_id, - case - when (addon_profiles -> 'omsagent' ->> 'enabled')::bool then 'ok' - else 'alarm' - end as status, - case - when (addon_profiles -> 'omsagent' ->> 'enabled')::bool then 'Microsoft Defender is enabled for this resource' - else 'Microsoft Defender is not enabled for this resource' - end as reason, - c.resource_group as resource_group, - sub.display_name as subscription - from - azure_kubernetes_cluster as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.name AS resource, + c.og_resource_id, + c.og_account_id, + CASE + WHEN (addon_profiles -> 'omsagent' ->> 'enabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (addon_profiles -> 'omsagent' ->> 'enabled')::bool THEN 'Microsoft Defender is enabled for this resource' + ELSE 'Microsoft Defender is not enabled for this resource' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS c + LEFT JOIN azure_subscription AS sub ON c.subscription_id = sub.subscription_id Severity: high Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - Azure Kubernetes (AKS) score_tags: - Tolerate Failures -IntegrationType: - - azure_subscription +Title: Enable Defender for Cloud for AKS Clusters \ No newline at end of file diff --git a/compliance/controls/baseline/azure/aks/azure_enable_kubernetes_role_based_access_control.yaml b/compliance/controls/baseline/azure/aks/azure_enable_kubernetes_role_based_access_control.yaml index a17242545..06c617633 100644 --- a/compliance/controls/baseline/azure/aks/azure_enable_kubernetes_role_based_access_control.yaml +++ b/compliance/controls/baseline/azure/aks/azure_enable_kubernetes_role_based_access_control.yaml @@ -1,32 +1,34 @@ +Description: Ensure that Kubernetes Role-Based Access Control is enabled for Azure Kubernetes clusters. ID: azure_enable_kubernetes_role_based_access_control -Title: "Enable Kubernetes Role-Based Access Control" -Description: "Ensure that Kubernetes Role-Based Access Control is enabled for Azure Kubernetes clusters." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.name as resource, - c.og_resource_id, - c.og_account_id, - kubernetes_version, - case - when enable_rbac then 'ok' - else 'alarm' - end as status, - case - when enable_rbac then c.name || ' Role-Based Access Control (RBAC) is enabled' - else c.name || ' Role-Based Access Control (RBAC) is not enabled' - end as reason, - c.resource_group as resource_group, - sub.display_name as subscription - from - azure_kubernetes_cluster as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.name AS resource, + c.og_resource_id, + c.og_account_id, + kubernetes_version, + CASE + WHEN enable_rbac THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_rbac THEN c.name || ' Role-Based Access Control (RBAC) is enabled' + ELSE c.name || ' Role-Based Access Control (RBAC) is not enabled' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS c + LEFT JOIN azure_subscription AS sub + ON c.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -37,5 +39,4 @@ Tags: - Azure Kubernetes (AKS) score_tags: - Unencrypted Traffic -IntegrationType: - - azure_subscription +Title: Enable Kubernetes Role-Based Access Control \ No newline at end of file diff --git a/compliance/controls/baseline/azure/aks/azure_kubernetes_api_version.yaml b/compliance/controls/baseline/azure/aks/azure_kubernetes_api_version.yaml index b7f046d46..7e657b831 100644 --- a/compliance/controls/baseline/azure/aks/azure_kubernetes_api_version.yaml +++ b/compliance/controls/baseline/azure/aks/azure_kubernetes_api_version.yaml @@ -1,38 +1,39 @@ +Description: Ensure that AKS clusters are using the latest version of Kubernetes API. ID: azure_kubernetes_api_version -Title: "Kubernetes API Version" -Description: "Ensure that AKS clusters are using the latest version of Kubernetes API." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.name as resource, - c.og_resource_id, - c.og_account_id, - case - when kubernetes_version < '{{.azureKubernetesLatestVersion}}' then 'alarm' - else 'ok' - end as status, - case - when kubernetes_version < '{{.azureKubernetesLatestVersion}}' then c.name || ' is not using the latest version of kubernetes API' - else c.name || ' is using the latest version of kubernetes API' - end as reason, - c.resource_group as resource_group, - sub.display_name as subscription - from - azure_kubernetes_cluster as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: - Key: azureKubernetesLatestVersion Required: true + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.name AS resource, + c.og_resource_id, + c.og_account_id, + CASE + WHEN kubernetes_version < '{{.azureKubernetesLatestVersion}}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN kubernetes_version < '{{.azureKubernetesLatestVersion}}' THEN c.name || ' is not using the latest version of Kubernetes API' + ELSE c.name || ' is using the latest version of Kubernetes API' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS c + LEFT JOIN + azure_subscription AS sub ON c.subscription_id = sub.subscription_id Severity: high Tags: platform_score_cloud_service_name: - Azure Kubernetes (AKS) score_service_name: - Azure Kubernetes (AKS) -IntegrationType: - - azure_subscription +Title: Kubernetes API Version \ No newline at end of file diff --git a/compliance/controls/baseline/azure/aks/azure_secure_access_to_kubernetes_api_server_using_authorized_ip_address_ranges.yaml b/compliance/controls/baseline/azure/aks/azure_secure_access_to_kubernetes_api_server_using_authorized_ip_address_ranges.yaml index db7c1c69e..2335d050e 100644 --- a/compliance/controls/baseline/azure/aks/azure_secure_access_to_kubernetes_api_server_using_authorized_ip_address_ranges.yaml +++ b/compliance/controls/baseline/azure/aks/azure_secure_access_to_kubernetes_api_server_using_authorized_ip_address_ranges.yaml @@ -1,32 +1,34 @@ +Description: Ensure that public access to Kubernetes API server is restricted. ID: azure_secure_access_to_kubernetes_api_server_using_authorized_ip_address_ranges -Title: "Secure Access to Kubernetes API Server Using Authorized IP Address Ranges" -Description: "Ensure that public access to Kubernetes API server is restricted." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.name as resource, - c.og_resource_id, - c.og_account_id, - kubernetes_version, - case - when api_server_access_profile is null then 'alarm' - else 'ok' - end as status, - case - when api_server_access_profile is null then c.name || ' is not configured to secure access to the Kubernetes API server' - else c.name || ' is configured to secure access to the Kubernetes API server' - end as reason, - c.resource_group as resource_group, - sub.display_name as subscription - from - azure_kubernetes_cluster as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.name AS resource, + c.og_resource_id, + c.og_account_id, + kubernetes_version, + CASE + WHEN api_server_access_profile IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN api_server_access_profile IS NULL THEN c.name || ' is not configured to secure access to the Kubernetes API server' + ELSE c.name || ' is configured to secure access to the Kubernetes API server' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS c + LEFT JOIN + azure_subscription AS sub ON c.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -37,5 +39,4 @@ Tags: - Azure Kubernetes (AKS) score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Secure Access to Kubernetes API Server Using Authorized IP Address Ranges \ No newline at end of file diff --git a/compliance/controls/baseline/azure/aks/azure_use_azure_cni_add_on_for_managing_network_resources.yaml b/compliance/controls/baseline/azure/aks/azure_use_azure_cni_add_on_for_managing_network_resources.yaml index 1443424ed..303a7c660 100644 --- a/compliance/controls/baseline/azure/aks/azure_use_azure_cni_add_on_for_managing_network_resources.yaml +++ b/compliance/controls/baseline/azure/aks/azure_use_azure_cni_add_on_for_managing_network_resources.yaml @@ -1,38 +1,38 @@ +Description: Ensure that DDoS standard protection is enabled for production Azure virtual networks. ID: azure_use_azure_cni_add_on_for_managing_network_resources -Title: "Use Azure CNI Add-On for Managing Network Resources" -Description: "Ensure that DDoS standard protection is enabled for production Azure virtual networks." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_kubernetes_cluster + - azure_subscription + Parameters: [] + PrimaryTable: azure_kubernetes_cluster QueryToExecute: | - select - kc.id as resource, + SELECT + kc.id AS resource, kc.og_account_id, kc.og_resource_id, - case - when network_profile ->> 'networkPlugin' = 'kubenet' then 'alarm' - else 'ok' - end as status, - case - when network_profile ->> 'networkPlugin' = 'kubenet' then 'not configured to use the Azure Container Networking Interface (CNI) add-on for managing network resources.' - else 'configured to use the Azure Container Networking Interface (CNI) add-on for managing network resources.' - end as reason, + CASE + WHEN network_profile ->> 'networkPlugin' = 'kubenet' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_profile ->> 'networkPlugin' = 'kubenet' THEN 'not configured to use the Azure Container Networking Interface (CNI) add-on for managing network resources.' + ELSE 'configured to use the Azure Container Networking Interface (CNI) add-on for managing network resources.' + END AS reason, kc.resource_group, - display_name as subscription - from - azure_kubernetes_cluster as kc, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_kubernetes_cluster AS kc, + azure_subscription AS sub + WHERE sub.subscription_id = kc.subscription_id - PrimaryTable: azure_kubernetes_cluster - ListOfTables: - - azure_kubernetes_cluster - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Kubernetes (AKS) score_service_name: - Azure Kubernetes (AKS) -IntegrationType: - - azure_subscription +Title: Use Azure CNI Add-On for Managing Network Resources \ No newline at end of file diff --git a/compliance/controls/baseline/azure/aks/azure_use_microsoft_entra_id_integration_for_aks_clusters.yaml b/compliance/controls/baseline/azure/aks/azure_use_microsoft_entra_id_integration_for_aks_clusters.yaml index cf25f84e1..e1f1ab2ac 100644 --- a/compliance/controls/baseline/azure/aks/azure_use_microsoft_entra_id_integration_for_aks_clusters.yaml +++ b/compliance/controls/baseline/azure/aks/azure_use_microsoft_entra_id_integration_for_aks_clusters.yaml @@ -1,38 +1,38 @@ +Description: Ensure that Microsoft Entra ID integration is enabled for Azure Kubernetes clusters. ID: azure_use_microsoft_entra_id_integration_for_aks_clusters -Title: "Use Microsoft Entra ID Integration for AKS Clusters" -Description: "Ensure that Microsoft Entra ID integration is enabled for Azure Kubernetes clusters." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_kubernetes_cluster + - azure_subscription + Parameters: [] + PrimaryTable: azure_kubernetes_cluster QueryToExecute: | - select - kc.id as resource, + SELECT + kc.id AS resource, kc.og_account_id, kc.og_resource_id, - case - when network_profile ->> 'networkPlugin' = 'kubenet' then 'alarm' - else 'ok' - end as status, - case - when network_profile ->> 'networkPlugin' = 'kubenet' then 'not configured to use the Azure Container Networking Interface (CNI) add-on for managing network resources.' - else 'configured to use the Azure Container Networking Interface (CNI) add-on for managing network resources.' - end as reason, + CASE + WHEN network_profile ->> 'networkPlugin' = 'kubenet' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_profile ->> 'networkPlugin' = 'kubenet' THEN 'not configured to use the Azure Container Networking Interface (CNI) add-on for managing network resources.' + ELSE 'configured to use the Azure Container Networking Interface (CNI) add-on for managing network resources.' + END AS reason, kc.resource_group, - display_name as subscription - from - azure_kubernetes_cluster as kc, - azure_subscription as sub - where + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS kc, + azure_subscription AS sub + WHERE sub.subscription_id = kc.subscription_id - PrimaryTable: azure_kubernetes_cluster - ListOfTables: - - azure_kubernetes_cluster - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Kubernetes (AKS) score_service_name: - Azure Kubernetes (AKS) -IntegrationType: - - azure_subscription +Title: Use Microsoft Entra ID Integration for AKS Clusters \ No newline at end of file diff --git a/compliance/controls/baseline/azure/aks/azure_use_network_contributor_role_for_managing_azure_network_resources.yaml b/compliance/controls/baseline/azure/aks/azure_use_network_contributor_role_for_managing_azure_network_resources.yaml index 786eb9d60..d46616864 100644 --- a/compliance/controls/baseline/azure/aks/azure_use_network_contributor_role_for_managing_azure_network_resources.yaml +++ b/compliance/controls/baseline/azure/aks/azure_use_network_contributor_role_for_managing_azure_network_resources.yaml @@ -1,21 +1,51 @@ +Description: Ensure that AKS clusters are configured to use the Network Contributor role. ID: azure_use_network_contributor_role_for_managing_azure_network_resources -Title: "Use Network Contributor Role for Managing Azure Network Resources" -Description: "Ensure that AKS clusters are configured to use the Network Contributor role." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: "with rd as (\n select\n scope, ARRAY_AGG(role_name) as roles\n from\n azure_role_assignment as ra left join azure_role_definition as rd on ra.role_definition_id = rd.id\n group by scope limit 10\n)\n \nselect\n c.name as resource,\n c.og_resource_id,\n c.og_account_id,\n case\n when rd.roles::text ilike '%Network Contributor%' then 'ok'\n else 'alarm'\n end as status,\n case\n when rd.roles::text ilike '%Network Contributor%' then c.name || ' is using a Network Contributor role to manage network resources.'\n else c.name || ' is not using a Network Contributor role to manage network resources.'\n end as reason,\n c.resource_group as resource_group,\n sub.display_name as subscription\n from\n azure_kubernetes_cluster as c\n left join azure_subscription as sub on c.subscription_id = sub.subscription_id\n left join rd as rd on c.id like '%' || rd.scope || '%'\n" - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_role_assignment - azure_role_definition - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + WITH rd AS ( + SELECT + scope, + ARRAY_AGG(role_name) AS roles + FROM + azure_role_assignment AS ra + LEFT JOIN azure_role_definition AS rd ON ra.role_definition_id = rd.id + GROUP BY + scope + LIMIT 10 + ) + + SELECT + c.name AS resource, + c.og_resource_id, + c.og_account_id, + CASE + WHEN rd.roles::text ILIKE '%Network Contributor%' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN rd.roles::text ILIKE '%Network Contributor%' THEN c.name || ' is using a Network Contributor role to manage network resources.' + ELSE c.name || ' is not using a Network Contributor role to manage network resources.' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS c + LEFT JOIN azure_subscription AS sub ON c.subscription_id = sub.subscription_id + LEFT JOIN rd AS rd ON c.id LIKE '%' || rd.scope || '%' Severity: medium Tags: platform_score_cloud_service_name: - Azure Kubernetes (AKS) score_service_name: - Azure Kubernetes (AKS) -IntegrationType: - - azure_subscription +Title: Use Network Contributor Role for Managing Azure Network Resources \ No newline at end of file diff --git a/compliance/controls/baseline/azure/aks/azure_use_system_assigned_managed_identities_for_aks_clusters.yaml b/compliance/controls/baseline/azure/aks/azure_use_system_assigned_managed_identities_for_aks_clusters.yaml index 3be942318..c24113a23 100644 --- a/compliance/controls/baseline/azure/aks/azure_use_system_assigned_managed_identities_for_aks_clusters.yaml +++ b/compliance/controls/baseline/azure/aks/azure_use_system_assigned_managed_identities_for_aks_clusters.yaml @@ -1,32 +1,33 @@ +Description: Ensure that AKS clusters are using system-assigned managed identities. ID: azure_use_system_assigned_managed_identities_for_aks_clusters -Title: "Use System-Assigned Managed Identities for AKS Clusters" -Description: "Ensure that AKS clusters are using system-assigned managed identities." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.name as resource, - c.og_resource_id, - c.og_account_id, - kubernetes_version, - case - when identity ->> 'type' = 'UserAssigned' then 'alarm' - else 'ok' - end as status, - case - when identity ->> 'type' = 'UserAssigned' then c.name || ' is not using a system-assigned managed identity' - else c.name || ' is using a system-assigned managed identity' - end as reason, - c.resource_group as resource_group, - sub.display_name as subscription - from - azure_kubernetes_cluster as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.name AS resource, + c.og_resource_id, + c.og_account_id, + kubernetes_version, + CASE + WHEN identity ->> 'type' = 'UserAssigned' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity ->> 'type' = 'UserAssigned' THEN c.name || ' is not using a system-assigned managed identity' + ELSE c.name || ' is using a system-assigned managed identity' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS c + LEFT JOIN azure_subscription AS sub ON c.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -37,5 +38,4 @@ Tags: - Azure Kubernetes (AKS) score_tags: - Unencrypted Traffic -IntegrationType: - - azure_subscription +Title: Use System-Assigned Managed Identities for AKS Clusters \ No newline at end of file diff --git a/compliance/controls/baseline/azure/aks/azure_use_user_assigned_managed_identities_for_aks_clusters.yaml b/compliance/controls/baseline/azure/aks/azure_use_user_assigned_managed_identities_for_aks_clusters.yaml index 582a60571..f61f3a6d5 100644 --- a/compliance/controls/baseline/azure/aks/azure_use_user_assigned_managed_identities_for_aks_clusters.yaml +++ b/compliance/controls/baseline/azure/aks/azure_use_user_assigned_managed_identities_for_aks_clusters.yaml @@ -1,36 +1,37 @@ +Description: Ensure that AKS clusters are using user-assigned managed identities. ID: azure_use_user_assigned_managed_identities_for_aks_clusters -Title: "Use User-Assigned Managed Identities for AKS Clusters" -Description: "Ensure that AKS clusters are using user-assigned managed identities." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - c.name as resource, - c.og_resource_id, - c.og_account_id, - case - when identity ->> 'type' = 'SystemAssigned' and identity ->> 'userAssignedIdentities' is null then 'alarm' - else 'ok' - end as status, - case - when identity ->> 'type' = 'SystemAssigned' and identity ->> 'userAssignedIdentities' is null then c.name || ' is not using an user-assigned managed identity' - else c.name || ' is using an user-assigned managed identity' - end as reason, - c.resource_group as resource_group, - sub.display_name as subscription - from - azure_kubernetes_cluster as c - left join azure_subscription as sub on c.subscription_id = sub.subscription_id - PrimaryTable: azure_kubernetes_cluster ListOfTables: - azure_kubernetes_cluster - azure_subscription Parameters: [] + PrimaryTable: azure_kubernetes_cluster + QueryToExecute: | + SELECT + c.name AS resource, + c.og_resource_id, + c.og_account_id, + CASE + WHEN identity ->> 'type' = 'SystemAssigned' AND identity ->> 'userAssignedIdentities' IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN identity ->> 'type' = 'SystemAssigned' AND identity ->> 'userAssignedIdentities' IS NULL THEN c.name || ' is not using a user-assigned managed identity' + ELSE c.name || ' is using a user-assigned managed identity' + END AS reason, + c.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_kubernetes_cluster AS c + LEFT JOIN + azure_subscription AS sub ON c.subscription_id = sub.subscription_id Severity: high Tags: platform_score_cloud_service_name: - Azure Kubernetes (AKS) score_service_name: - Azure Kubernetes (AKS) -IntegrationType: - - azure_subscription +Title: Use User-Assigned Managed Identities for AKS Clusters \ No newline at end of file diff --git a/compliance/controls/baseline/azure/app_services/azure_disable_plain_ftp_deployment.yaml b/compliance/controls/baseline/azure/app_services/azure_disable_plain_ftp_deployment.yaml index 8df76a3fb..0c8fa7a63 100644 --- a/compliance/controls/baseline/azure/app_services/azure_disable_plain_ftp_deployment.yaml +++ b/compliance/controls/baseline/azure/app_services/azure_disable_plain_ftp_deployment.yaml @@ -1,31 +1,32 @@ +Description: Ensure that FTP access is disabled for your Azure App Services web applications. ID: azure_disable_plain_ftp_deployment -Title: "Disable Plain FTP Deployment" -Description: "Ensure that FTP access is disabled for your Azure App Services web applications." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - wa.name as resource, - wa.og_resource_id, - wa.og_account_id, - case - when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm' - else 'ok' - end as status, - case - when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' default FTP deployment is not disabled' - else name || ' default FTP deployment is disabled' - end as reason, - wa.resource_group as resource_group, - sub.display_name as subscription - from - azure_app_service_web_app as wa - left join azure_subscription as sub on wa.subscription_id = sub.subscription_id - PrimaryTable: azure_app_service_web_app ListOfTables: - azure_app_service_web_app - azure_subscription Parameters: [] + PrimaryTable: azure_app_service_web_app + QueryToExecute: | + SELECT + wa.name AS resource, + wa.og_resource_id, + wa.og_account_id, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' default FTP deployment is not disabled' + ELSE name || ' default FTP deployment is disabled' + END AS reason, + wa.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_app_service_web_app AS wa + LEFT JOIN azure_subscription AS sub ON wa.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - Azure App Services score_tags: - Lacking High Availability -IntegrationType: - - azure_subscription +Title: Disable Plain FTP Deployment \ No newline at end of file diff --git a/compliance/controls/baseline/azure/cosmosdb/azure_enable_automatic_failover.yaml b/compliance/controls/baseline/azure/cosmosdb/azure_enable_automatic_failover.yaml index 3c3d09a19..6afc4ab14 100644 --- a/compliance/controls/baseline/azure/cosmosdb/azure_enable_automatic_failover.yaml +++ b/compliance/controls/baseline/azure/cosmosdb/azure_enable_automatic_failover.yaml @@ -1,36 +1,38 @@ +Description: Enable automatic failover for Microsoft Azure Cosmos DB accounts. ID: azure_enable_automatic_failover -Title: "Enable Automatic Failover" -Description: "Enable automatic failover for Microsoft Azure Cosmos DB accounts." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - a.name as resource, - a.og_resource_id, - a.og_account_id, - case - when enable_automatic_failover = 'true' then 'ok' - else 'alarm' - end as status, - case - when enable_automatic_failover = 'true' then 'Automatic Failover feature is enabled.' - else 'Automatic Failover feature is not enabled.' - end as reason, - a.resource_group as resource_group, - sub.display_name as subscription - from - azure_cosmosdb_account as a - left join azure_subscription as sub on a.subscription_id = sub.subscription_id - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + SELECT + a.name AS resource, + a.og_resource_id, + a.og_account_id, + CASE + WHEN enable_automatic_failover = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_automatic_failover = 'true' THEN 'Automatic Failover feature is enabled.' + ELSE 'Automatic Failover feature is not enabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cosmosdb_account AS a + LEFT JOIN + azure_subscription AS sub + ON a.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Enable Automatic Failover \ No newline at end of file diff --git a/compliance/controls/baseline/azure/monitor/azure_monitor_log_all_activities.yaml b/compliance/controls/baseline/azure/monitor/azure_monitor_log_all_activities.yaml index e8b3ea334..a406a4962 100644 --- a/compliance/controls/baseline/azure/monitor/azure_monitor_log_all_activities.yaml +++ b/compliance/controls/baseline/azure/monitor/azure_monitor_log_all_activities.yaml @@ -1,31 +1,33 @@ +Description: Ensure audit profile captures all the activities. ID: azure_monitor_log_all_activities -Title: "Azure Monitor Log All Activities" -Description: "Ensure audit profile captures all the activities." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - p.id as resource, - p.og_resource_id, - p.og_account_id, - case - when p.categories @> '["Write", "Delete", "Action"]' then 'ok' - else 'alarm' - end as status, - case - when p.categories @> '["Write", "Delete", "Action"]' then p.name || ' collect activity logs from all activities.' - else p.name || ' not collect activity logs from all activities.' - end as reason, - p.resource_group as resource_group, - sub.display_name as subscription - from - azure_log_profile as p - left join azure_subscription sub on sub.subscription_id = p.subscription_id; - PrimaryTable: azure_log_profile ListOfTables: - azure_log_profile - azure_subscription Parameters: [] + PrimaryTable: azure_log_profile + QueryToExecute: | + SELECT + p.id AS resource, + p.og_resource_id, + p.og_account_id, + CASE + WHEN p.categories @> '["Write", "Delete", "Action"]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.categories @> '["Write", "Delete", "Action"]' THEN p.name || ' collect activity logs from all activities.' + ELSE p.name || ' not collect activity logs from all activities.' + END AS reason, + p.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_log_profile AS p + LEFT JOIN + azure_subscription sub ON sub.subscription_id = p.subscription_id; Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +38,4 @@ Tags: - Azure Monitor score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Azure Monitor Log All Activities \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mongodb_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mongodb_access.yaml index 7d337f74f..1fe121571 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mongodb_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mongodb_access.yaml @@ -1,45 +1,57 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on TCP ports 27017, 27018 and 27019. ID: azure_check_for_unrestricted_mongodb_access -Title: "Check for Unrestricted MongoDB Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on TCP ports 27017, 27018 and 27019." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The MongoDB inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The MongoDB inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '27017' or sr -> 'properties' ->> 'destinationPortRanges' like '%"27017"%' or sr -> 'properties' ->> 'destinationPortRanges' = '27018' or sr -> 'properties' ->> 'destinationPortRanges' like '%"27018"%' or sr -> 'properties' ->> 'destinationPortRanges' = '27019' or sr -> 'properties' ->> 'destinationPortRanges' like '%"27019"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*') and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') + THEN 'The MongoDB inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The MongoDB inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Tcp' + AND ( + sr -> 'properties' ->> 'destinationPortRanges' = '27017' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"27017"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '27018' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"27018"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '27019' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"27019"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*' + ) + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: high Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted MongoDB Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mssql_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mssql_access.yaml index bfcbada99..0e17779ef 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mssql_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mssql_access.yaml @@ -1,45 +1,49 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on TCP port 1433. ID: azure_check_for_unrestricted_mssql_access -Title: "Check for Unrestricted MSSQL Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on TCP port 1433." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The MSSQL inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The MSSQL inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '1433' or sr -> 'properties' ->> 'destinationPortRanges' like '%"1433"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*') and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'The MSSQL inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The MSSQL inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Tcp' + AND (sr -> 'properties' ->> 'destinationPortRanges' = '1433' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"1433"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*') + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: high Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted MSSQL Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mysql_database_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mysql_database_access.yaml index ed540fc8f..53aa735df 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mysql_database_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_mysql_database_access.yaml @@ -1,45 +1,49 @@ +Description: Ensure that no network security groups allow unrestricted ingress access on TCP port 3306 (MySQL Database). ID: azure_check_for_unrestricted_mysql_database_access -Title: "Check for Unrestricted MySQL Database Access" -Description: "Ensure that no network security groups allow unrestricted ingress access on TCP port 3306 (MySQL Database)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The MySQL Database inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The MySQL Database inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '3306' or sr -> 'properties' ->> 'destinationPortRanges' like '%"3306"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*') and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'The MySQL Database inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The MySQL Database inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Tcp' + AND (sr -> 'properties' ->> 'destinationPortRanges' = '3306' OR + sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"3306"%' OR + sr -> 'properties' ->> 'destinationPortRanges' = '*') + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: high Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted MySQL Database Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_netbios_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_netbios_access.yaml index f4a07bdf9..6782e7aa3 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_netbios_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_netbios_access.yaml @@ -1,46 +1,66 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on TCP port 139 and UDP ports 137 and 138 (NetBIOS). ID: azure_check_for_unrestricted_netbios_access -Title: "Check for Unrestricted NetBIOS Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on TCP port 139 and UDP ports 137 and 138 (NetBIOS)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The NetBIOS inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The NetBIOS inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and ((sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '139' or sr -> 'properties' ->> 'destinationPortRanges' like '%"139"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*')) or (sr -> 'properties' ->> 'protocol' = 'Udp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '137' or sr -> 'properties' ->> 'destinationPortRanges' like '%"137"%' or sr -> 'properties' ->> 'destinationPortRanges' = '138' or sr -> 'properties' ->> 'destinationPortRanges' like '%"138"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*'))) and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') + THEN 'The NetBIOS inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The NetBIOS inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND ( + (sr -> 'properties' ->> 'protocol' = 'Tcp' + AND ( + sr -> 'properties' ->> 'destinationPortRanges' = '139' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"139"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*' + ) + ) + OR + (sr -> 'properties' ->> 'protocol' = 'Udp' + AND ( + sr -> 'properties' ->> 'destinationPortRanges' = '137' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"137"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '138' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"138"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*' + ) + ) + ) + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: high Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted NetBIOS Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_oracle_database_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_oracle_database_access.yaml index 3f3eab726..aa910f6c4 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_oracle_database_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_oracle_database_access.yaml @@ -1,45 +1,51 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on TCP port 1521 (Oracle Database). ID: azure_check_for_unrestricted_oracle_database_access -Title: "Check for Unrestricted Oracle Database Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on TCP port 1521 (Oracle Database)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The Oracle Database inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The Oracle Database inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '1521' or sr -> 'properties' ->> 'destinationPortRanges' like '%"1521"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*') and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN + 'The Oracle Database inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE + 'The Oracle Database inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Tcp' + AND (sr -> 'properties' ->> 'destinationPortRanges' = '1521' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"1521"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*') + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: high Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted Oracle Database Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_postgresql_database_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_postgresql_database_access.yaml index e78a2c077..4223cfbc2 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_postgresql_database_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_postgresql_database_access.yaml @@ -1,45 +1,52 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on TCP port 5432 (PostgreSQL Database Server). ID: azure_check_for_unrestricted_postgresql_database_access -Title: "Check for Unrestricted PostgreSQL Database Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on TCP port 5432 (PostgreSQL Database Server)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The PosrgreSQL Database inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The PosrgreSQL Database inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '5432' or sr -> 'properties' ->> 'destinationPortRanges' like '%"5432"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*') and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN + 'The PostgreSQL Database inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The PostgreSQL Database inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Tcp' + AND ( + sr -> 'properties' ->> 'destinationPortRanges' = '5432' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"5432"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*' + ) + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: high Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted PostgreSQL Database Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_rdp_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_rdp_access.yaml index 716a56204..8e0c2b846 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_rdp_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_rdp_access.yaml @@ -1,45 +1,51 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on TCP port 3389 (Remote Desktop Protocol RDP). ID: azure_check_for_unrestricted_rdp_access -Title: "Check for Unrestricted RDP Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on TCP port 3389 (Remote Desktop Protocol RDP)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The RDP inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The RDP inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '3389' or sr -> 'properties' ->> 'destinationPortRanges' like '%"3389"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*') and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'The RDP inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The RDP inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Tcp' + AND ( + sr -> 'properties' ->> 'destinationPortRanges' = '3389' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"3389"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*' + ) + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: critical Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted RDP Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_rpc_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_rpc_access.yaml index 8ebc1502c..0f1cc7dee 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_rpc_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_rpc_access.yaml @@ -1,45 +1,53 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on TCP port 135. ID: azure_check_for_unrestricted_rpc_access -Title: "Check for Unrestricted RPC Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on TCP port 135." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The RPC inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The RPC inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '135' or sr -> 'properties' ->> 'destinationPortRanges' like '%"135"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*') and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') + THEN 'The RPC inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The RPC inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Tcp' + AND ( + sr -> 'properties' ->> 'destinationPortRanges' = '135' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"135"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*' + ) + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: high Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted RPC Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_smtp_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_smtp_access.yaml index 547b17c14..e73244aef 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_smtp_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_smtp_access.yaml @@ -1,45 +1,49 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on TCP port 25. ID: azure_check_for_unrestricted_smtp_access -Title: "Check for Unrestricted SMTP Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on TCP port 25." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The SMTP inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The SMTP inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '25' or sr -> 'properties' ->> 'destinationPortRanges' like '%"25"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*') and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'The SMTP inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The SMTP inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Tcp' + AND (sr -> 'properties' ->> 'destinationPortRanges' = '25' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"25"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*') + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: high Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted SMTP Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_ssh_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_ssh_access.yaml index 3df589c2f..4084e1795 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_ssh_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_ssh_access.yaml @@ -1,45 +1,50 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on TCP port 22. ID: azure_check_for_unrestricted_ssh_access -Title: "Check for Unrestricted SSH Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on TCP port 22." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The SSH inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The SSH inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '22' or sr -> 'properties' ->> 'destinationPortRanges' like '%"22"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*') and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') OR + (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') THEN + 'The SSH inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The SSH inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Tcp' + AND (sr -> 'properties' ->> 'destinationPortRanges' = '22' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"22"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*') + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: critical Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted SSH Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_telnet_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_telnet_access.yaml index 4ac62998e..0f7d95bbe 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_telnet_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_telnet_access.yaml @@ -1,45 +1,51 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on TCP port 23. ID: azure_check_for_unrestricted_telnet_access -Title: "Check for Unrestricted Telnet Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on TCP port 23." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The Telnet inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The Telnet inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Tcp' and - (sr -> 'properties' ->> 'destinationPortRanges' = '23' or sr -> 'properties' ->> 'destinationPortRanges' like '%"23"%' or sr -> 'properties' ->> 'destinationPortRanges' = '*') and sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') + THEN 'The Telnet inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The Telnet inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Tcp' + AND (sr -> 'properties' ->> 'destinationPortRanges' = '23' + OR sr -> 'properties' ->> 'destinationPortRanges' LIKE '%"23"%' + OR sr -> 'properties' ->> 'destinationPortRanges' = '*') + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: medium Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted Telnet Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_udp_access.yaml b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_udp_access.yaml index 048a4e57b..988e5f2cd 100644 --- a/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_udp_access.yaml +++ b/compliance/controls/baseline/azure/network/azure_check_for_unrestricted_udp_access.yaml @@ -1,45 +1,48 @@ +Description: Ensure that no network security groups allow unrestricted inbound access on UDP ports. ID: azure_check_for_unrestricted_udp_access -Title: "Check for Unrestricted UDP Access" -Description: "Ensure that no network security groups allow unrestricted inbound access on UDP ports." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sg.id as resource, - sg.og_account_id, - sg.og_resource_id, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'alarm' - else 'ok' - end as status, - case - when (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') or - (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') then 'The UDP inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' - else 'The UDP inbound access to the associated Microsoft Azure virtual machine(s) is secured.' - end as reason, - sg.resource_group, - display_name as subscription - from - azure_network_security_group as sg, - azure_subscription as sub, - jsonb_array_elements(security_rules) as sr - where - sub.subscription_id = sg.subscription_id and - sr -> 'properties' ->> 'access' = 'Allow' and sr -> 'properties' ->> 'protocol' = 'Udp' and - sr -> 'properties' ->> 'direction' = 'Inbound' - PrimaryTable: azure_network_security_group ListOfTables: - azure_network_security_group - azure_subscription Parameters: [] + PrimaryTable: azure_network_security_group + QueryToExecute: | + SELECT + sg.id AS resource, + sg.og_account_id, + sg.og_resource_id, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (sr -> 'properties' ->> 'sourceAddressPrefix' = '*') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'any') + OR (sr -> 'properties' ->> 'sourceAddressPrefix' = 'internet') + THEN 'The UDP inbound access to the associated Microsoft Azure virtual machine(s) is not secured.' + ELSE 'The UDP inbound access to the associated Microsoft Azure virtual machine(s) is secured.' + END AS reason, + sg.resource_group, + display_name AS subscription + FROM + azure_network_security_group AS sg, + azure_subscription AS sub, + jsonb_array_elements(security_rules) AS sr + WHERE + sub.subscription_id = sg.subscription_id + AND sr -> 'properties' ->> 'access' = 'Allow' + AND sr -> 'properties' ->> 'protocol' = 'Udp' + AND sr -> 'properties' ->> 'direction' = 'Inbound' Severity: medium Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Check for Unrestricted UDP Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_enable_azure_network_watcher.yaml b/compliance/controls/baseline/azure/network/azure_enable_azure_network_watcher.yaml index 0a1e4c606..cb64958ec 100644 --- a/compliance/controls/baseline/azure/network/azure_enable_azure_network_watcher.yaml +++ b/compliance/controls/baseline/azure/network/azure_enable_azure_network_watcher.yaml @@ -1,77 +1,86 @@ +Description: Ensure that Network Watcher is enabled within your Microsoft Azure account subscription. ID: azure_enable_azure_network_watcher -Title: "Enable Azure Network Watcher" -Description: "Ensure that Network Watcher is enabled within your Microsoft Azure account subscription." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - with regions_nw as ( - SELECT subscription_id, array_agg(DISTINCT region) AS regions - FROM azure_network_watcher - GROUP BY subscription_id - ) - - select - sub.id as resource, - sub.og_account_id, - sub.og_resource_id, - case - when nw.regions @> ARRAY[ - 'eastus', 'eastus2', 'southcentralus', 'westus2', 'westus3', - 'australiaeast', 'southeastasia', 'northeurope', 'swedencentral', - 'uksouth', 'westeurope', 'centralus', 'southafricanorth', 'centralindia', - 'eastasia', 'japaneast', 'koreacentral', 'canadacentral', 'francecentral', - 'germanywestcentral', 'norwayeast', 'polandcentral', 'switzerlandnorth', - 'uaenorth', 'brazilsouth', 'centraluseuap', 'eastus2euap', 'qatarcentral', - 'centralusstage', 'eastusstage', 'eastus2stage', 'northcentralusstage', - 'southcentralusstage', 'westusstage', 'westus2stage', 'asia', 'asiapacific', - 'australia', 'brazil', 'canada', 'europe', 'france', 'germany', 'global', - 'india', 'japan', 'korea', 'norway', 'singapore', 'southafrica', 'switzerland', - 'uae', 'uk', 'unitedstates', 'unitedstateseuap', 'eastasiastage', - 'southeastasiastage', 'brazilus', 'eastusstg', 'northcentralus', 'westus', - 'jioindiawest', 'southcentralusstg', 'westcentralus', 'southafricawest', - 'australiacentral', 'australiacentral2', 'australiasoutheast', 'japanwest', - 'jioindiacentral', 'koreasouth', 'southindia', 'westindia', 'canadaeast', - 'francesouth', 'germanynorth', 'norwaywest', 'switzerlandwest', 'ukwest', - 'uaecentral', 'brazilsoutheast' - ] then 'ok' - else 'alarm' - end as status, - case - when nw.regions @> ARRAY[ - 'eastus', 'eastus2', 'southcentralus', 'westus2', 'westus3', - 'australiaeast', 'southeastasia', 'northeurope', 'swedencentral', - 'uksouth', 'westeurope', 'centralus', 'southafricanorth', 'centralindia', - 'eastasia', 'japaneast', 'koreacentral', 'canadacentral', 'francecentral', - 'germanywestcentral', 'norwayeast', 'polandcentral', 'switzerlandnorth', - 'uaenorth', 'brazilsouth', 'centraluseuap', 'eastus2euap', 'qatarcentral', - 'centralusstage', 'eastusstage', 'eastus2stage', 'northcentralusstage', - 'southcentralusstage', 'westusstage', 'westus2stage', 'asia', 'asiapacific', - 'australia', 'brazil', 'canada', 'europe', 'france', 'germany', 'global', - 'india', 'japan', 'korea', 'norway', 'singapore', 'southafrica', 'switzerland', - 'uae', 'uk', 'unitedstates', 'unitedstateseuap', 'eastasiastage', - 'southeastasiastage', 'brazilus', 'eastusstg', 'northcentralus', 'westus', - 'jioindiawest', 'southcentralusstg', 'westcentralus', 'southafricawest', - 'australiacentral', 'australiacentral2', 'australiasoutheast', 'japanwest', - 'jioindiacentral', 'koreasouth', 'southindia', 'westindia', 'canadaeast', - 'francesouth', 'germanynorth', 'norwaywest', 'switzerlandwest', 'ukwest', - 'uaecentral', 'brazilsoutheast' - ] then 'Network watcher is available for all regions for this subscription.' - else 'Network watcher is not available for all regions for this subscription.' - end as reason, - display_name as subscription - from - azure_subscription as sub - left join regions_nw as nw on sub.subscription_id = nw.subscription_id - PrimaryTable: azure_subscription ListOfTables: - azure_network_watcher - azure_subscription Parameters: [] + PrimaryTable: azure_subscription + QueryToExecute: | + WITH regions_nw AS ( + SELECT + subscription_id, + ARRAY_AGG(DISTINCT region) AS regions + FROM + azure_network_watcher + GROUP BY + subscription_id + ) + + SELECT + sub.id AS resource, + sub.og_account_id, + sub.og_resource_id, + CASE + WHEN nw.regions @> ARRAY[ + 'eastus', 'eastus2', 'southcentralus', 'westus2', 'westus3', + 'australiaeast', 'southeastasia', 'northeurope', 'swedencentral', + 'uksouth', 'westeurope', 'centralus', 'southafricanorth', 'centralindia', + 'eastasia', 'japaneast', 'koreacentral', 'canadacentral', 'francecentral', + 'germanywestcentral', 'norwayeast', 'polandcentral', 'switzerlandnorth', + 'uaenorth', 'brazilsouth', 'centraluseuap', 'eastus2euap', 'qatarcentral', + 'centralusstage', 'eastusstage', 'eastus2stage', 'northcentralusstage', + 'southcentralusstage', 'westusstage', 'westus2stage', 'asia', 'asiapacific', + 'australia', 'brazil', 'canada', 'europe', 'france', 'germany', 'global', + 'india', 'japan', 'korea', 'norway', 'singapore', 'southafrica', 'switzerland', + 'uae', 'uk', 'unitedstates', 'unitedstateseuap', 'eastasiastage', + 'southeastasiastage', 'brazilus', 'eastusstg', 'northcentralus', 'westus', + 'jioindiawest', 'southcentralusstg', 'westcentralus', 'southafricawest', + 'australiacentral', 'australiacentral2', 'australiasoutheast', 'japanwest', + 'jioindiacentral', 'koreasouth', 'southindia', 'westindia', 'canadaeast', + 'francesouth', 'germanynorth', 'norwaywest', 'switzerlandwest', 'ukwest', + 'uaecentral', 'brazilsoutheast' + ] + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nw.regions @> ARRAY[ + 'eastus', 'eastus2', 'southcentralus', 'westus2', 'westus3', + 'australiaeast', 'southeastasia', 'northeurope', 'swedencentral', + 'uksouth', 'westeurope', 'centralus', 'southafricanorth', 'centralindia', + 'eastasia', 'japaneast', 'koreacentral', 'canadacentral', 'francecentral', + 'germanywestcentral', 'norwayeast', 'polandcentral', 'switzerlandnorth', + 'uaenorth', 'brazilsouth', 'centraluseuap', 'eastus2euap', 'qatarcentral', + 'centralusstage', 'eastusstage', 'eastus2stage', 'northcentralusstage', + 'southcentralusstage', 'westusstage', 'westus2stage', 'asia', 'asiapacific', + 'australia', 'brazil', 'canada', 'europe', 'france', 'germany', 'global', + 'india', 'japan', 'korea', 'norway', 'singapore', 'southafrica', 'switzerland', + 'uae', 'uk', 'unitedstates', 'unitedstateseuap', 'eastasiastage', + 'southeastasiastage', 'brazilus', 'eastusstg', 'northcentralus', 'westus', + 'jioindiawest', 'southcentralusstg', 'westcentralus', 'southafricawest', + 'australiacentral', 'australiacentral2', 'australiasoutheast', 'japanwest', + 'jioindiacentral', 'koreasouth', 'southindia', 'westindia', 'canadaeast', + 'francesouth', 'germanynorth', 'norwaywest', 'switzerlandwest', 'ukwest', + 'uaecentral', 'brazilsoutheast' + ] + THEN 'Network watcher is available for all regions for this subscription.' + ELSE 'Network watcher is not available for all regions for this subscription.' + END AS reason, + display_name AS subscription + FROM + azure_subscription AS sub + LEFT JOIN + regions_nw AS nw + ON + sub.subscription_id = nw.subscription_id Severity: medium Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Enable Azure Network Watcher \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_enable_ddos_standard_protection_for_virtual_networks.yaml b/compliance/controls/baseline/azure/network/azure_enable_ddos_standard_protection_for_virtual_networks.yaml index 234a9255b..269cccf67 100644 --- a/compliance/controls/baseline/azure/network/azure_enable_ddos_standard_protection_for_virtual_networks.yaml +++ b/compliance/controls/baseline/azure/network/azure_enable_ddos_standard_protection_for_virtual_networks.yaml @@ -1,38 +1,38 @@ +Description: Ensure that DDoS standard protection is enabled for production Azure virtual networks. ID: azure_enable_ddos_standard_protection_for_virtual_networks -Title: "Enable DDoS Standard Protection for Virtual Networks" -Description: "Ensure that DDoS standard protection is enabled for production Azure virtual networks." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_subscription + - azure_virtual_network + Parameters: [] + PrimaryTable: azure_virtual_network QueryToExecute: | - select - vn.id as resource, + SELECT + vn.id AS resource, vn.og_account_id, vn.og_resource_id, - case - when enable_ddos_protection = 'true' then 'ok' - else 'alarm' - end as status, - case - when enable_ddos_protection = 'true' then 'DDOS Protection is enabled.' - else 'DDOS Protection is not enabled.' - end as reason, + CASE + WHEN enable_ddos_protection = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_ddos_protection = 'true' THEN 'DDOS Protection is enabled.' + ELSE 'DDOS Protection is not enabled.' + END AS reason, vn.resource_group, - display_name as subscription - from - azure_virtual_network as vn, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_virtual_network AS vn, + azure_subscription AS sub + WHERE sub.subscription_id = vn.subscription_id - PrimaryTable: azure_virtual_network - ListOfTables: - - azure_subscription - - azure_virtual_network - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Enable DDoS Standard Protection for Virtual Networks \ No newline at end of file diff --git a/compliance/controls/baseline/azure/network/azure_review_network_interfaces_with_ip_forwarding_enabled.yaml b/compliance/controls/baseline/azure/network/azure_review_network_interfaces_with_ip_forwarding_enabled.yaml index df26adb5e..3924bfff0 100644 --- a/compliance/controls/baseline/azure/network/azure_review_network_interfaces_with_ip_forwarding_enabled.yaml +++ b/compliance/controls/baseline/azure/network/azure_review_network_interfaces_with_ip_forwarding_enabled.yaml @@ -1,38 +1,38 @@ +Description: Ensure that the Azure network interfaces with IP forwarding enabled are regularly reviewed. ID: azure_review_network_interfaces_with_ip_forwarding_enabled -Title: "Review Network Interfaces with IP Forwarding Enabled" -Description: "Ensure that the Azure network interfaces with IP forwarding enabled are regularly reviewed." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_network_interface + - azure_subscription + Parameters: [] + PrimaryTable: azure_network_interface QueryToExecute: | - select - ni.id as resource, + SELECT + ni.id AS resource, ni.og_account_id, ni.og_resource_id, - case - when enable_ip_forwarding = 'true' then 'alarm' - else 'ok' - end as status, - case - when enable_ip_forwarding = 'true' then 'NIC resource must be reviewed in order to decide whether or not IP forwarding is required.' - else 'IP forwarding is not enabled.' - end as reason, + CASE + WHEN enable_ip_forwarding = 'true' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN enable_ip_forwarding = 'true' THEN 'NIC resource must be reviewed in order to decide whether or not IP forwarding is required.' + ELSE 'IP forwarding is not enabled.' + END AS reason, ni.resource_group, - display_name as subscription - from - azure_network_interface as ni, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_network_interface AS ni, + azure_subscription AS sub + WHERE sub.subscription_id = ni.subscription_id - PrimaryTable: azure_network_interface - ListOfTables: - - azure_network_interface - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Network score_service_name: - Azure Network -IntegrationType: - - azure_subscription +Title: Review Network Interfaces with IP Forwarding Enabled \ No newline at end of file diff --git a/compliance/controls/baseline/azure/recovery_service/azure_recovery_service_vault_alert_for_job_failures_enabled.yaml b/compliance/controls/baseline/azure/recovery_service/azure_recovery_service_vault_alert_for_job_failures_enabled.yaml index fd17a8f56..c2f6ef490 100644 --- a/compliance/controls/baseline/azure/recovery_service/azure_recovery_service_vault_alert_for_job_failures_enabled.yaml +++ b/compliance/controls/baseline/azure/recovery_service/azure_recovery_service_vault_alert_for_job_failures_enabled.yaml @@ -1,31 +1,32 @@ +Description: Ensure all Recovery Service Vaults alert for job failures are enabled ID: azure_recovery_service_vault_alert_for_job_failures_enabled -Title: "Recovery Service Vault alert for job failures enabled" -Description: "Ensure all Recovery Service Vaults alert for job failures are enabled" +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - v.id as resource, - v.og_resource_id, - v.og_account_id, - case - when v.og_description -> 'Vault' -> 'Properties' -> 'MonitoringSettings' -> 'AzureMonitorAlertSettings' ->> 'AlertsForAllJobFailures' = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when v.og_description -> 'Vault' -> 'Properties' -> 'MonitoringSettings' -> 'AzureMonitorAlertSettings' ->> 'AlertsForAllJobFailures' = 'Enabled' then v.name || ' alert for job failiures is enabled.' - else v.name || ' alert for job failiures is not enabled.' - end as reason, - v.resource_group as resource_group, - sub.display_name as subscription - from - azure_recovery_services_vault as v - left join azure_subscription sub on sub.subscription_id = v.subscription_id; - PrimaryTable: azure_recovery_services_vault ListOfTables: - azure_recovery_services_vault - azure_subscription Parameters: [] + PrimaryTable: azure_recovery_services_vault + QueryToExecute: | + SELECT + v.id AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN v.og_description -> 'Vault' -> 'Properties' -> 'MonitoringSettings' -> 'AzureMonitorAlertSettings' ->> 'AlertsForAllJobFailures' = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.og_description -> 'Vault' -> 'Properties' -> 'MonitoringSettings' -> 'AzureMonitorAlertSettings' ->> 'AlertsForAllJobFailures' = 'Enabled' THEN v.name || ' alert for job failures is enabled.' + ELSE v.name || ' alert for job failures is not enabled.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_recovery_services_vault AS v + LEFT JOIN azure_subscription sub ON sub.subscription_id = v.subscription_id; Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - Azure Recovery Services score_tags: - Lacking High Availability -IntegrationType: - - azure_subscription +Title: Recovery Service Vault alert for job failures enabled \ No newline at end of file diff --git a/compliance/controls/baseline/azure/recovery_service/azure_recovery_service_vault_not_publicly_accessible_and_not_encrypted.yaml b/compliance/controls/baseline/azure/recovery_service/azure_recovery_service_vault_not_publicly_accessible_and_not_encrypted.yaml index 278e15725..9d12f5ead 100644 --- a/compliance/controls/baseline/azure/recovery_service/azure_recovery_service_vault_not_publicly_accessible_and_not_encrypted.yaml +++ b/compliance/controls/baseline/azure/recovery_service/azure_recovery_service_vault_not_publicly_accessible_and_not_encrypted.yaml @@ -1,31 +1,36 @@ +Description: Ensure Recovery Service Vaults are not publicly accessible and not encrypted ID: azure_recovery_service_vault_not_publicly_accessible_and_not_encrypted -Title: "Recovery Service Vault not publicly accessible and not encrypted" -Description: "Ensure Recovery Service Vaults are not publicly accessible and not encrypted" +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - v.id as resource, - v.og_resource_id, - v.og_account_id, - case - when v.og_description -> 'Vault' -> 'Properties' ->> 'Encryption' is null and v.og_description -> 'Vault' -> 'Properties' ->> 'PublicNetworkAccess' = 'Enabled' then 'alarm' - else 'ok' - end as status, - case - when v.og_description -> 'Vault' -> 'Properties' ->> 'Encryption' is null and v.og_description -> 'Vault' -> 'Properties' ->> 'PublicNetworkAccess' = 'Enabled' then v.name || ' is not encrypted and publicly accessible.' - else v.name || ' is not publicly accessible.' - end as reason, - v.resource_group as resource_group, - sub.display_name as subscription - from - azure_recovery_services_vault as v - left join azure_subscription sub on sub.subscription_id = v.subscription_id - PrimaryTable: azure_recovery_services_vault ListOfTables: - azure_recovery_services_vault - azure_subscription Parameters: [] + PrimaryTable: azure_recovery_services_vault + QueryToExecute: | + SELECT + v.id AS resource, + v.og_resource_id, + v.og_account_id, + CASE + WHEN v.og_description -> 'Vault' -> 'Properties' ->> 'Encryption' IS NULL + AND v.og_description -> 'Vault' -> 'Properties' ->> 'PublicNetworkAccess' = 'Enabled' + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN v.og_description -> 'Vault' -> 'Properties' ->> 'Encryption' IS NULL + AND v.og_description -> 'Vault' -> 'Properties' ->> 'PublicNetworkAccess' = 'Enabled' + THEN v.name || ' is not encrypted and publicly accessible.' + ELSE v.name || ' is not publicly accessible.' + END AS reason, + v.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_recovery_services_vault AS v + LEFT JOIN azure_subscription AS sub ON sub.subscription_id = v.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +41,4 @@ Tags: - Azure Recovery Services score_tags: - Unencrypted Storage -IntegrationType: - - azure_subscription +Title: Recovery Service Vault not publicly accessible and not encrypted \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_advanced_data_security_for_sql_servers.yaml b/compliance/controls/baseline/azure/sql/azure_advanced_data_security_for_sql_servers.yaml index 826d0b777..c66ae56fa 100644 --- a/compliance/controls/baseline/azure/sql/azure_advanced_data_security_for_sql_servers.yaml +++ b/compliance/controls/baseline/azure/sql/azure_advanced_data_security_for_sql_servers.yaml @@ -1,32 +1,34 @@ +Description: Ensure that database auditing is enabled at the Azure SQL database server level. ID: azure_enable_auditing_for_sql_servers -Title: "Enable Auditing for SQL Servers" -Description: "Ensure that database auditing is enabled at the Azure SQL database server level." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when security -> 'properties' ->> 'state' = 'Disabled' then 'advanced data security is disabled.' - else 'advanced data security is enabled.' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id, - jsonb_array_elements(server_security_alert_policy) as security - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'advanced data security is disabled.' + ELSE 'advanced data security is enabled.' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS s + LEFT JOIN + azure_subscription AS sub ON s.subscription_id = sub.subscription_id, + jsonb_array_elements(server_security_alert_policy) AS security Severity: medium Tags: platform_score_cloud_service_name: @@ -37,5 +39,4 @@ Tags: - Azure Managed SQL Service score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Enable Auditing for SQL Servers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_check_for_publicly_accessible_sql_servers.yaml b/compliance/controls/baseline/azure/sql/azure_check_for_publicly_accessible_sql_servers.yaml index 5d8b37771..35c6cdc75 100644 --- a/compliance/controls/baseline/azure/sql/azure_check_for_publicly_accessible_sql_servers.yaml +++ b/compliance/controls/baseline/azure/sql/azure_check_for_publicly_accessible_sql_servers.yaml @@ -1,33 +1,34 @@ +Description: Ensure that Azure SQL database servers are accessible via private endpoints only. ID: azure_check_for_publicly_accessible_sql_servers -Title: "Check for Publicly Accessible SQL Servers" -Description: "Ensure that Azure SQL database servers are accessible via private endpoints only." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - a.name as resource, - a.og_resource_id, - a.og_account_id, - case - when public_network_access != 'Disabled' then 'alarm' - else 'ok' - end as status, - case - when public_network_access != 'Disabled' then a.name || ' not uses private link.' - else a.name || ' uses private link.' - end as reason, - a.resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as a, - azure_subscription as sub - where - sub.subscription_id = a.subscription_id; - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + a.name AS resource, + a.og_resource_id, + a.og_account_id, + CASE + WHEN public_network_access != 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN public_network_access != 'Disabled' THEN a.name || ' not uses private link.' + ELSE a.name || ' uses private link.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: high Tags: platform_score_cloud_service_name: @@ -38,5 +39,4 @@ Tags: - Azure Managed SQL Service score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Check for Publicly Accessible SQL Servers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_check_for_sufficient_point_in_time_restore_pitr_backup_retention_period.yaml b/compliance/controls/baseline/azure/sql/azure_check_for_sufficient_point_in_time_restore_pitr_backup_retention_period.yaml index c293aad8b..a340cef1b 100644 --- a/compliance/controls/baseline/azure/sql/azure_check_for_sufficient_point_in_time_restore_pitr_backup_retention_period.yaml +++ b/compliance/controls/baseline/azure/sql/azure_check_for_sufficient_point_in_time_restore_pitr_backup_retention_period.yaml @@ -1,31 +1,33 @@ +Description: Ensure there is a sufficient PITR backup retention period configured for Azure SQL databases. ID: azure_check_for_sufficient_point_in_time_restore_pitr_backup_retention_period -Title: "Check for Sufficient Point in Time Restore (PITR) Backup Retention Period" -Description: "Ensure there is a sufficient PITR backup retention period configured for Azure SQL databases." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when (p -> 'properties' ->> 'retentionDays')::int < '{{.azureDatabaseServerRetentionPeriodDays}}'::int then 'alarm' - else 'ok' - end as status, - name || ' backup retention period set to ' || (p -> 'properties' ->> 'retentionDays') || '.' as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id, - jsonb_array_elements(server_audit_policy) as p - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: - Key: azureDatabaseServerRetentionPeriodDays Required: true + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN (p -> 'properties' ->> 'retentionDays')::int < '{{.azureDatabaseServerRetentionPeriodDays}}'::int THEN 'alarm' + ELSE 'ok' + END AS status, + name || ' backup retention period set to ' || (p -> 'properties' ->> 'retentionDays') || '.' AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS s + LEFT JOIN azure_subscription AS sub + ON s.subscription_id = sub.subscription_id, + jsonb_array_elements(server_audit_policy) AS p Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +38,4 @@ Tags: - Azure Managed SQL Service score_tags: - Missing Backup -IntegrationType: - - azure_subscription +Title: Check for Sufficient Point in Time Restore (PITR) Backup Retention Period \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_check_for_unrestricted_sql_database_access.yaml b/compliance/controls/baseline/azure/sql/azure_check_for_unrestricted_sql_database_access.yaml index aaf28693d..a9d4330eb 100644 --- a/compliance/controls/baseline/azure/sql/azure_check_for_unrestricted_sql_database_access.yaml +++ b/compliance/controls/baseline/azure/sql/azure_check_for_unrestricted_sql_database_access.yaml @@ -1,32 +1,38 @@ +Description: Ensure that no SQL databases allow unrestricted inbound access from 0.0.0.0/0 (any IP address). ID: azure_check_for_unrestricted_sql_database_access -Title: "Check for Unrestricted SQL Database Access" -Description: "Ensure that no SQL databases allow unrestricted inbound access from 0.0.0.0/0 (any IP address)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when s.public_network_access = 'Enabled' and (r -> 'properties' ->> 'startIpAddress' = '0.0.0.0') then 'alarm' - else 'ok' - end as status, - case - when s.public_network_access = 'Enabled' and (r -> 'properties' ->> 'startIpAddress' = '0.0.0.0') then 'allows unrestricted ingress/inbound access for all the SQL databases hosted on the server.' - else 'does not allow unrestricted ingress/inbound access for all the SQL databases hosted on the server.' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id, - jsonb_array_elements(firewall_rules) as r - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN s.public_network_access = 'Enabled' + AND (r -> 'properties' ->> 'startIpAddress' = '0.0.0.0') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.public_network_access = 'Enabled' + AND (r -> 'properties' ->> 'startIpAddress' = '0.0.0.0') THEN + 'allows unrestricted ingress/inbound access for all the SQL databases hosted on the server.' + ELSE + 'does not allow unrestricted ingress/inbound access for all the SQL databases hosted on the server.' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS s + LEFT JOIN azure_subscription AS sub + ON s.subscription_id = sub.subscription_id, + jsonb_array_elements(firewall_rules) AS r Severity: critical Tags: platform_score_cloud_service_name: @@ -37,5 +43,4 @@ Tags: - Azure Managed SQL Service score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Check for Unrestricted SQL Database Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_configure_audit_action_group_for_sql_server_auditing.yaml b/compliance/controls/baseline/azure/sql/azure_configure_audit_action_group_for_sql_server_auditing.yaml index a69cc153a..b1dc0e01d 100644 --- a/compliance/controls/baseline/azure/sql/azure_configure_audit_action_group_for_sql_server_auditing.yaml +++ b/compliance/controls/baseline/azure/sql/azure_configure_audit_action_group_for_sql_server_auditing.yaml @@ -1,37 +1,48 @@ +Description: Ensure that "AuditActionGroup" property is well configured at the Azure SQL database server level. ID: azure_configure_audit_action_group_for_sql_server_auditing -Title: "Configure \"AuditActionGroup\" for SQL Server Auditing" -Description: "Ensure that \"AuditActionGroup\" property is well configured at the Azure SQL database server level." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when (select ARRAY_AGG(g) from jsonb_array_elements_text(ap -> 'properties' -> 'auditActionsAndGroups') as g) @> ARRAY['SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP','FAILED_DATABASE_AUTHENTICATION_GROUP','BATCH_COMPLETED_GROUP'] then 'ok' - else 'alarm' - end as status, - case - when (select ARRAY_AGG(g) from jsonb_array_elements_text(ap -> 'properties' -> 'auditActionsAndGroups') as g) @> ARRAY['SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP','FAILED_DATABASE_AUTHENTICATION_GROUP','BATCH_COMPLETED_GROUP'] then 'AuditActionGroup property configuration for the selected Microsoft Azure SQL database server is compliant' - else 'AuditActionGroup property configuration for the selected Microsoft Azure SQL database server is not compliant' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id, - jsonb_array_elements(server_audit_policy) as ap - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN ( + SELECT ARRAY_AGG(g) + FROM jsonb_array_elements_text(ap -> 'properties' -> 'auditActionsAndGroups') AS g + ) @> ARRAY['SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP', 'FAILED_DATABASE_AUTHENTICATION_GROUP', 'BATCH_COMPLETED_GROUP'] + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ( + SELECT ARRAY_AGG(g) + FROM jsonb_array_elements_text(ap -> 'properties' -> 'auditActionsAndGroups') AS g + ) @> ARRAY['SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP', 'FAILED_DATABASE_AUTHENTICATION_GROUP', 'BATCH_COMPLETED_GROUP'] + THEN 'AuditActionGroup property configuration for the selected Microsoft Azure SQL database server is compliant' + ELSE 'AuditActionGroup property configuration for the selected Microsoft Azure SQL database server is not compliant' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS s + LEFT JOIN + azure_subscription AS sub + ON + s.subscription_id = sub.subscription_id, + jsonb_array_elements(server_audit_policy) AS ap Severity: medium Tags: platform_score_cloud_service_name: - Azure Managed SQL Service score_service_name: - Azure Managed SQL Service -IntegrationType: - - azure_subscription +Title: Configure "AuditActionGroup" for SQL Server Auditing \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_configure_emails_for_vulnerability_assessment_scan_reports_and_alerts.yaml b/compliance/controls/baseline/azure/sql/azure_configure_emails_for_vulnerability_assessment_scan_reports_and_alerts.yaml index 58fcf9f91..f3e0bcf18 100644 --- a/compliance/controls/baseline/azure/sql/azure_configure_emails_for_vulnerability_assessment_scan_reports_and_alerts.yaml +++ b/compliance/controls/baseline/azure/sql/azure_configure_emails_for_vulnerability_assessment_scan_reports_and_alerts.yaml @@ -1,32 +1,33 @@ +Description: Ensure that "Send scan reports to" setting is configured for SQL database servers. ID: azure_configure_emails_for_vulnerability_assessment_scan_reports_and_alerts -Title: "Configure Emails for Vulnerability Assessment Scan Reports and Alerts" -Description: "Ensure that \"Send scan reports to\" setting is configured for SQL database servers." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when vs -> 'properties' -> 'recurringScans' ->> 'emails' is null then 'alarm' - else 'ok' - end as status, - case - when vs -> 'properties' -> 'recurringScans' ->> 'emails' is null then 'allows unrestricted ingress/inbound access for all the SQL databases hosted on the server.' - else 'does not allow unrestricted ingress/inbound access for all the SQL databases hosted on the server.' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id, - jsonb_array_elements(server_vulnerability_assessment) as vs - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN vs -> 'properties' -> 'recurringScans' ->> 'emails' IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vs -> 'properties' -> 'recurringScans' ->> 'emails' IS NULL THEN 'allows unrestricted ingress/inbound access for all the SQL databases hosted on the server.' + ELSE 'does not allow unrestricted ingress/inbound access for all the SQL databases hosted on the server.' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS s + LEFT JOIN azure_subscription AS sub ON s.subscription_id = sub.subscription_id, + JSONB_ARRAY_ELEMENTS(server_vulnerability_assessment) AS vs Severity: medium Tags: platform_score_cloud_service_name: @@ -37,5 +38,4 @@ Tags: - Azure Managed SQL Service score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Configure Emails for Vulnerability Assessment Scan Reports and Alerts \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_enable_all_types_of_threat_detection_on_sql_servers.yaml b/compliance/controls/baseline/azure/sql/azure_enable_all_types_of_threat_detection_on_sql_servers.yaml index defd9187f..b013c967d 100644 --- a/compliance/controls/baseline/azure/sql/azure_enable_all_types_of_threat_detection_on_sql_servers.yaml +++ b/compliance/controls/baseline/azure/sql/azure_enable_all_types_of_threat_detection_on_sql_servers.yaml @@ -1,34 +1,35 @@ +Description: Enable all types of threat detection for your Microsoft Azure SQL database servers. ID: azure_enable_all_types_of_threat_detection_on_sql_servers -Title: "Enable All Types of Threat Detection on SQL Servers" -Description: "Enable all types of threat detection for your Microsoft Azure SQL database servers." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when alert_length = 1 and disabled_alerts = '' then 'ok' - else 'alarm' - end as status, - case - when alert_length = 1 and disabled_alerts = '' then 'send notification alerts for all types of threats detected for the selected SQL server.' - else 'does not send notification alerts for all types of threats detected for the selected SQL server.' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id, - jsonb_array_elements(server_security_alert_policy) as security, - jsonb_array_elements_text(security -> 'properties' -> 'disabledAlerts') as disabled_alerts, - jsonb_array_length(security -> 'properties' -> 'disabledAlerts') as alert_length - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN alert_length = 1 AND disabled_alerts = '' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN alert_length = 1 AND disabled_alerts = '' THEN 'send notification alerts for all types of threats detected for the selected SQL server.' + ELSE 'does not send notification alerts for all types of threats detected for the selected SQL server.' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS s + LEFT JOIN azure_subscription AS sub ON s.subscription_id = sub.subscription_id, + jsonb_array_elements(server_security_alert_policy) AS security, + jsonb_array_elements_text(security -> 'properties' -> 'disabledAlerts') AS disabled_alerts, + jsonb_array_length(security -> 'properties' -> 'disabledAlerts') AS alert_length Severity: high Tags: platform_score_cloud_service_name: @@ -39,5 +40,4 @@ Tags: - Azure Managed SQL Service score_tags: - Problem Identities -IntegrationType: - - azure_subscription +Title: Enable All Types of Threat Detection on SQL Servers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_enable_auditing_for_sql_servers.yaml b/compliance/controls/baseline/azure/sql/azure_enable_auditing_for_sql_servers.yaml index ea2983ce7..19da5fd60 100644 --- a/compliance/controls/baseline/azure/sql/azure_enable_auditing_for_sql_servers.yaml +++ b/compliance/controls/baseline/azure/sql/azure_enable_auditing_for_sql_servers.yaml @@ -1,41 +1,38 @@ +Description: Enable all types of threat detection for your Microsoft Azure SQL database servers. ID: azure_enable_all_types_of_threat_detection_on_sql_servers -Title: "Enable All Types of Threat Detection on SQL Servers" -Description: "Enable all types of threat detection for your Microsoft Azure SQL database servers." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - with sql_server_audit_enabled as ( - select - distinct id - from - azure_sql_server as s, - jsonb_array_elements(server_audit_policy) as audit - where - audit -> 'properties' ->> 'state' = 'Enabled' - ) - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when a.id is not null then 'ok' - else 'alarm' - end as status, - case - when a.id is not null then 'auditing is enabled for server.' - else 'auditing is not enabled for server.' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - left join sql_server_audit_enabled as a on lower(s.id) = lower(a.id); - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + WITH sql_server_audit_enabled AS ( + SELECT DISTINCT id + FROM azure_sql_server AS s, + jsonb_array_elements(server_audit_policy) AS audit + WHERE audit -> 'properties' ->> 'state' = 'Enabled' + ) + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN a.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.id IS NOT NULL THEN 'auditing is enabled for server.' + ELSE 'auditing is not enabled for server.' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM azure_sql_server AS s + LEFT JOIN azure_subscription AS sub ON s.subscription_id = sub.subscription_id + LEFT JOIN sql_server_audit_enabled AS a ON LOWER(s.id) = LOWER(a.id); Severity: high Tags: platform_score_cloud_service_name: @@ -46,5 +43,4 @@ Tags: - Azure Managed SQL Service score_tags: - Problem Identities -IntegrationType: - - azure_subscription +Title: Enable All Types of Threat Detection on SQL Servers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_enable_auto_failover_groups.yaml b/compliance/controls/baseline/azure/sql/azure_enable_auto_failover_groups.yaml index 9ab89c450..a98b220ef 100644 --- a/compliance/controls/baseline/azure/sql/azure_enable_auto_failover_groups.yaml +++ b/compliance/controls/baseline/azure/sql/azure_enable_auto_failover_groups.yaml @@ -1,31 +1,35 @@ +Description: Ensure that your Azure SQL database servers are configured to use auto-failover groups. ID: azure_enable_auto_failover_groups -Title: "Enable Auto-Failover Groups" -Description: "Ensure that your Azure SQL database servers are configured to use auto-failover groups." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - s.name as resource, - s.og_resource_id, - s.og_account_id, - case - when failover_groups is null then 'alarm' - else 'ok' - end as status, - case - when failover_groups is null then 'Automatic Failover Group feature is not enabled.' - else 'Automatic Failover Group feature is enabled.' - end as reason, - s.resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN failover_groups IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN failover_groups IS NULL THEN 'Automatic Failover Group feature is not enabled.' + ELSE 'Automatic Failover Group feature is enabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS s + LEFT JOIN + azure_subscription AS sub + ON + s.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +40,4 @@ Tags: - Azure Managed SQL Service score_tags: - Missing Backup -IntegrationType: - - azure_subscription +Title: Enable Auto-Failover Groups \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_enable_automatic_tuning_for_sql_database_servers.yaml b/compliance/controls/baseline/azure/sql/azure_enable_automatic_tuning_for_sql_database_servers.yaml index 354ab4cbe..2c737de8b 100644 --- a/compliance/controls/baseline/azure/sql/azure_enable_automatic_tuning_for_sql_database_servers.yaml +++ b/compliance/controls/baseline/azure/sql/azure_enable_automatic_tuning_for_sql_database_servers.yaml @@ -1,33 +1,38 @@ +Description: Ensure that Automatic Tuning feature is enabled for Microsoft Azure SQL database servers. ID: azure_enable_automatic_tuning_for_sql_database_servers -Title: "Enable Automatic Tuning for SQL Database Servers" -Description: "Ensure that Automatic Tuning feature is enabled for Microsoft Azure SQL database servers." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - s.name as resource, - s.og_resource_id, - s.og_account_id, - case - when s.automatic_tuning -> 'properties' -> 'options' -> 'forceLastGoodPlan' ->> 'actualState' = 'On' or s.automatic_tuning -> 'properties' -> 'options' -> 'dropIndex' ->> 'actualState' = 'On' or s.automatic_tuning -> 'properties' -> 'options' -> 'createIndex' ->> 'actualState' = 'On' or - s.automatic_tuning -> 'properties' -> 'options' -> 'maintainIndex' ->> 'actualState' = 'On' then 'ok' - else 'alarm' - end as status, - case - when s.automatic_tuning -> 'properties' -> 'options' -> 'forceLastGoodPlan' ->> 'actualState' = 'On' or s.automatic_tuning -> 'properties' -> 'options' -> 'dropIndex' ->> 'actualState' = 'On' or s.automatic_tuning -> 'properties' -> 'options' -> 'createIndex' ->> 'actualState' = 'On' or - s.automatic_tuning -> 'properties' -> 'options' -> 'maintainIndex' ->> 'actualState' = 'On' then 'Automatic Tuning feature is enabled.' - else 'Automatic Tuning feature is not enabled.' - end as reason, - s.resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + s.name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN s.automatic_tuning -> 'properties' -> 'options' -> 'forceLastGoodPlan' ->> 'actualState' = 'On' + OR s.automatic_tuning -> 'properties' -> 'options' -> 'dropIndex' ->> 'actualState' = 'On' + OR s.automatic_tuning -> 'properties' -> 'options' -> 'createIndex' ->> 'actualState' = 'On' + OR s.automatic_tuning -> 'properties' -> 'options' -> 'maintainIndex' ->> 'actualState' = 'On' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.automatic_tuning -> 'properties' -> 'options' -> 'forceLastGoodPlan' ->> 'actualState' = 'On' + OR s.automatic_tuning -> 'properties' -> 'options' -> 'dropIndex' ->> 'actualState' = 'On' + OR s.automatic_tuning -> 'properties' -> 'options' -> 'createIndex' ->> 'actualState' = 'On' + OR s.automatic_tuning -> 'properties' -> 'options' -> 'maintainIndex' ->> 'actualState' = 'On' THEN 'Automatic Tuning feature is enabled.' + ELSE 'Automatic Tuning feature is not enabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS s + LEFT JOIN azure_subscription AS sub ON s.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -38,5 +43,4 @@ Tags: - Azure Managed SQL Service score_tags: - Missing Backup -IntegrationType: - - azure_subscription +Title: Enable Automatic Tuning for SQL Database Servers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_enable_in_transit_encryption_for_mysql_servers.yaml b/compliance/controls/baseline/azure/sql/azure_enable_in_transit_encryption_for_mysql_servers.yaml index e984893ab..fabe4d6ad 100644 --- a/compliance/controls/baseline/azure/sql/azure_enable_in_transit_encryption_for_mysql_servers.yaml +++ b/compliance/controls/baseline/azure/sql/azure_enable_in_transit_encryption_for_mysql_servers.yaml @@ -1,36 +1,39 @@ +Description: Ensure that in-transit encryption is enabled for your Azure MySQL database servers. ID: azure_enable_in_transit_encryption_for_mysql_servers -Title: "Enable In-Transit Encryption for MySQL Servers" -Description: "Ensure that in-transit encryption is enabled for your Azure MySQL database servers." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - s.name as resource, - s.og_resource_id, - s.og_account_id, - case - when ssl_enforcement = 'Enabled' then 'ok' - else 'alarm' - end as status, - case - when ssl_enforcement = 'Enabled' then s.name || ' encryption in transit using Secure Sockets Layer (SSL) is enabled.' - else s.name || ' encryption in transit using Secure Sockets Layer (SSL) is not enabled.' - end as reason, - s.resource_group as resource_group, - sub.display_name as subscription - from - azure_mysql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - PrimaryTable: azure_mysql_server ListOfTables: - azure_mysql_server - azure_subscription Parameters: [] + PrimaryTable: azure_mysql_server + QueryToExecute: | + SELECT + s.name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN ssl_enforcement = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ssl_enforcement = 'Enabled' THEN s.name || ' encryption in transit using Secure Sockets Layer (SSL) is enabled.' + ELSE s.name || ' encryption in transit using Secure Sockets Layer (SSL) is not enabled.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_mysql_server AS s + LEFT JOIN + azure_subscription AS sub + ON + s.subscription_id = sub.subscription_id Severity: high Tags: platform_score_cloud_service_name: - Azure Database for MySQL score_service_name: - Azure Database for MySQL -IntegrationType: - - azure_subscription +Title: Enable In-Transit Encryption for MySQL Servers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_enable_transparent_data_encryption_for_sql_managed_instance_using_customer_managed_keys.yaml b/compliance/controls/baseline/azure/sql/azure_enable_transparent_data_encryption_for_sql_managed_instance_using_customer_managed_keys.yaml index 4bee941cd..1548b1e3e 100644 --- a/compliance/controls/baseline/azure/sql/azure_enable_transparent_data_encryption_for_sql_managed_instance_using_customer_managed_keys.yaml +++ b/compliance/controls/baseline/azure/sql/azure_enable_transparent_data_encryption_for_sql_managed_instance_using_customer_managed_keys.yaml @@ -1,34 +1,35 @@ +Description: Ensure that Azure SQL managed instances are encrypted at rest using Customer-Managed Keys (CMKs). ID: azure_enable_transparent_data_encryption_for_sql_managed_instance_using_customer_managed_keys -Title: "Enable Transparent Data Encryption for SQL Managed Instance using Customer-Managed Keys" -Description: "Ensure that Azure SQL managed instances are encrypted at rest using Customer-Managed Keys (CMKs)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_sql_server + - azure_subscription + Parameters: [] + PrimaryTable: azure_sql_server QueryToExecute: | - select - s.id as resource, + SELECT + s.id AS resource, s.og_resource_id, s.og_account_id, - case - when encryption ->> 'kind' = 'servicemanaged' then 'alarm' - else 'ok' - end as status, - case - when encryption ->> 'kind' = 'servicemanaged' then s.name || ' TDE protector not encrypted with CMK.' - else s.name || ' TDE protector encrypted with CMK.' - end as reason, - s.resource_group as resource_group, - sub.display_name as subscription - from + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN s.name || ' TDE protector not encrypted with CMK.' + ELSE s.name || ' TDE protector encrypted with CMK.' + END AS reason, + s.resource_group AS resource_group, + sub.display_name AS subscription + FROM azure_sql_server s, jsonb_array_elements(encryption_protector) encryption, azure_subscription sub - where + WHERE sub.subscription_id = s.subscription_id - PrimaryTable: azure_sql_server - ListOfTables: - - azure_sql_server - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -39,5 +40,4 @@ Tags: - Azure Managed SQL Service score_tags: - Tolerate Failures -IntegrationType: - - azure_subscription +Title: Enable Transparent Data Encryption for SQL Managed Instance using Customer-Managed Keys \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_email_notifications_for_admins_and_subscription_owners.yaml b/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_email_notifications_for_admins_and_subscription_owners.yaml index 9cda492b8..248321e25 100644 --- a/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_email_notifications_for_admins_and_subscription_owners.yaml +++ b/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_email_notifications_for_admins_and_subscription_owners.yaml @@ -1,39 +1,40 @@ +Description: Ensure that the Vulnerability Assessment setting "Also send email notification to admins and subscription owners" is enabled for your Microsoft SQL database servers. ID: azure_enable_vulnerability_assessment_email_notifications_for_admins_and_subscription_owners -Title: "Enable Vulnerability Assessment Email Notifications for Admins and Subscription Owners" -Description: "Ensure that the Vulnerability Assessment setting \"Also send email notification to admins and subscription owners\" is enabled for your Microsoft SQL database servers." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_sql_server + - azure_subscription + Parameters: [] + PrimaryTable: azure_sql_server QueryToExecute: | - with sql_server_va as ( - select - distinct id - from - azure_sql_server as s, - jsonb_array_elements(server_vulnerability_assessment) as va - where + WITH sql_server_va AS ( + SELECT + DISTINCT id + FROM + azure_sql_server AS s, + JSONB_ARRAY_ELEMENTS(server_vulnerability_assessment) AS va + WHERE va -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'true' ) - select - name as resource, + SELECT + name AS resource, s.og_resource_id, s.og_account_id, - case - when v.id is not null then 'ok' - else 'alarm' - end as status, - case - when v.id is not null then 'Vulnerability Assessment Email Notifications is enabled' - else 'Vulnerability Assessment Email Notifications is not enabled' - end as reason - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - left join sql_server_va as v on lower(s.id) = lower(v.id) - PrimaryTable: azure_sql_server - ListOfTables: - - azure_sql_server - - azure_subscription - Parameters: [] + CASE + WHEN v.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.id IS NOT NULL THEN 'Vulnerability Assessment Email Notifications is enabled' + ELSE 'Vulnerability Assessment Email Notifications is not enabled' + END AS reason + FROM + azure_sql_server AS s + LEFT JOIN azure_subscription AS sub ON s.subscription_id = sub.subscription_id + LEFT JOIN sql_server_va AS v ON LOWER(s.id) = LOWER(v.id) Severity: medium Tags: platform_score_cloud_service_name: @@ -44,5 +45,4 @@ Tags: - Azure Managed SQL Service score_tags: - Problem Identities -IntegrationType: - - azure_subscription +Title: Enable Vulnerability Assessment Email Notifications for Admins and Subscription Owners \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_for_microsoft_sql_servers.yaml b/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_for_microsoft_sql_servers.yaml index 1d47fc39e..df582a024 100644 --- a/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_for_microsoft_sql_servers.yaml +++ b/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_for_microsoft_sql_servers.yaml @@ -1,39 +1,40 @@ +Description: Ensure that Vulnerability Assessment is enabled for Microsoft SQL database servers. ID: azure_enable_vulnerability_assessment_for_microsoft_sql_servers -Title: "Enable Vulnerability Assessment for Microsoft SQL Servers" -Description: "Ensure that Vulnerability Assessment is enabled for Microsoft SQL database servers." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - with sql_server_va as ( - select - distinct id - from - azure_sql_server as s, - jsonb_array_elements(server_vulnerability_assessment) as va - where - va -> 'properties' -> 'storageContainerPath' is not null - ) - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when v.id is not null then 'ok' - else 'alarm' - end as status, - case - when v.id is not null then 'Vulnerability Assessment is enabled' - else 'Vulnerability Assessment Recurring is not enabled' - end as reason - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - left join sql_server_va as v on lower(s.id) = lower(v.id) - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + WITH sql_server_va AS ( + SELECT + DISTINCT id + FROM + azure_sql_server AS s, + jsonb_array_elements(server_vulnerability_assessment) AS va + WHERE + va -> 'properties' -> 'storageContainerPath' IS NOT NULL + ) + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN v.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.id IS NOT NULL THEN 'Vulnerability Assessment is enabled' + ELSE 'Vulnerability Assessment Recurring is not enabled' + END AS reason + FROM + azure_sql_server AS s + LEFT JOIN azure_subscription AS sub ON s.subscription_id = sub.subscription_id + LEFT JOIN sql_server_va AS v ON LOWER(s.id) = LOWER(v.id) Severity: medium Tags: platform_score_cloud_service_name: @@ -44,5 +45,4 @@ Tags: - Azure Managed SQL Service score_tags: - Problem Identities -IntegrationType: - - azure_subscription +Title: Enable Vulnerability Assessment for Microsoft SQL Servers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_periodic_recurring_scans.yaml b/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_periodic_recurring_scans.yaml index 213088de7..73914e47d 100644 --- a/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_periodic_recurring_scans.yaml +++ b/compliance/controls/baseline/azure/sql/azure_enable_vulnerability_assessment_periodic_recurring_scans.yaml @@ -1,39 +1,40 @@ +Description: Ensure that the Vulnerability Assessment Periodic Recurring Scans setting is enabled for SQL database servers. ID: azure_enable_vulnerability_assessment_periodic_recurring_scans -Title: "Enable Vulnerability Assessment Periodic Recurring Scans" -Description: "Ensure that the Vulnerability Assessment Periodic Recurring Scans setting is enabled for SQL database servers." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_sql_server + - azure_subscription + Parameters: [] + PrimaryTable: azure_sql_server QueryToExecute: | - with sql_server_va as ( - select - distinct id - from - azure_sql_server as s, - jsonb_array_elements(server_vulnerability_assessment) as va - where + WITH sql_server_va AS ( + SELECT + DISTINCT id + FROM + azure_sql_server AS s, + jsonb_array_elements(server_vulnerability_assessment) AS va + WHERE va -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'true' ) - select - name as resource, + SELECT + name AS resource, s.og_resource_id, s.og_account_id, - case - when v.id is not null then 'ok' - else 'alarm' - end as status, - case - when v.id is not null then 'Vulnerability Assessment Recurring Scan is enabled' - else 'Vulnerability Assessment Recurring Scan is not enabled' - end as reason - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - left join sql_server_va as v on lower(s.id) = lower(v.id) - PrimaryTable: azure_sql_server - ListOfTables: - - azure_sql_server - - azure_subscription - Parameters: [] + CASE + WHEN v.id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.id IS NOT NULL THEN 'Vulnerability Assessment Recurring Scan is enabled' + ELSE 'Vulnerability Assessment Recurring Scan is not enabled' + END AS reason + FROM + azure_sql_server AS s + LEFT JOIN azure_subscription AS sub ON s.subscription_id = sub.subscription_id + LEFT JOIN sql_server_va AS v ON LOWER(s.id) = LOWER(v.id) Severity: medium Tags: platform_score_cloud_service_name: @@ -44,5 +45,4 @@ Tags: - Azure Managed SQL Service score_tags: - Problem Identities -IntegrationType: - - azure_subscription +Title: Enable Vulnerability Assessment Periodic Recurring Scans \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_restrict_default_network_access_for_azure_cosmos_db_accounts.yaml b/compliance/controls/baseline/azure/sql/azure_restrict_default_network_access_for_azure_cosmos_db_accounts.yaml index ef4b5f857..392f267ad 100644 --- a/compliance/controls/baseline/azure/sql/azure_restrict_default_network_access_for_azure_cosmos_db_accounts.yaml +++ b/compliance/controls/baseline/azure/sql/azure_restrict_default_network_access_for_azure_cosmos_db_accounts.yaml @@ -1,31 +1,32 @@ +Description: Ensure that default network access (i.e. public access) is denied within your Azure Cosmos DB account configuration. ID: azure_restrict_default_network_access_for_azure_cosmos_db_accounts -Title: "Restrict Default Network Access for Azure Cosmos DB Accounts" -Description: "Ensure that default network access (i.e. public access) is denied within your Azure Cosmos DB account configuration." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - a.og_resource_id, - a.og_account_id, - case - when not is_virtual_network_filter_enabled and ip_rules is null then 'alarm' - else 'ok' - end as status, - case - when not is_virtual_network_filter_enabled and ip_rules is null then 'all networks can access' - else name || 'network access is filtered' - end as reason, - a.resource_group as resource_group, - sub.display_name as subscription - from - azure_cosmosdb_account as a - left join azure_subscription as sub on a.subscription_id = sub.subscription_id - PrimaryTable: azure_cosmosdb_account ListOfTables: - azure_cosmosdb_account - azure_subscription Parameters: [] + PrimaryTable: azure_cosmosdb_account + QueryToExecute: | + SELECT + name AS resource, + a.og_resource_id, + a.og_account_id, + CASE + WHEN NOT is_virtual_network_filter_enabled AND ip_rules IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT is_virtual_network_filter_enabled AND ip_rules IS NULL THEN 'all networks can access' + ELSE name || ' network access is filtered' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_cosmosdb_account AS a + LEFT JOIN azure_subscription AS sub ON a.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - Azure Managed SQL Service score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Restrict Default Network Access for Azure Cosmos DB Accounts \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_sql_auditing_retention.yaml b/compliance/controls/baseline/azure/sql/azure_sql_auditing_retention.yaml index 3864f2915..b0ef6ea1c 100644 --- a/compliance/controls/baseline/azure/sql/azure_sql_auditing_retention.yaml +++ b/compliance/controls/baseline/azure/sql/azure_sql_auditing_retention.yaml @@ -1,32 +1,36 @@ +Description: Ensure that SQL database auditing has a sufficient log data retention period configured. ID: azure_sql_auditing_retention -Title: "SQL Auditing Retention" -Description: "Ensure that SQL database auditing has a sufficient log data retention period configured." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when (ap -> 'properties' ->> 'retentionDays')::int = 0 then 'ok' - when (ap -> 'properties' ->> 'retentionDays')::int >= 90 then 'ok' - else 'alarm' - end as status, - case - when (ap -> 'properties' ->> 'retentionDays')::int = 0 then 'server has unlimited retention' - when (ap -> 'properties' ->> 'retentionDays')::int >= 90 then 'server has a sufficient retention period' - else 'server does not have a sufficient log data retention period currently configured.' - end as reason - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id, - jsonb_array_elements(server_audit_policy) as ap - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN (ap -> 'properties' ->> 'retentionDays')::INT = 0 THEN 'ok' + WHEN (ap -> 'properties' ->> 'retentionDays')::INT >= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (ap -> 'properties' ->> 'retentionDays')::INT = 0 THEN 'server has unlimited retention' + WHEN (ap -> 'properties' ->> 'retentionDays')::INT >= 90 THEN 'server has a sufficient retention period' + ELSE 'server does not have a sufficient log data retention period currently configured.' + END AS reason + FROM + azure_sql_server AS s + LEFT JOIN + azure_subscription AS sub + ON + s.subscription_id = sub.subscription_id, + jsonb_array_elements(server_audit_policy) AS ap Severity: medium Tags: platform_score_cloud_service_name: @@ -37,5 +41,4 @@ Tags: - Azure Managed SQL Service score_tags: - Problem Identities -IntegrationType: - - azure_subscription +Title: SQL Auditing Retention \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_use_byok_for_transparent_data_encryption.yaml b/compliance/controls/baseline/azure/sql/azure_use_byok_for_transparent_data_encryption.yaml index fecfe53a5..afc964a4b 100644 --- a/compliance/controls/baseline/azure/sql/azure_use_byok_for_transparent_data_encryption.yaml +++ b/compliance/controls/baseline/azure/sql/azure_use_byok_for_transparent_data_encryption.yaml @@ -1,31 +1,34 @@ +Description: Use Bring Your Own Key (BYOK) support for Transparent Data Encryption (TDE). ID: azure_use_byok_for_transparent_data_encryption -Title: "Use BYOK for Transparent Data Encryption" -Description: "Use Bring Your Own Key (BYOK) support for Transparent Data Encryption (TDE)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - encryption ->> 'kind', - case - when (encryption ->> 'kind') = 'servicemanaged' then 'alarm' - else 'ok' - end as status, - case - when (encryption ->> 'kind') = 'servicemanaged' then 'server encryption is using a service-managed key instead of a Customer-Managed Key (CMK)' - else 'server encryption is using a Customer-Managed Key (CMK)' - end as reason - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id, - jsonb_array_elements(encryption_protector) as encryption - PrimaryTable: azure_sql_server ListOfTables: - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + encryption ->> 'kind', + CASE + WHEN (encryption ->> 'kind') = 'servicemanaged' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (encryption ->> 'kind') = 'servicemanaged' THEN + 'server encryption is using a service-managed key instead of a Customer-Managed Key (CMK)' + ELSE 'server encryption is using a Customer-Managed Key (CMK)' + END AS reason + FROM + azure_sql_server AS s + LEFT JOIN + azure_subscription AS sub ON s.subscription_id = sub.subscription_id, + jsonb_array_elements(encryption_protector) AS encryption Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +39,4 @@ Tags: - Azure Managed SQL Service score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Use BYOK for Transparent Data Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/azure/sql/azure_use_microsoft_entra_admin_for_sql_authentication.yaml b/compliance/controls/baseline/azure/sql/azure_use_microsoft_entra_admin_for_sql_authentication.yaml index e40062499..8fc1842b4 100644 --- a/compliance/controls/baseline/azure/sql/azure_use_microsoft_entra_admin_for_sql_authentication.yaml +++ b/compliance/controls/baseline/azure/sql/azure_use_microsoft_entra_admin_for_sql_authentication.yaml @@ -1,37 +1,41 @@ +Description: Ensure that an Microsoft Entra admin is configured for SQL authentication. ID: azure_use_microsoft_entra_admin_for_sql_authentication -Title: "Use Microsoft Entra Admin for SQL Authentication" -Description: "Ensure that an Microsoft Entra admin is configured for SQL authentication." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when server_azure_ad_administrator is null then 'alarm' - else 'ok' - end as status, - case - when server_azure_ad_administrator is null then 'There is no Microsoft Entra administrator configured for SQL authentication' - else 'There is Microsoft Entra administrator configured for SQL authentication' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_sql_server as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - PrimaryTable: azure_sql_server ListOfTables: - azure_ad_administrator - azure_sql_server - azure_subscription Parameters: [] + PrimaryTable: azure_sql_server + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN server_azure_ad_administrator IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN server_azure_ad_administrator IS NULL + THEN 'There is no Microsoft Entra administrator configured for SQL authentication' + ELSE 'There is Microsoft Entra administrator configured for SQL authentication' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_sql_server AS s + LEFT JOIN + azure_subscription AS sub + ON + s.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: - Azure Managed SQL Service score_service_name: - Azure Managed SQL Service -IntegrationType: - - azure_subscription +Title: Use Microsoft Entra Admin for SQL Authentication \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_check_for_publicly_accessible_web_containers.yaml b/compliance/controls/baseline/azure/storage_account/azure_check_for_publicly_accessible_web_containers.yaml index 1b03bccc8..7bc58dc3c 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_check_for_publicly_accessible_web_containers.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_check_for_publicly_accessible_web_containers.yaml @@ -1,35 +1,38 @@ +Description: Ensure that Azure Storage containers aren't publicly accessible. ID: azure_check_for_publicly_accessible_web_containers -Title: "Check for Publicly Accessible Web Containers" -Description: "Ensure that Azure Storage containers aren't publicly accessible." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - container.id as resource, - container.og_resource_id, - container.og_account_id, - case - when not account.allow_blob_public_access - and container.public_access = 'None' then 'ok' - else 'alarm' - end as status, - case - when not account.allow_blob_public_access - and container.public_access = 'None' then account.name || ' container ' || container.name || ' doesn''t allow anonymous access.' - else account.name || ' container ' || container.name || ' allows anonymous access.' - end as reason, - container.resource_group as resource_group, - sub.display_name as subscription - from - azure_storage_container container - join azure_storage_account account on container.account_name = account.name - join azure_subscription sub on sub.subscription_id = account.subscription_id; - PrimaryTable: azure_storage_container ListOfTables: - azure_storage_account - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_container + QueryToExecute: | + SELECT + container.id AS resource, + container.og_resource_id, + container.og_account_id, + CASE + WHEN NOT account.allow_blob_public_access + AND container.public_access = 'None' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT account.allow_blob_public_access + AND container.public_access = 'None' THEN account.name || ' container ' || container.name || ' doesn''t allow anonymous access.' + ELSE account.name || ' container ' || container.name || ' allows anonymous access.' + END AS reason, + container.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_container container + JOIN + azure_storage_account account ON container.account_name = account.name + JOIN + azure_subscription sub ON sub.subscription_id = account.subscription_id; Severity: high Tags: platform_score_cloud_service_name: @@ -40,5 +43,4 @@ Tags: - Azure Storage Accounts score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Check for Publicly Accessible Web Containers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_check_for_sufficient_soft_deleted_data_retention_period.yaml b/compliance/controls/baseline/azure/storage_account/azure_check_for_sufficient_soft_deleted_data_retention_period.yaml index 66ff42a41..916d9ad04 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_check_for_sufficient_soft_deleted_data_retention_period.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_check_for_sufficient_soft_deleted_data_retention_period.yaml @@ -1,42 +1,42 @@ +Description: Ensure there is a sufficient retention period configured for Azure Blob Storage soft deleted data. ID: azure_check_for_sufficient_soft_deleted_data_retention_period -Title: "Check for Sufficient Soft Deleted Data Retention Period" -Description: "Ensure there is a sufficient retention period configured for Azure Blob Storage soft deleted data." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - sa.id as resource, - sa.og_account_id, - sa.og_resource_id, - case - when blob_soft_delete_retention_days is null then 'alarm' - when blob_soft_delete_retention_days <> '{{.azureStorageBlobSoftDeleteSufficientDays}}'::int then 'alarm' - else 'ok' - end as status, - case - when blob_soft_delete_retention_days is null then 'Blob soft delete not enabled' - when blob_soft_delete_retention_days <> '{{.azureStorageBlobSoftDeleteSufficientDays}}'::int then 'Blob soft delete retention days is not sufficient' - else 'Blob soft delete retention days is sufficient' - end as reason, - sa.resource_group, - display_name as subscription - from - azure_storage_account as sa, - azure_subscription as sub - where - sub.subscription_id = sa.subscription_id - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: - Key: azureStorageBlobSoftDeleteSufficientDays Required: true + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + sa.id AS resource, + sa.og_account_id, + sa.og_resource_id, + CASE + WHEN blob_soft_delete_retention_days IS NULL THEN 'alarm' + WHEN blob_soft_delete_retention_days <> '{{.azureStorageBlobSoftDeleteSufficientDays}}'::int THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN blob_soft_delete_retention_days IS NULL THEN 'Blob soft delete not enabled' + WHEN blob_soft_delete_retention_days <> '{{.azureStorageBlobSoftDeleteSufficientDays}}'::int THEN 'Blob soft delete retention days is not sufficient' + ELSE 'Blob soft delete retention days is sufficient' + END AS reason, + sa.resource_group, + display_name AS subscription + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE + sub.subscription_id = sa.subscription_id Severity: medium Tags: platform_score_cloud_service_name: - Azure Storage Accounts score_service_name: - Azure Storage Accounts -IntegrationType: - - azure_subscription +Title: Check for Sufficient Soft Deleted Data Retention Period \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_configure_minimum_tls_version.yaml b/compliance/controls/baseline/azure/storage_account/azure_configure_minimum_tls_version.yaml index 0873e9e0e..a00de91a9 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_configure_minimum_tls_version.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_configure_minimum_tls_version.yaml @@ -1,30 +1,32 @@ +Description: Ensure that the "Minimum TLS version" setting is set to "Version 1.2" for all Azure Storage accounts. ID: azure_configure_minimum_tls_version -Title: "Configure Minimum TLS Version" -Description: "Ensure that the \"Minimum TLS version\" setting is set to \"Version 1.2\" for all Azure Storage accounts." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when minimum_tls_version = '{{.azureLatestTlsVersion}}' then 'ok' - else 'alarm' - end as status, - name || ' tls version is set to ' || minimum_tls_version || '.' as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_storage_account as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: - Key: azureLatestTlsVersion Required: true + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN minimum_tls_version = '{{.azureLatestTlsVersion}}' THEN 'ok' + ELSE 'alarm' + END AS status, + name || ' tls version is set to ' || minimum_tls_version || '.' AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS s + LEFT JOIN + azure_subscription AS sub ON s.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -35,5 +37,4 @@ Tags: - Azure Storage Accounts score_tags: - Expiring Certificates -IntegrationType: - - azure_subscription +Title: Configure Minimum TLS Version \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_disable_anonymous_access_to_blob_containers.yaml b/compliance/controls/baseline/azure/storage_account/azure_disable_anonymous_access_to_blob_containers.yaml index 5f4fbf5b0..42a23ba38 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_disable_anonymous_access_to_blob_containers.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_disable_anonymous_access_to_blob_containers.yaml @@ -1,35 +1,36 @@ +Description: Ensure that anonymous access to blob containers is disabled within your Azure Storage account. ID: azure_disable_anonymous_access_to_blob_containers -Title: "Disable Anonymous Access to Blob Containers" -Description: "Ensure that anonymous access to blob containers is disabled within your Azure Storage account." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - a.name as resource, - a.og_resource_id, - a.og_account_id, - case - when c.public_access is null then 'skip' - when c.public_access = 'container' then 'alarm' - else 'ok' - end as status, - case - when c.public_access is null then 'no container found' - when c.public_access = 'container' then a.name || ' anonymous access to blob container is not disabled.' - else a.name || ' anonymous access to blob container is disabled.' - end as reason, - a.resource_group as resource_group, - sub.display_name as subscription - from - azure_storage_account as a - left join azure_storage_container as c on a.name = c.account_name - left join azure_subscription as sub on a.subscription_id = sub.subscription_id - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_storage_container - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + a.name AS resource, + a.og_resource_id, + a.og_account_id, + CASE + WHEN c.public_access IS NULL THEN 'skip' + WHEN c.public_access = 'container' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN c.public_access IS NULL THEN 'no container found' + WHEN c.public_access = 'container' THEN a.name || ' anonymous access to blob container is not disabled.' + ELSE a.name || ' anonymous access to blob container is disabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS a + LEFT JOIN azure_storage_container AS c ON a.name = c.account_name + LEFT JOIN azure_subscription AS sub ON a.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -40,5 +41,4 @@ Tags: - Azure Storage Accounts score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Disable Anonymous Access to Blob Containers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_disable_public_access_to_storage_accounts_with_blob_containers.yaml b/compliance/controls/baseline/azure/storage_account/azure_disable_public_access_to_storage_accounts_with_blob_containers.yaml index 8402fa05b..38c09e8e8 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_disable_public_access_to_storage_accounts_with_blob_containers.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_disable_public_access_to_storage_accounts_with_blob_containers.yaml @@ -1,31 +1,33 @@ +Description: Ensure that public access to blob containers is disabled for your Azure storage accounts to override any ACL configurations allowing access. ID: azure_disable_public_access_to_storage_accounts_with_blob_containers -Title: "Disable public access to storage accounts with blob containers" -Description: "Ensure that public access to blob containers is disabled for your Azure storage accounts to override any ACL configurations allowing access." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - a.name as resource, - a.og_resource_id, - a.og_account_id, - case - when allow_blob_public_access then 'alarm' - else 'ok' - end as status, - case - when allow_blob_public_access then a.name || ' container and blob data can be read by anonymous users.' - else a.name || ' container and blob data can not be read by anonymous users.' - end as reason, - a.resource_group as resource_group, - sub.display_name as subscription - from - azure_storage_account as a - left join azure_subscription as sub on a.subscription_id = sub.subscription_id - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + a.name AS resource, + a.og_resource_id, + a.og_account_id, + CASE + WHEN allow_blob_public_access THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN allow_blob_public_access THEN a.name || ' container and blob data can be read by anonymous users.' + ELSE a.name || ' container and blob data can not be read by anonymous users.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS a + LEFT JOIN + azure_subscription AS sub ON a.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +38,4 @@ Tags: - Azure Storage Accounts score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Disable public access to storage accounts with blob containers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_enable_blob_storage_lifecycle_management.yaml b/compliance/controls/baseline/azure/storage_account/azure_enable_blob_storage_lifecycle_management.yaml index 6120b37a1..3255089ed 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_enable_blob_storage_lifecycle_management.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_enable_blob_storage_lifecycle_management.yaml @@ -1,38 +1,40 @@ +Description: Ensure that Azure Blob Storage service has a lifecycle management policy configured. ID: azure_enable_blob_storage_lifecycle_management -Title: "Enable Blob Storage Lifecycle Management" -Description: "Ensure that Azure Blob Storage service has a lifecycle management policy configured." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_storage_account + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_account QueryToExecute: | - select - sa.id as resource, + SELECT + sa.id AS resource, sa.og_account_id, sa.og_resource_id, - case - when lifecycle_management_policy = '{}' then 'alarm' - else 'ok' - end as status, - case - when lifecycle_management_policy = '{}' then 'Lifecycle management is not enabled for the blob data available in the selected Microsoft Azure Storage account.' - else 'Lifecycle management is enabled for the blob data available in the selected Microsoft Azure Storage account.' - end as reason, + CASE + WHEN lifecycle_management_policy = '{}' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN lifecycle_management_policy = '{}' THEN + 'Lifecycle management is not enabled for the blob data available in the selected Microsoft Azure Storage account.' + ELSE + 'Lifecycle management is enabled for the blob data available in the selected Microsoft Azure Storage account.' + END AS reason, sa.resource_group, - display_name as subscription - from - azure_storage_account as sa, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE sub.subscription_id = sa.subscription_id - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Storage Accounts score_service_name: - Azure Storage Accounts -IntegrationType: - - azure_subscription +Title: Enable Blob Storage Lifecycle Management \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_enable_immutable_blob_storage.yaml b/compliance/controls/baseline/azure/storage_account/azure_enable_immutable_blob_storage.yaml index 0786b02a5..c72ef94e1 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_enable_immutable_blob_storage.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_enable_immutable_blob_storage.yaml @@ -1,38 +1,38 @@ +Description: Ensure that critical Azure Blob Storage data is protected from accidental deletion or modification. ID: azure_enable_immutable_blob_storage -Title: "Enable Immutable Blob Storage" -Description: "Ensure that critical Azure Blob Storage data is protected from accidental deletion or modification." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_storage_container + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_container QueryToExecute: | - select - sc.id as resource, + SELECT + sc.id AS resource, sc.og_account_id, sc.og_resource_id, - case - when has_immutability_policy = 'false' and has_legal_hold = 'false' then 'alarm' - else 'ok' - end as status, - case - when has_immutability_policy = 'false' and has_legal_hold = 'false' then 'Immutable Blob Storage protection feature is not enabled.' - else 'Immutable Blob Storage protection feature is enabled.' - end as reason, + CASE + WHEN has_immutability_policy = 'false' AND has_legal_hold = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN has_immutability_policy = 'false' AND has_legal_hold = 'false' THEN 'Immutable Blob Storage protection feature is not enabled.' + ELSE 'Immutable Blob Storage protection feature is enabled.' + END AS reason, sc.resource_group, - display_name as subscription - from - azure_storage_container as sc, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_storage_container AS sc, + azure_subscription AS sub + WHERE sub.subscription_id = sc.subscription_id - PrimaryTable: azure_storage_container - ListOfTables: - - azure_storage_container - - azure_subscription - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: - Azure Storage Accounts score_service_name: - Azure Storage Accounts -IntegrationType: - - azure_subscription +Title: Enable Immutable Blob Storage \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_enable_infrastructure_encryption.yaml b/compliance/controls/baseline/azure/storage_account/azure_enable_infrastructure_encryption.yaml index b029e6b55..a4fb0f302 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_enable_infrastructure_encryption.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_enable_infrastructure_encryption.yaml @@ -1,31 +1,32 @@ +Description: Ensure that infrastructure encryption is enabled for Microsoft Azure Storage accounts. ID: azure_enable_infrastructure_encryption -Title: "Enable Infrastructure Encryption" -Description: "Ensure that infrastructure encryption is enabled for Microsoft Azure Storage accounts." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - a.name as resource, - a.og_resource_id, - a.og_account_id, - case - when require_infrastructure_encryption is null or require_infrastructure_encryption = 'false' then 'alarm' - else 'ok' - end as status, - case - when require_infrastructure_encryption is null or require_infrastructure_encryption = 'false' then a.name || ' Infrastructure Encryption feature is not enabled.' - else a.name || ' Infrastructure Encryption feature is not enabled.' - end as reason, - a.resource_group as resource_group, - sub.display_name as subscription - from - azure_storage_account as a - left join azure_subscription as sub on a.subscription_id = sub.subscription_id - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + a.name AS resource, + a.og_resource_id, + a.og_account_id, + CASE + WHEN require_infrastructure_encryption IS NULL OR require_infrastructure_encryption = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN require_infrastructure_encryption IS NULL OR require_infrastructure_encryption = 'false' THEN a.name || ' Infrastructure Encryption feature is not enabled.' + ELSE a.name || ' Infrastructure Encryption feature is enabled.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS a + LEFT JOIN azure_subscription AS sub ON a.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - Azure Storage Accounts score_tags: - Unencrypted Storage -IntegrationType: - - azure_subscription +Title: Enable Infrastructure Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_blob_service.yaml b/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_blob_service.yaml index ecb2fae35..f7386a72f 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_blob_service.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_blob_service.yaml @@ -1,38 +1,44 @@ +Description: Ensure that storage logging is enabled for the Azure Storage Blob service. ID: azure_enable_logging_for_azure_storage_blob_service -Title: "Enable Logging for Azure Storage Blob Service" -Description: "Ensure that storage logging is enabled for the Azure Storage Blob service." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_storage_account + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_account QueryToExecute: | - select - sa.id as resource, + SELECT + sa.id AS resource, sa.og_account_id, sa.og_resource_id, - case - when (blob_service_logging ->> 'Read' = 'false' and blob_service_logging ->> 'Write' = 'false' and blob_service_logging ->> 'Delete' = 'false') then 'alarm' - else 'ok' - end as status, - case - when (blob_service_logging ->> 'Read' = 'false' and blob_service_logging ->> 'Write' = 'false' and blob_service_logging ->> 'Delete' = 'false') then 'The storage logging is not enabled for the Azure Storage Blob service in the selected storage account settings.' - else 'The storage logging is enabled for the Azure Storage Blob service in the selected storage account settings.' - end as reason, + CASE + WHEN (blob_service_logging ->> 'Read' = 'false' AND + blob_service_logging ->> 'Write' = 'false' AND + blob_service_logging ->> 'Delete' = 'false') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (blob_service_logging ->> 'Read' = 'false' AND + blob_service_logging ->> 'Write' = 'false' AND + blob_service_logging ->> 'Delete' = 'false') THEN + 'The storage logging is not enabled for the Azure Storage Blob service in the selected storage account settings.' + ELSE + 'The storage logging is enabled for the Azure Storage Blob service in the selected storage account settings.' + END AS reason, sa.resource_group, - display_name as subscription - from - azure_storage_account as sa, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE sub.subscription_id = sa.subscription_id - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Storage Accounts score_service_name: - Azure Storage Accounts -IntegrationType: - - azure_subscription +Title: Enable Logging for Azure Storage Blob Service \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_queue_service.yaml b/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_queue_service.yaml index 0fd9fa2fb..4d706f795 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_queue_service.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_queue_service.yaml @@ -1,38 +1,40 @@ +Description: Ensure that detailed storage logging is enabled for the Azure Storage Queue service. ID: azure_enable_logging_for_azure_storage_queue_service -Title: "Enable Logging for Azure Storage Queue Service" -Description: "Ensure that detailed storage logging is enabled for the Azure Storage Queue service." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_storage_account + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_account QueryToExecute: | - select - sa.id as resource, + SELECT + sa.id AS resource, sa.og_account_id, sa.og_resource_id, - case - when (queue_logging_read = 'false' and queue_logging_write = 'false' and queue_logging_delete = 'false') then 'alarm' - else 'ok' - end as status, - case - when (queue_logging_read = 'false' and queue_logging_write = 'false' and queue_logging_delete = 'false') then 'The detailed storage logging is not enabled for the Azure Storage Queue service within the selected storage account.' - else 'The detailed storage logging is enabled for the Azure Storage Queue service within the selected storage account.' - end as reason, + CASE + WHEN (queue_logging_read = 'false' AND queue_logging_write = 'false' AND queue_logging_delete = 'false') + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (queue_logging_read = 'false' AND queue_logging_write = 'false' AND queue_logging_delete = 'false') + THEN 'The detailed storage logging is not enabled for the Azure Storage Queue service within the selected storage account.' + ELSE 'The detailed storage logging is enabled for the Azure Storage Queue service within the selected storage account.' + END AS reason, sa.resource_group, - display_name as subscription - from - azure_storage_account as sa, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE sub.subscription_id = sa.subscription_id - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Storage Accounts score_service_name: - Azure Storage Accounts -IntegrationType: - - azure_subscription +Title: Enable Logging for Azure Storage Queue Service \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_table_service.yaml b/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_table_service.yaml index 34e67e132..30f068523 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_table_service.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_enable_logging_for_azure_storage_table_service.yaml @@ -1,38 +1,38 @@ +Description: Ensure that storage logging is enabled for the Azure Storage Table service. ID: azure_enable_logging_for_azure_storage_table_service -Title: "Enable Logging for Azure Storage Table Service" -Description: "Ensure that storage logging is enabled for the Azure Storage Table service." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_storage_account + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_account QueryToExecute: | - select - sa.id as resource, + SELECT + sa.id AS resource, sa.og_account_id, sa.og_resource_id, - case - when (table_logging_read = 'false' and table_logging_write = 'false' and table_logging_delete = 'false') then 'alarm' - else 'ok' - end as status, - case - when (table_logging_read = 'false' and table_logging_write = 'false' and table_logging_delete = 'false') then 'The storage logging is not enabled for the Azure Storage Table service' - else 'The storage logging is enabled for the Azure Storage Table service' - end as reason, + CASE + WHEN (table_logging_read = 'false' AND table_logging_write = 'false' AND table_logging_delete = 'false') THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (table_logging_read = 'false' AND table_logging_write = 'false' AND table_logging_delete = 'false') THEN 'The storage logging is not enabled for the Azure Storage Table service' + ELSE 'The storage logging is enabled for the Azure Storage Table service' + END AS reason, sa.resource_group, - display_name as subscription - from - azure_storage_account as sa, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE sub.subscription_id = sa.subscription_id - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Storage Accounts score_service_name: - Azure Storage Accounts -IntegrationType: - - azure_subscription +Title: Enable Logging for Azure Storage Table Service \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_enable_secure_transfer_in_azure_storage.yaml b/compliance/controls/baseline/azure/storage_account/azure_enable_secure_transfer_in_azure_storage.yaml index e924598af..ae3b9d49a 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_enable_secure_transfer_in_azure_storage.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_enable_secure_transfer_in_azure_storage.yaml @@ -1,38 +1,39 @@ +Description: Ensure that "Secure transfer required" security feature is enabled within your Azure Storage account configuration. ID: azure_enable_secure_transfer_in_azure_storage -Title: "Enable Secure Transfer in Azure Storage" -Description: "Ensure that \"Secure transfer required\" security feature is enabled within your Azure Storage account configuration." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_storage_account + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_account QueryToExecute: | - select - sa.id as resource, + SELECT + sa.id AS resource, sa.og_account_id, sa.og_resource_id, - case - when enable_https_traffic_only = 'true' then 'ok' - else 'alarm' - end as status, - case - when enable_https_traffic_only = 'true' then 'The data in transit between clients and the resources available in the selected Azure Storage account (i.e. files, blobs, queues, tables, and disks) is encrypted' - else 'The data in transit between clients and the resources available in the selected Azure Storage account (i.e. files, blobs, queues, tables, and disks) is encrypted' - end as reason, + CASE + WHEN enable_https_traffic_only = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enable_https_traffic_only = 'true' THEN 'The data in transit between clients and the resources available in the selected Azure Storage account (i.e. files, blobs, queues, tables, and disks) is encrypted' + ELSE 'The data in transit between clients and the resources available in the selected Azure Storage account (i.e. files, blobs, queues, tables, and disks) is not encrypted' + END AS reason, sa.resource_group, - display_name as subscription - from - azure_storage_account as sa, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_storage_account AS sa + JOIN + azure_subscription AS sub + ON sub.subscription_id = sa.subscription_id - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Storage Accounts score_service_name: - Azure Storage Accounts -IntegrationType: - - azure_subscription +Title: Enable Secure Transfer in Azure Storage \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_enable_soft_delete_for_azure_blob_storage.yaml b/compliance/controls/baseline/azure/storage_account/azure_enable_soft_delete_for_azure_blob_storage.yaml index af349cc23..cfd966ae6 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_enable_soft_delete_for_azure_blob_storage.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_enable_soft_delete_for_azure_blob_storage.yaml @@ -1,38 +1,38 @@ +Description: Ensure that infrastructure encryption is enabled for Microsoft Azure Storage accounts. ID: azure_enable_soft_delete_for_azure_blob_storage -Title: "Enable Soft Delete for Azure Blob Storage" -Description: "Ensure that infrastructure encryption is enabled for Microsoft Azure Storage accounts." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_storage_account + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_account QueryToExecute: | - select - sa.id as resource, + SELECT + sa.id AS resource, sa.og_account_id, sa.og_resource_id, - case - when blob_container_soft_delete_enabled = 'true' then 'ok' - else 'alarm' - end as status, - case - when blob_container_soft_delete_enabled = 'true' then 'Soft Delete feature is enabled' - else 'Soft Delete feature is not enabled' - end as reason, + CASE + WHEN blob_container_soft_delete_enabled = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN blob_container_soft_delete_enabled = 'true' THEN 'Soft Delete feature is enabled' + ELSE 'Soft Delete feature is not enabled' + END AS reason, sa.resource_group, - display_name as subscription - from - azure_storage_account as sa, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE sub.subscription_id = sa.subscription_id - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Storage Accounts score_service_name: - Azure Storage Accounts -IntegrationType: - - azure_subscription +Title: Enable Soft Delete for Azure Blob Storage \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_enable_trusted_microsoft_services_for_storage_account_access.yaml b/compliance/controls/baseline/azure/storage_account/azure_enable_trusted_microsoft_services_for_storage_account_access.yaml index 14cea2f3d..eec2a5993 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_enable_trusted_microsoft_services_for_storage_account_access.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_enable_trusted_microsoft_services_for_storage_account_access.yaml @@ -1,38 +1,38 @@ +Description: Allow Trusted Microsoft Services to access your Azure Storage account resources. ID: azure_enable_trusted_microsoft_services_for_storage_account_access -Title: "Enable Trusted Microsoft Services for Storage Account Access" -Description: "Allow Trusted Microsoft Services to access your Azure Storage account resources." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_storage_account + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_account QueryToExecute: | - select - sa.id as resource, + SELECT + sa.id AS resource, sa.og_account_id, sa.og_resource_id, - case - when network_rule_bypass = 'None' then 'alarm' - else 'ok' - end as status, - case - when network_rule_bypass = 'None' then 'Trusted Microsoft services are not allowed to access the selected Azure Storage account' - else 'Trusted Microsoft services are allowed to access the selected Azure Storage account' - end as reason, + CASE + WHEN network_rule_bypass = 'None' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_rule_bypass = 'None' THEN 'Trusted Microsoft services are not allowed to access the selected Azure Storage account' + ELSE 'Trusted Microsoft services are allowed to access the selected Azure Storage account' + END AS reason, sa.resource_group, - display_name as subscription - from - azure_storage_account as sa, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE sub.subscription_id = sa.subscription_id - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Storage Accounts score_service_name: - Azure Storage Accounts -IntegrationType: - - azure_subscription +Title: Enable Trusted Microsoft Services for Storage Account Access \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_limit_storage_account_access_by_ip_address.yaml b/compliance/controls/baseline/azure/storage_account/azure_limit_storage_account_access_by_ip_address.yaml index b51a6b9aa..0df490735 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_limit_storage_account_access_by_ip_address.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_limit_storage_account_access_by_ip_address.yaml @@ -1,43 +1,47 @@ +Description: Ensure that Azure Storage account access is limited only to specific IP address(es). ID: azure_limit_storage_account_access_by_ip_address -Title: "Limit Storage Account Access by IP Address" -Description: "Ensure that Azure Storage account access is limited only to specific IP address(es)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - name as resource, - s.og_resource_id, - s.og_account_id, - case - when network_ip_rules is null then 'skip' - when exists ( - select 1 - from jsonb_array_elements(network_ip_rules) as r - where (r ->> 'action') = 'Allow' and '{{.azureStorageAccountAllowedIPAddresses}}' not LIKE '%' || (r ->> 'value') || '%' - ) then 'alarm' - else 'ok' - end as status, - case - when network_ip_rules is null then 'storage account does not have network ip rule' - when exists ( - select 1 - from jsonb_array_elements(network_ip_rules) as r - where (r ->> 'action') = 'Allow' and '{{.azureStorageAccountAllowedIPAddresses}}' not LIKE '%' || (r ->> 'value') || '%' - ) then 'is not restricted to trusted IP addresses/IP ranges only.' - else 'is restricted to trusted IP addresses/IP ranges only.' - end as reason, - resource_group as resource_group, - sub.display_name as subscription - from - azure_storage_account as s - left join azure_subscription as sub on s.subscription_id = sub.subscription_id - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: - Key: azureStorageAccountAllowedIPAddresses Required: true + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + name AS resource, + s.og_resource_id, + s.og_account_id, + CASE + WHEN network_ip_rules IS NULL THEN 'skip' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(network_ip_rules) AS r + WHERE (r ->> 'action') = 'Allow' + AND '{{.azureStorageAccountAllowedIPAddresses}}' NOT LIKE '%' || (r ->> 'value') || '%' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_ip_rules IS NULL THEN 'storage account does not have network ip rule' + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(network_ip_rules) AS r + WHERE (r ->> 'action') = 'Allow' + AND '{{.azureStorageAccountAllowedIPAddresses}}' NOT LIKE '%' || (r ->> 'value') || '%' + ) THEN 'is not restricted to trusted IP addresses/IP ranges only.' + ELSE 'is restricted to trusted IP addresses/IP ranges only.' + END AS reason, + resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS s + LEFT JOIN azure_subscription AS sub + ON s.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -48,5 +52,4 @@ Tags: - Azure Storage Accounts score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Limit Storage Account Access by IP Address \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_private_endpoint_in_use.yaml b/compliance/controls/baseline/azure/storage_account/azure_private_endpoint_in_use.yaml index 11601546a..dd5348254 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_private_endpoint_in_use.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_private_endpoint_in_use.yaml @@ -1,31 +1,32 @@ +Description: Ensure that private endpoints are used to access Microsoft Azure Storage accounts. ID: azure_private_endpoint_in_use -Title: "Private Endpoint in Use" -Description: "Ensure that private endpoints are used to access Microsoft Azure Storage accounts." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - a.name as resource, - a.og_resource_id, - a.og_account_id, - case - when a.private_endpoint_connections is null then 'alarm' - else 'ok' - end as status, - case - when a.private_endpoint_connections is null then a.name || ' is not using private endpoints for secure access.' - else a.name || ' is using private endpoints for secure access.' - end as reason, - a.resource_group as resource_group, - sub.display_name as subscription - from - azure_storage_account as a - left join azure_subscription as sub on a.subscription_id = sub.subscription_id - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + a.name AS resource, + a.og_resource_id, + a.og_account_id, + CASE + WHEN a.private_endpoint_connections IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.private_endpoint_connections IS NULL THEN a.name || ' is not using private endpoints for secure access.' + ELSE a.name || ' is using private endpoints for secure access.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS a + LEFT JOIN azure_subscription AS sub ON a.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - Azure Storage Accounts score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Private Endpoint in Use \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_restrict_default_network_access_for_storage_accounts.yaml b/compliance/controls/baseline/azure/storage_account/azure_restrict_default_network_access_for_storage_accounts.yaml index ee7fb52c2..598e6d559 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_restrict_default_network_access_for_storage_accounts.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_restrict_default_network_access_for_storage_accounts.yaml @@ -1,31 +1,33 @@ +Description: Ensure that the default network access rule is set to "Deny" within your Azure Storage account. ID: azure_restrict_default_network_access_for_storage_accounts -Title: "Restrict Default Network Access for Storage Accounts" -Description: "Ensure that the default network access rule is set to \"Deny\" within your Azure Storage account." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - a.name as resource, - a.og_resource_id, - a.og_account_id, - case - when network_rule_default_action = 'Allow' then 'alarm' - else 'ok' - end as status, - case - when network_rule_default_action = 'Allow' then a.name || ' can be accessed by all networks, including the Internet.' - else a.name || ' can not be accessed by all networks, including the Internet.' - end as reason, - a.resource_group as resource_group, - sub.display_name as subscription - from - azure_storage_account as a - left join azure_subscription as sub on a.subscription_id = sub.subscription_id - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + a.name AS resource, + a.og_resource_id, + a.og_account_id, + CASE + WHEN network_rule_default_action = 'Allow' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN network_rule_default_action = 'Allow' THEN a.name || ' can be accessed by all networks, including the Internet.' + ELSE a.name || ' can not be accessed by all networks, including the Internet.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS a + LEFT JOIN + azure_subscription AS sub ON a.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +38,4 @@ Tags: - Azure Storage Accounts score_tags: - Exposed Endpoints -IntegrationType: - - azure_subscription +Title: Restrict Default Network Access for Storage Accounts \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_storage_account_encryption_using_customer_managed_keys.yaml b/compliance/controls/baseline/azure/storage_account/azure_storage_account_encryption_using_customer_managed_keys.yaml index d6d747f23..8f6915b97 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_storage_account_encryption_using_customer_managed_keys.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_storage_account_encryption_using_customer_managed_keys.yaml @@ -1,31 +1,32 @@ +Description: Use Customer Managed Keys (CMKs) to encrypt data within Azure Storage accounts. ID: azure_storage_account_encryption_using_customer_managed_keys -Title: "Storage Account Encryption using Customer Managed Keys" -Description: "Use Customer Managed Keys (CMKs) to encrypt data within Azure Storage accounts." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - a.name as resource, - a.og_resource_id, - a.og_account_id, - case - when encryption_key_source = 'Microsoft.Keyvault' then 'ok' - else 'alarm' - end as status, - case - when encryption_key_source = 'Microsoft.Keyvault' then a.name || ' is encrypted using a Customer Managed Key.' - else a.name || ' is not encrypted using a Customer Managed Key.' - end as reason, - a.resource_group as resource_group, - sub.display_name as subscription - from - azure_storage_account as a - left join azure_subscription as sub on a.subscription_id = sub.subscription_id - PrimaryTable: azure_storage_account ListOfTables: - azure_storage_account - azure_subscription Parameters: [] + PrimaryTable: azure_storage_account + QueryToExecute: | + SELECT + a.name AS resource, + a.og_resource_id, + a.og_account_id, + CASE + WHEN encryption_key_source = 'Microsoft.Keyvault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_key_source = 'Microsoft.Keyvault' THEN a.name || ' is encrypted using a Customer Managed Key.' + ELSE a.name || ' is not encrypted using a Customer Managed Key.' + END AS reason, + a.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_storage_account AS a + LEFT JOIN azure_subscription AS sub ON a.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -36,5 +37,4 @@ Tags: - Azure Storage Accounts score_tags: - Unencrypted Storage -IntegrationType: - - azure_subscription +Title: Storage Account Encryption using Customer Managed Keys \ No newline at end of file diff --git a/compliance/controls/baseline/azure/storage_account/azure_use_byok_for_storage_account_encryption.yaml b/compliance/controls/baseline/azure/storage_account/azure_use_byok_for_storage_account_encryption.yaml index 6a77c9e3f..73ae90700 100644 --- a/compliance/controls/baseline/azure/storage_account/azure_use_byok_for_storage_account_encryption.yaml +++ b/compliance/controls/baseline/azure/storage_account/azure_use_byok_for_storage_account_encryption.yaml @@ -1,38 +1,38 @@ +Description: Ensure that infrastructure encryption is enabled for Microsoft Azure Storage accounts. ID: azure_use_byok_for_storage_account_encryption -Title: "Use BYOK for Storage Account Encryption" -Description: "Ensure that infrastructure encryption is enabled for Microsoft Azure Storage accounts." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_storage_account + - azure_subscription + Parameters: [] + PrimaryTable: azure_storage_account QueryToExecute: | - select - sa.id as resource, + SELECT + sa.id AS resource, sa.og_account_id, sa.og_resource_id, - case - when encryption_key_vault_properties_key_name is not null then 'ok' - else 'alarm' - end as status, - case - when encryption_key_vault_properties_key_name is not null then 'Microsoft Azure Storage account is encrypted using a customer-managed key' - else 'Microsoft Azure Storage account is not encrypted using a customer-managed key' - end as reason, + CASE + WHEN encryption_key_vault_properties_key_name IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_key_vault_properties_key_name IS NOT NULL THEN 'Microsoft Azure Storage account is encrypted using a customer-managed key' + ELSE 'Microsoft Azure Storage account is not encrypted using a customer-managed key' + END AS reason, sa.resource_group, - display_name as subscription - from - azure_storage_account as sa, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_storage_account AS sa, + azure_subscription AS sub + WHERE sub.subscription_id = sa.subscription_id - PrimaryTable: azure_storage_account - ListOfTables: - - azure_storage_account - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Storage Accounts score_service_name: - Azure Storage Accounts -IntegrationType: - - azure_subscription +Title: Use BYOK for Storage Account Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_approved_azure_machine_image_in_use.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_approved_azure_machine_image_in_use.yaml index 7a8a15917..ae59d5afb 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_approved_azure_machine_image_in_use.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_approved_azure_machine_image_in_use.yaml @@ -1,38 +1,38 @@ +Description: Ensure that all your Azure virtual machine instances are launched from approved machine images only. ID: azure_approved_azure_machine_image_in_use -Title: "Approved Azure Machine Image in Use" -Description: "Ensure that all your Azure virtual machine instances are launched from approved machine images only." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_virtual_machine QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'StorageProfile' -> 'ImageReference' ->> 'ID' is null then 'alarm' - else 'ok' - end as status, - case - when vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'StorageProfile' -> 'ImageReference' ->> 'ID' is null then 'Virtual Machine instance was launched without using an approved Azure machine image' - else 'Virtual Machine instance was launched using an approved Azure machine image' - end as reason, + CASE + WHEN vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'StorageProfile' -> 'ImageReference' ->> 'ID' IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'StorageProfile' -> 'ImageReference' ->> 'ID' IS NULL THEN 'Virtual Machine instance was launched without using an approved Azure machine image' + ELSE 'Virtual Machine instance was launched using an approved Azure machine image' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine - ListOfTables: - - azure_compute_virtual_machine - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Approved Azure Machine Image in Use \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_accelerated_networking_for_virtual_machines.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_accelerated_networking_for_virtual_machines.yaml index 6f0674096..b7df7908c 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_accelerated_networking_for_virtual_machines.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_accelerated_networking_for_virtual_machines.yaml @@ -1,29 +1,9 @@ +Description: Ensure that Microsoft Azure virtual machines are configured to use accelerated networking. ID: azure_check_for_accelerated_networking_for_virtual_machines -Title: "Check for Accelerated Networking for Virtual Machines" -Description: "Ensure that Microsoft Azure virtual machines are configured to use accelerated networking." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when nic.enable_accelerated_networking = 'true' then 'ok' - else 'alarm' - end as status, - case - when nic.enable_accelerated_networking = 'true' then 'Accelerated networking is enabled' - else 'Accelerated networking is not enabled' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_subscription as sub on sub.subscription_id = vm.subscription_id, - jsonb_array_elements(network_interfaces) as ni - left join azure_network_interface as nic on nic.id = (ni ->> 'id') - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_network_interface @@ -31,11 +11,31 @@ Query: Parameters: - Key: azureAllowedVmExtentions Required: true + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN nic.enable_accelerated_networking = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN nic.enable_accelerated_networking = 'true' THEN 'Accelerated networking is enabled' + ELSE 'Accelerated networking is not enabled' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN azure_subscription AS sub ON sub.subscription_id = vm.subscription_id, + jsonb_array_elements(network_interfaces) AS ni + LEFT JOIN azure_network_interface AS nic ON nic.id = (ni ->> 'id') Severity: high Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Accelerated Networking for Virtual Machines \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_associated_load_balancers.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_associated_load_balancers.yaml index e00509ae5..016b137bf 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_associated_load_balancers.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_associated_load_balancers.yaml @@ -1,38 +1,38 @@ +Description: Ensure that your Azure virtual machine scale sets are using load balancers for traffic distribution. ID: azure_check_for_associated_load_balancers -Title: "Check for Associated Load Balancers" -Description: "Ensure that your Azure virtual machine scale sets are using load balancers for traffic distribution." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine_scale_set + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when (select count(*) from jsonb_array_elements_text(zones)) > 1 then 'ok' - else 'alarm' - end as status, - case - when (select count(*) from jsonb_array_elements_text(zones)) > 1 then 'VM Scale-set is available in more than one zone' - else 'VM Scale-set is not available in more than one zone' - end as reason, + CASE + WHEN (SELECT COUNT(*) FROM jsonb_array_elements_text(zones)) > 1 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (SELECT COUNT(*) FROM jsonb_array_elements_text(zones)) > 1 THEN 'VM Scale-set is available in more than one zone' + ELSE 'VM Scale-set is not available in more than one zone' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine_scale_set as vm, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_virtual_machine_scale_set AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine_scale_set - ListOfTables: - - azure_compute_virtual_machine_scale_set - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Associated Load Balancers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_automatic_instance_repairs.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_automatic_instance_repairs.yaml index b8dbbedae..c534091f1 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_automatic_instance_repairs.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_automatic_instance_repairs.yaml @@ -1,38 +1,38 @@ +Description: Ensure that Azure virtual machine scale sets are configured to use automatic instance repairs ID: azure_check_for_automatic_instance_repairs -Title: "Check for Automatic Instance Repairs" -Description: "Ensure that Azure virtual machine scale sets are configured to use automatic instance repairs" +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine_scale_set + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when vm.og_description -> 'VirtualMachineScaleSet' -> 'Properties' -> 'AutomaticRepairsPolicy' ->> 'Enabled' = 'true' then 'ok' - else 'alarm' - end as status, - case - when vm.og_description -> 'VirtualMachineScaleSet' -> 'Properties' -> 'AutomaticRepairsPolicy' ->> 'Enabled' = 'true' then 'Automatic repairs feature is enabled' - else 'Automatic repairs feature is not currently enabled' - end as reason, + CASE + WHEN vm.og_description -> 'VirtualMachineScaleSet' -> 'Properties' -> 'AutomaticRepairsPolicy' ->> 'Enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN vm.og_description -> 'VirtualMachineScaleSet' -> 'Properties' -> 'AutomaticRepairsPolicy' ->> 'Enabled' = 'true' THEN 'Automatic repairs feature is enabled' + ELSE 'Automatic repairs feature is not currently enabled' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine_scale_set as vm, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_virtual_machine_scale_set AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine_scale_set - ListOfTables: - - azure_compute_virtual_machine_scale_set - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Automatic Instance Repairs \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_automatic_os_upgrades.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_automatic_os_upgrades.yaml index 3e43f0c74..71bf34d55 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_automatic_os_upgrades.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_automatic_os_upgrades.yaml @@ -1,38 +1,38 @@ +Description: Ensure that Automatic OS Upgrades feature is enabled for your Azure virtual machine scale sets. ID: azure_check_for_automatic_os_upgrades -Title: "Check for Automatic OS Upgrades" -Description: "Ensure that Automatic OS Upgrades feature is enabled for your Azure virtual machine scale sets." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine_scale_set + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when upgrade_policy -> 'automaticOSUpgradePolicy' ->> 'enableAutomaticOSUpgrade' = 'true' then 'ok' - else 'alarm' - end as status, - case - when upgrade_policy -> 'automaticOSUpgradePolicy' ->> 'enableAutomaticOSUpgrade' = 'true' then 'Automatic OS Upgrades feature is enabled' - else 'Automatic OS Upgrades feature is not currently enabled' - end as reason, + CASE + WHEN upgrade_policy -> 'automaticOSUpgradePolicy' ->> 'enableAutomaticOSUpgrade' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN upgrade_policy -> 'automaticOSUpgradePolicy' ->> 'enableAutomaticOSUpgrade' = 'true' THEN 'Automatic OS Upgrades feature is enabled' + ELSE 'Automatic OS Upgrades feature is not currently enabled' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine_scale_set as vm, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_virtual_machine_scale_set AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine_scale_set - ListOfTables: - - azure_compute_virtual_machine_scale_set - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Automatic OS Upgrades \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_autoscale_notifications.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_autoscale_notifications.yaml index 87556370d..cce7953fe 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_autoscale_notifications.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_autoscale_notifications.yaml @@ -1,38 +1,40 @@ +Description: Ensure that autoscale notifications are enabled for Azure virtual machine scale sets. ID: azure_check_for_autoscale_notifications -Title: "Check for Autoscale Notifications" -Description: "Ensure that autoscale notifications are enabled for Azure virtual machine scale sets." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when s.notifications ->> 'enabled' = 'true' then 'ok' - else 'alarm' - end as status, - case - when s.notifications ->> 'enabled' = 'true' then 'autoscale notifications are enabled' - else 'autoscale notifications are not enabled' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine_scale_set as vm - left join azure_subscription as sub on sub.subscription_id = vm.subscription_id - left join azure_autoscale_setting as s on vm.id = s.target_resource_uri - PrimaryTable: azure_compute_virtual_machine_scale_set ListOfTables: - azure_autoscale_setting - azure_compute_virtual_machine_scale_set - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN s.notifications ->> 'enabled' = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.notifications ->> 'enabled' = 'true' THEN 'autoscale notifications are enabled' + ELSE 'autoscale notifications are not enabled' + END AS reason, + vm.resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine_scale_set AS vm + LEFT JOIN + azure_subscription AS sub ON sub.subscription_id = vm.subscription_id + LEFT JOIN + azure_autoscale_setting AS s ON vm.id = s.target_resource_uri Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Autoscale Notifications \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_backups_for_azure_virtual_machines.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_backups_for_azure_virtual_machines.yaml index 3f9cc75f9..91b861a9b 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_backups_for_azure_virtual_machines.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_backups_for_azure_virtual_machines.yaml @@ -1,38 +1,40 @@ +Description: Ensure that Microsoft Azure Backup service is in use for your Azure virtual machines (VMs). ID: azure_check_for_backups_for_azure_virtual_machines -Title: "Check for Backups for Azure Virtual Machines" -Description: "Ensure that Microsoft Azure Backup service is in use for your Azure virtual machines (VMs)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when bi.name is null then 'alarm' - else 'ok' - end as status, - case - when bi.name is null then 'Diagnostic extensions installed on the VM' - else 'Diagnostic extensions not installed on the VM' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_subscription as sub on sub.subscription_id = vm.subscription_id - left join azure_recovery_services_backup_item as bi on vm.id = (bi.properties ->> 'SourceResourceID') - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_recovery_services_backup_item - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN bi.name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN bi.name IS NULL THEN 'Diagnostic extensions installed on the VM' + ELSE 'Diagnostic extensions not installed on the VM' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN azure_subscription AS sub + ON sub.subscription_id = vm.subscription_id + LEFT JOIN azure_recovery_services_backup_item AS bi + ON vm.id = (bi.properties ->> 'SourceResourceID') Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Backups for Azure Virtual Machines \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_configure_health_monitoring.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_configure_health_monitoring.yaml index 1cb94f54e..60e67b5a5 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_configure_health_monitoring.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_configure_health_monitoring.yaml @@ -1,42 +1,47 @@ +Description: Ensure that the health of your Microsoft Azure scale set instances is being monitored. ID: azure_check_for_configure_health_monitoring -Title: "Check for Configure Health Monitoring" -Description: "Ensure that the health of your Microsoft Azure scale set instances is being monitored." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vmss.id as resource, - vmss.og_account_id, - vmss.og_resource_id, - case - when exists( - select 1 from jsonb_array_elements(vmss.extensions) as ex - where ('ApplicationHealthLinux' = (ex ->> 'name')) or ('healthRepairExtension' = (ex ->> 'name')) - ) then 'ok' - else 'alarm' - end as status, - case - when exists( - select 1 from jsonb_array_elements(vmss.extensions) as ex - where ('ApplicationHealthLinux' = (ex ->> 'name')) or ('healthRepairExtension' = (ex ->> 'name')) - ) then 'Azure virtual machine scaleset has application health monitoring enabled' - else 'Azure virtual machine scaleset does not have application health monitoring enabled' - end as reason, - vmss.resource_group, - display_name as subscription - from - azure_compute_virtual_machine_scale_set as vmss - left join azure_subscription as sub on sub.subscription_id = vmss.subscription_id - PrimaryTable: azure_compute_virtual_machine_scale_set ListOfTables: - azure_compute_virtual_machine_scale_set - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set + QueryToExecute: | + SELECT + vmss.id AS resource, + vmss.og_account_id, + vmss.og_resource_id, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements(vmss.extensions) AS ex + WHERE ('ApplicationHealthLinux' = (ex ->> 'name')) + OR ('healthRepairExtension' = (ex ->> 'name')) + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements(vmss.extensions) AS ex + WHERE ('ApplicationHealthLinux' = (ex ->> 'name')) + OR ('healthRepairExtension' = (ex ->> 'name')) + ) THEN 'Azure virtual machine scaleset has application health monitoring enabled' + ELSE 'Azure virtual machine scaleset does not have application health monitoring enabled' + END AS reason, + vmss.resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine_scale_set AS vmss + LEFT JOIN azure_subscription AS sub + ON sub.subscription_id = vmss.subscription_id Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Configure Health Monitoring \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_desired_vm_sku_sizes.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_desired_vm_sku_sizes.yaml index 3ea3953d2..4c66e2053 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_desired_vm_sku_sizes.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_desired_vm_sku_sizes.yaml @@ -1,35 +1,36 @@ +Description: Ensure that your virtual machine instances are of a given SKU size (e.g. Standard_A8_v2). ID: azure_check_for_desired_vm_sku_sizes -Title: "Check for Desired VM SKU Size(s)" -Description: "Ensure that your virtual machine instances are of a given SKU size (e.g. Standard_A8_v2)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when '{{.azureAllowedVmSizes}}' not like '%' || (vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'HardwareProfile' ->> 'VMSize') || '%' then 'alarm' - else 'ok' - end as status, - case - when '{{.azureAllowedVmSizes}}' not like '%' || (vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'HardwareProfile' ->> 'VMSize') || '%' then 'the virtual machine vm size is not allowed by your organization' - else 'the virtual machine vm size is allowed by your organization' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where - sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: - Key: azureAllowedVmSizes Required: true + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN '{{.azureAllowedVmSizes}}' NOT LIKE '%' || (vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'HardwareProfile' ->> 'VMSize') || '%' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN '{{.azureAllowedVmSizes}}' NOT LIKE '%' || (vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'HardwareProfile' ->> 'VMSize') || '%' THEN 'the virtual machine vm size is not allowed by your organization' + ELSE 'the virtual machine vm size is allowed by your organization' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id; Severity: high Tags: platform_score_cloud_service_name: @@ -40,5 +41,4 @@ Tags: - Azure Virtual Machines score_tags: - Unencrypted Traffic -IntegrationType: - - azure_subscription +Title: Check for Desired VM SKU Size(s) \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_encryption_for_web_tier_disk_volumes.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_encryption_for_web_tier_disk_volumes.yaml index ad4ee7dfa..cc018963c 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_encryption_for_web_tier_disk_volumes.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_encryption_for_web_tier_disk_volumes.yaml @@ -1,44 +1,44 @@ +Description: Ensure that Azure virtual machine disk volumes created for the web tier are encrypted. ID: azure_check_for_encryption_for_web_tier_disk_volumes -Title: "Check for Encryption for Web-Tier Disk Volumes" -Description: "Ensure that Azure virtual machine disk volumes created for the web tier are encrypted." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine + - azure_subscription + Parameters: + - Key: azureAppTierTags + Required: true + PrimaryTable: azure_compute_virtual_machine QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when (vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'StorageProfile' -> 'OSDisk' -> 'EncryptionSettings' ->> 'Enabled')::bool then 'ok' - else 'alarm' - end as status, - case - when (vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'StorageProfile' -> 'OSDisk' -> 'EncryptionSettings' ->> 'Enabled')::bool then 'OS disk encrypted' - else 'OS disk not encrypted' - end as reason, + CASE + WHEN (vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'StorageProfile' -> 'OSDisk' -> 'EncryptionSettings' ->> 'Enabled')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'StorageProfile' -> 'OSDisk' -> 'EncryptionSettings' ->> 'Enabled')::bool THEN 'OS disk encrypted' + ELSE 'OS disk not encrypted' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where - sub.subscription_id = vm.subscription_id and - vm.tags::text like '%' || REPLACE(REPLACE(( + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id + AND vm.tags::text LIKE '%' || REPLACE(REPLACE(( SELECT jsonb_object_agg(key, value)::text FROM jsonb_each_text('{{.azureWebTierTags}}'::jsonb) ), '{', ''), '}', '') || '%' - PrimaryTable: azure_compute_virtual_machine - ListOfTables: - - azure_compute_virtual_machine - - azure_subscription - Parameters: - - Key: azureAppTierTags - Required: true Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Encryption for Web-Tier Disk Volumes \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_guest_level_diagnostics_for_virtual_machines.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_guest_level_diagnostics_for_virtual_machines.yaml index ce321b92c..6c3ccbb83 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_guest_level_diagnostics_for_virtual_machines.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_guest_level_diagnostics_for_virtual_machines.yaml @@ -1,52 +1,52 @@ +Description: Ensure that Microsoft Azure virtual machines are configured to use OS guest-level monitoring. ID: azure_check_for_guest_level_diagnostics_for_virtual_machines -Title: "Check for Guest-Level Diagnostics for Virtual Machines" -Description: "Ensure that Microsoft Azure virtual machines are configured to use OS guest-level monitoring." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_virtual_machine QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when exists( - select 1 - from - jsonb_array_elements(extensions) as e - where - (extensions_settings -> (e ->> 'id') -> 'ladCfg' ->> 'diagnosticMonitorConfiguration') is not null or - (extensions_settings -> (e ->> 'id') -> 'WadCfg' ->> 'DiagnosticMonitorConfiguration') is not null - ) then 'ok' - else 'alarm' - end as status, - case - when exists( - select 1 - from - jsonb_array_elements(extensions) as e - where - (extensions_settings -> (e ->> 'id') -> 'ladCfg' ->> 'diagnosticMonitorConfiguration') is not null or - (extensions_settings -> (e ->> 'id') -> 'WadCfg' ->> 'DiagnosticMonitorConfiguration') is not null - ) then 'Guest-Level Diagnostics feature is enabled' - else 'Guest-Level Diagnostics feature is not enabled' - end as reason, + CASE + WHEN EXISTS ( + SELECT 1 + FROM + jsonb_array_elements(extensions) AS e + WHERE + (extensions_settings -> (e ->> 'id') -> 'ladCfg' ->> 'diagnosticMonitorConfiguration') IS NOT NULL OR + (extensions_settings -> (e ->> 'id') -> 'WadCfg' ->> 'DiagnosticMonitorConfiguration') IS NOT NULL + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM + jsonb_array_elements(extensions) AS e + WHERE + (extensions_settings -> (e ->> 'id') -> 'ladCfg' ->> 'diagnosticMonitorConfiguration') IS NOT NULL OR + (extensions_settings -> (e ->> 'id') -> 'WadCfg' ->> 'DiagnosticMonitorConfiguration') IS NOT NULL + ) THEN 'Guest-Level Diagnostics feature is enabled' + ELSE 'Guest-Level Diagnostics feature is not enabled' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine - ListOfTables: - - azure_compute_virtual_machine - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Guest-Level Diagnostics for Virtual Machines \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_installataion_for_latest_os_patches.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_installataion_for_latest_os_patches.yaml index 955b1f3b4..5348f1805 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_installataion_for_latest_os_patches.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_installataion_for_latest_os_patches.yaml @@ -1,38 +1,40 @@ +Description: Ensure that the latest OS patches available for Microsoft Azure virtual machines are applied. ID: azure_check_for_installataion_for_latest_os_patches -Title: "Check for installataion for latest OS Patches" -Description: "Ensure that the latest OS patches available for Microsoft Azure virtual machines are applied." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_virtual_machine QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when COALESCE((vm.og_description -> 'VirtualMachineInstanceView' -> 'PatchStatus' -> 'AvailablePatchSummary' ->> 'CriticalAndSecurityPatchCount')::int) + COALESCE((vm.og_description -> 'VirtualMachineInstanceView' -> 'PatchStatus' -> 'AvailablePatchSummary' ->> 'OtherPatchCount')::int) > 0 then 'alarm' - else 'ok' - end as status, - case - when COALESCE((vm.og_description -> 'VirtualMachineInstanceView' -> 'PatchStatus' -> 'AvailablePatchSummary' ->> 'CriticalAndSecurityPatchCount')::int) + COALESCE((vm.og_description -> 'VirtualMachineInstanceView' -> 'PatchStatus' -> 'AvailablePatchSummary' ->> 'OtherPatchCount')::int) > 0 then 'There are pending updates in this virtual machine' - else 'There is no pending updates in this virtual machine' - end as reason, + CASE + WHEN COALESCE((vm.og_description -> 'VirtualMachineInstanceView' -> 'PatchStatus' -> 'AvailablePatchSummary' ->> 'CriticalAndSecurityPatchCount')::int) + + COALESCE((vm.og_description -> 'VirtualMachineInstanceView' -> 'PatchStatus' -> 'AvailablePatchSummary' ->> 'OtherPatchCount')::int) > 0 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN COALESCE((vm.og_description -> 'VirtualMachineInstanceView' -> 'PatchStatus' -> 'AvailablePatchSummary' ->> 'CriticalAndSecurityPatchCount')::int) + + COALESCE((vm.og_description -> 'VirtualMachineInstanceView' -> 'PatchStatus' -> 'AvailablePatchSummary' ->> 'OtherPatchCount')::int) > 0 THEN 'There are pending updates in this virtual machine' + ELSE 'There is no pending updates in this virtual machine' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine - ListOfTables: - - azure_compute_virtual_machine - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for installataion for latest OS Patches \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_instance_termination_notifications_for_virtual_machine_scale_sets.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_instance_termination_notifications_for_virtual_machine_scale_sets.yaml index 54fee4389..300a5a489 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_instance_termination_notifications_for_virtual_machine_scale_sets.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_instance_termination_notifications_for_virtual_machine_scale_sets.yaml @@ -1,38 +1,40 @@ +Description: Ensure that instance termination notifications are enabled for your Azure virtual machine scale sets. ID: azure_check_for_instance_termination_notifications_for_virtual_machine_scale_sets -Title: "Check for Instance Termination Notifications for Virtual Machine Scale Sets" -Description: "Ensure that instance termination notifications are enabled for your Azure virtual machine scale sets." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine_scale_set + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when vm.og_description -> 'VirtualMachineScaleSet' -> 'Properties' -> 'VirtualMachineProfile' -> 'ScheduledEventsProfile' -> 'TerminateNotificationProfile' ->> 'Enable' = 'true' then 'ok' - else 'alarm' - end as status, - case - when vm.og_description -> 'VirtualMachineScaleSet' -> 'Properties' -> 'VirtualMachineProfile' -> 'ScheduledEventsProfile' -> 'TerminateNotificationProfile' ->> 'Enable' = 'true' then 'Instance Termination Notifications feature is enabled' - else 'Instance Termination Notifications feature is not enabled' - end as reason, + CASE + WHEN vm.og_description -> 'VirtualMachineScaleSet' -> 'Properties' -> 'VirtualMachineProfile' -> 'ScheduledEventsProfile' -> 'TerminateNotificationProfile' ->> 'Enable' = 'true' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN vm.og_description -> 'VirtualMachineScaleSet' -> 'Properties' -> 'VirtualMachineProfile' -> 'ScheduledEventsProfile' -> 'TerminateNotificationProfile' ->> 'Enable' = 'true' + THEN 'Instance Termination Notifications feature is enabled' + ELSE 'Instance Termination Notifications feature is not enabled' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine_scale_set as vm, - azure_subscription as sub - where + sub.display_name AS subscription + FROM + azure_compute_virtual_machine_scale_set AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine_scale_set - ListOfTables: - - azure_compute_virtual_machine_scale_set - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Instance Termination Notifications for Virtual Machine Scale Sets \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_just_in_time_access_for_virtual_machines.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_just_in_time_access_for_virtual_machines.yaml index 9aabcf58f..21119b4ea 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_just_in_time_access_for_virtual_machines.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_just_in_time_access_for_virtual_machines.yaml @@ -1,51 +1,47 @@ +Description: Ensure that Microsoft Azure virtual machines are configured to use Just-in-Time (JIT) access. ID: azure_check_for_just_in_time_access_for_virtual_machines -Title: "Check for Just-In-Time Access for Virtual Machines" -Description: "Ensure that Microsoft Azure virtual machines are configured to use Just-in-Time (JIT) access." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - distinct vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when not exists( - select 1 from - azure_security_center_jit_network_access_policy - where - virtual_machines::text like '%' || vm.id || '%' - limit 1 - ) then 'alarm' - else 'ok' - end as status, - case - when not exists( - select 1 from - azure_security_center_jit_network_access_policy - where - virtual_machines::text like '%' || vm.id || '%' - limit 1 - ) then 'Virtual machine is not associated with a Just-in-Time (JIT) network access policy.' - else 'Virtual machine is associated with a Just-in-Time (JIT) network access policy.' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where - sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_security_center_jit_network_access_policy - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT DISTINCT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN NOT EXISTS( + SELECT 1 + FROM azure_security_center_jit_network_access_policy + WHERE virtual_machines::text LIKE '%' || vm.id || '%' + LIMIT 1 + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT EXISTS( + SELECT 1 + FROM azure_security_center_jit_network_access_policy + WHERE virtual_machines::text LIKE '%' || vm.id || '%' + LIMIT 1 + ) THEN 'Virtual machine is not associated with a Just-in-Time (JIT) network access policy.' + ELSE 'Virtual machine is associated with a Just-in-Time (JIT) network access policy.' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id; Severity: high Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Just-In-Time Access for Virtual Machines \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_old_virtual_machine_disk_snapshots.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_old_virtual_machine_disk_snapshots.yaml index efe744d12..ba4920f40 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_old_virtual_machine_disk_snapshots.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_old_virtual_machine_disk_snapshots.yaml @@ -1,40 +1,46 @@ +Description: Identify and remove old virtual machine disk snapshots in order to optimize cloud costs. ID: azure_check_for_old_virtual_machine_disk_snapshots -Title: "Check for Old Virtual Machine Disk Snapshots" -Description: "Identify and remove old virtual machine disk snapshots in order to optimize cloud costs." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - s.name as resource, - s.og_account_id, - s.og_resource_id, - now() - s.time_created, - case - when now() - s.time_created > '{{.azureDiskSnapshotAgeThreshold}} days'::interval then 'alarm' - else 'ok' - end as status, - case - when now() - s.time_created > '{{.azureDiskSnapshotAgeThreshold}} days'::interval then s.name || ' snapshot is too old and can be removed' - else s.name || ' snapshot is not old' - end as reason, - case - when now() - s.time_created > '{{.azureDiskSnapshotAgeThreshold}} days'::interval then (SELECT cost FROM pennywise_cost_estimate where resource_type = 'microsoft.compute/snapshots' and resource_id = s.og_resource_id limit 1) - else 0 - end as cost_optimization, - s.resource_group, - display_name as subscription - from - azure_compute_snapshot as s, - azure_subscription as sub - where - sub.subscription_id = s.subscription_id; - PrimaryTable: azure_compute_snapshot ListOfTables: - azure_compute_snapshot - azure_subscription Parameters: - Key: azureDiskSnapshotAgeThreshold Required: true + PrimaryTable: azure_compute_snapshot + QueryToExecute: | + SELECT + s.name AS resource, + s.og_account_id, + s.og_resource_id, + NOW() - s.time_created AS age, + CASE + WHEN NOW() - s.time_created > '{{.azureDiskSnapshotAgeThreshold}} days'::interval THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOW() - s.time_created > '{{.azureDiskSnapshotAgeThreshold}} days'::interval THEN s.name || ' snapshot is too old and can be removed' + ELSE s.name || ' snapshot is not old' + END AS reason, + CASE + WHEN NOW() - s.time_created > '{{.azureDiskSnapshotAgeThreshold}} days'::interval THEN ( + SELECT cost + FROM pennywise_cost_estimate + WHERE resource_type = 'microsoft.compute/snapshots' AND resource_id = s.og_resource_id + LIMIT 1 + ) + ELSE 0 + END AS cost_optimization, + s.resource_group, + sub.display_name AS subscription + FROM + azure_compute_snapshot AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id; Severity: medium Tags: platform_score_cloud_service_name: @@ -45,5 +51,4 @@ Tags: - Azure Virtual Machines score_tags: - Optimization -IntegrationType: - - azure_subscription +Title: Check for Old Virtual Machine Disk Snapshots \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_performance_diagnostics_for_azure_virtual_machines.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_performance_diagnostics_for_azure_virtual_machines.yaml index 87a823352..7b5d34444 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_performance_diagnostics_for_azure_virtual_machines.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_performance_diagnostics_for_azure_virtual_machines.yaml @@ -1,42 +1,47 @@ +Description: Ensure that Azure virtual machines are configured to use the Performance Diagnostics tool. ID: azure_check_for_performance_diagnostics_for_azure_virtual_machines -Title: "Check for Performance Diagnostics for Azure Virtual Machines" -Description: "Ensure that Azure virtual machines are configured to use the Performance Diagnostics tool." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when exists( - select 1 from jsonb_array_elements(vm.extensions) as ex - where ('AzurePerformanceDiagnosticsLinux' = (ex ->> 'name')) or ('AzurePerformanceDiagnostics' = (ex ->> 'name')) - ) then 'ok' - else 'alarm' - end as status, - case - when exists( - select 1 from jsonb_array_elements(vm.extensions) as ex - where ('AzurePerformanceDiagnosticsLinux' = (ex ->> 'name')) or ('AzurePerformanceDiagnostics' = (ex ->> 'name')) - ) then 'Performance Diagnostics feature, powered by PerfInsights extension, is enabled' - else 'Performance Diagnostics feature, powered by PerfInsights extension, is not enabled' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_subscription as sub on sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN EXISTS( + SELECT 1 FROM jsonb_array_elements(vm.extensions) AS ex + WHERE ('AzurePerformanceDiagnosticsLinux' = (ex ->> 'name')) + OR ('AzurePerformanceDiagnostics' = (ex ->> 'name')) + ) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS( + SELECT 1 FROM jsonb_array_elements(vm.extensions) AS ex + WHERE ('AzurePerformanceDiagnosticsLinux' = (ex ->> 'name')) + OR ('AzurePerformanceDiagnostics' = (ex ->> 'name')) + ) + THEN 'Performance Diagnostics feature, powered by PerfInsights extension, is enabled' + ELSE 'Performance Diagnostics feature, powered by PerfInsights extension, is not enabled' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN azure_subscription AS sub + ON sub.subscription_id = vm.subscription_id Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Performance Diagnostics for Azure Virtual Machines \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_ssh_authentication_type.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_ssh_authentication_type.yaml index 4a1e8dca8..85b365e93 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_ssh_authentication_type.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_ssh_authentication_type.yaml @@ -1,38 +1,38 @@ +Description: Ensure that Azure Linux-based virtual machines (VMs) are configured to use SSH keys. ID: azure_check_for_ssh_authentication_type -Title: "Check for SSH Authentication Type" -Description: "Ensure that Azure Linux-based virtual machines (VMs) are configured to use SSH keys." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_virtual_machine QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'OSProfile' -> 'LinuxConfiguration' ->> 'DisablePasswordAuthentication' = 'false' then 'alarm' - else 'ok' - end as status, - case - when vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'OSProfile' -> 'LinuxConfiguration' ->> 'DisablePasswordAuthentication' = 'false' then 'SSH authentication type for the selected Microsoft Azure virtual machine is password-based and is not secured' - else 'SSH authentication type for the selected Microsoft Azure virtual machine is secured' - end as reason, + CASE + WHEN vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'OSProfile' -> 'LinuxConfiguration' ->> 'DisablePasswordAuthentication' = 'false' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vm.og_description -> 'VirtualMachine' -> 'Properties' -> 'OSProfile' -> 'LinuxConfiguration' ->> 'DisablePasswordAuthentication' = 'false' THEN 'SSH authentication type for the selected Microsoft Azure virtual machine is password-based and is not secured' + ELSE 'SSH authentication type for the selected Microsoft Azure virtual machine is secured' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine - ListOfTables: - - azure_compute_virtual_machine - - azure_subscription - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for SSH Authentication Type \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_sufficient_daily_backup_retention_period.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_sufficient_daily_backup_retention_period.yaml index 62b1b3ede..b1b5f225a 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_sufficient_daily_backup_retention_period.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_sufficient_daily_backup_retention_period.yaml @@ -1,29 +1,9 @@ +Description: Ensure there is a sufficient daily backup retention period configured for Azure virtual machines. ID: azure_check_for_sufficient_daily_backup_retention_period -Title: "Check for Sufficient Daily Backup Retention Period" -Description: "Ensure there is a sufficient daily backup retention period configured for Azure virtual machines." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when (bp.properties -> 'RetentionPolicy' -> 'dailySchedule' -> 'retentionDuration' ->> 'count')::int < '{{.azureSufficientDailyBackupRetention}}'::int then 'alarm' - else 'ok' - end as status, - case - when (bp.properties -> 'RetentionPolicy' -> 'dailySchedule' -> 'retentionDuration' ->> 'count')::int < '{{.azureSufficientDailyBackupRetention}}'::int then 'backup policy does not have a sufficient daily backup retention period configured.' - else 'backup policy has a sufficient daily backup retention period configured.' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_subscription as sub on sub.subscription_id = vm.subscription_id - left join azure_recovery_services_backup_item as bi on vm.id = (bi.properties ->> 'SourceResourceID') - left join azure_recovery_services_backup_policy as bp on bi.properties ->> 'PolicyID' = bp.id - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_recovery_services_backup_item @@ -32,11 +12,31 @@ Query: Parameters: - Key: azureSufficientDailyBackupRetention Required: true + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN (bp.properties -> 'RetentionPolicy' -> 'dailySchedule' -> 'retentionDuration' ->> 'count')::int < '{{.azureSufficientDailyBackupRetention}}'::int THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (bp.properties -> 'RetentionPolicy' -> 'dailySchedule' -> 'retentionDuration' ->> 'count')::int < '{{.azureSufficientDailyBackupRetention}}'::int THEN 'backup policy does not have a sufficient daily backup retention period configured.' + ELSE 'backup policy has a sufficient daily backup retention period configured.' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN azure_subscription AS sub ON sub.subscription_id = vm.subscription_id + LEFT JOIN azure_recovery_services_backup_item AS bi ON vm.id = (bi.properties ->> 'SourceResourceID') + LEFT JOIN azure_recovery_services_backup_policy AS bp ON bi.properties ->> 'PolicyID' = bp.id Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Sufficient Daily Backup Retention Period \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_sufficient_instant_restore_retention_period.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_sufficient_instant_restore_retention_period.yaml index 5c2a18772..1ce6ac7cb 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_sufficient_instant_restore_retention_period.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_sufficient_instant_restore_retention_period.yaml @@ -1,29 +1,9 @@ +Description: Ensure there is a sufficient instant restore retention period configured for Azure virtual machines. ID: azure_check_for_sufficient_instant_restore_retention_period -Title: "Check for Sufficient Instant Restore Retention Period" -Description: "Ensure there is a sufficient instant restore retention period configured for Azure virtual machines." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when (bp.properties ->> 'InstantRpRetentionRangeInDays')::int < '{{.azureSufficientInstantRestoreRetention}}'::int then 'alarm' - else 'ok' - end as status, - case - when (bp.properties ->> 'InstantRpRetentionRangeInDays')::int < '{{.azureSufficientInstantRestoreRetention}}'::int then 'backup policy does not have a sufficient daily backup retention period configured.' - else 'backup policy has a sufficient daily backup retention period configured.' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_subscription as sub on sub.subscription_id = vm.subscription_id - left join azure_recovery_services_backup_item as bi on vm.id = (bi.properties ->> 'SourceResourceID') - left join azure_recovery_services_backup_policy as bp on bi.properties ->> 'PolicyID' = bp.id - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_recovery_services_backup_item @@ -32,11 +12,34 @@ Query: Parameters: - Key: azureSufficientInstantRestoreRetention Required: true + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN (bp.properties ->> 'InstantRpRetentionRangeInDays')::int < '{{.azureSufficientInstantRestoreRetention}}'::int THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (bp.properties ->> 'InstantRpRetentionRangeInDays')::int < '{{.azureSufficientInstantRestoreRetention}}'::int THEN 'backup policy does not have a sufficient daily backup retention period configured.' + ELSE 'backup policy has a sufficient daily backup retention period configured.' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN azure_subscription AS sub + ON sub.subscription_id = vm.subscription_id + LEFT JOIN azure_recovery_services_backup_item AS bi + ON vm.id = (bi.properties ->> 'SourceResourceID') + LEFT JOIN azure_recovery_services_backup_policy AS bp + ON bi.properties ->> 'PolicyID' = bp.id Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Sufficient Instant Restore Retention Period \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_system_assigned_managed_identities.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_system_assigned_managed_identities.yaml index f5b376985..1e20624ca 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_system_assigned_managed_identities.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_system_assigned_managed_identities.yaml @@ -1,38 +1,38 @@ +Description: Ensure that Azure virtual machines are configured to use system-assigned managed identities. ID: azure_check_for_system_assigned_managed_identities -Title: "Check for System-Assigned Managed Identities" -Description: "Ensure that Azure virtual machines are configured to use system-assigned managed identities." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_virtual_machine QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when (vm.og_description -> 'VirtualMachine' ->> 'Identity') is null then 'alarm' - else 'ok' - end as status, - case - when (vm.og_description -> 'VirtualMachine' ->> 'Identity') is null then 'system-assigned managed identity is not enabled' - else 'system-assigned managed identity is enabled' - end as reason, + CASE + WHEN (vm.og_description -> 'VirtualMachine' ->> 'Identity') IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (vm.og_description -> 'VirtualMachine' ->> 'Identity') IS NULL THEN 'system-assigned managed identity is not enabled' + ELSE 'system-assigned managed identity is enabled' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine - ListOfTables: - - azure_compute_virtual_machine - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for System-Assigned Managed Identities \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_unattached_virtual_machine_disk_volumes.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_unattached_virtual_machine_disk_volumes.yaml index d88477638..cb3990640 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_unattached_virtual_machine_disk_volumes.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_unattached_virtual_machine_disk_volumes.yaml @@ -1,37 +1,44 @@ +Description: Remove any unattached Azure virtual machine (VM) disk volumes to improve security and reduce costs ID: azure_check_for_unattached_virtual_machine_disk_volumes -Title: "Check for Unattached Virtual Machine Disk Volumes" -Description: "Remove any unattached Azure virtual machine (VM) disk volumes to improve security and reduce costs" +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_disk + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_disk QueryToExecute: | - select - disk.id as resource, + SELECT + disk.id AS resource, disk.og_account_id, disk.og_resource_id, - case - when disk.disk_state = 'Unattached' then 'alarm' - else 'ok' - end as status, - case - when disk.disk_state = 'Unattached' then disk.title || ' has no attachments.' - else disk.title || ' has attachments.' - end as reason, - case - when disk.disk_state = 'Unattached' then (SELECT cost FROM pennywise_cost_estimate where resource_type = 'microsoft.compute/disks' and resource_id = disk.og_resource_id limit 1) - else 0 - end as cost_optimization, + CASE + WHEN disk.disk_state = 'Unattached' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN disk.disk_state = 'Unattached' THEN disk.title || ' has no attachments.' + ELSE disk.title || ' has attachments.' + END AS reason, + CASE + WHEN disk.disk_state = 'Unattached' THEN ( + SELECT cost + FROM pennywise_cost_estimate + WHERE resource_type = 'microsoft.compute/disks' + AND resource_id = disk.og_resource_id + LIMIT 1 + ) + ELSE 0 + END AS cost_optimization, disk.resource_group, - display_name as subscription - from - azure_compute_disk as disk, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_disk AS disk, + azure_subscription AS sub + WHERE sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk - ListOfTables: - - azure_compute_disk - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: @@ -42,5 +49,4 @@ Tags: - Azure Virtual Machines score_tags: - Orphaned Resources -IntegrationType: - - azure_subscription +Title: Check for Unattached Virtual Machine Disk Volumes \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_unused_load_balancers.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_unused_load_balancers.yaml index 5d322df5d..f402022d5 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_unused_load_balancers.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_unused_load_balancers.yaml @@ -1,44 +1,52 @@ +Description: Identify and remove unused load balancers from your Microsoft Azure cloud account. ID: azure_check_for_unused_load_balancers -Title: "Check for Unused Load Balancers" -Description: "Identify and remove unused load balancers from your Microsoft Azure cloud account." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_lb + - azure_subscription + Parameters: [] + PrimaryTable: azure_lb QueryToExecute: | - select - lb.name as resource, + SELECT + lb.name AS resource, lb.og_resource_id, lb.og_account_id, - case - when EXISTS ( + CASE + WHEN EXISTS ( SELECT 1 FROM jsonb_array_elements(backend_address_pools) AS p - WHERE p -> 'properties' ->> 'backendIPConfigurations' is not null - ) then 'ok' - else 'alarm' - end as status, - case - when EXISTS ( - SELECT 1 FROM jsonb_array_elements(backend_address_pools) AS p - WHERE p -> 'properties' ->> 'backendIPConfigurations' is not null - ) then lb.name || ' is used.' - else lb.name || ' is unused.' - end as reason, - case - when EXISTS ( + WHERE p -> 'properties' ->> 'backendIPConfigurations' IS NOT NULL + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( SELECT 1 FROM jsonb_array_elements(backend_address_pools) AS p - WHERE p -> 'properties' ->> 'backendIPConfigurations' is not null - ) then 0 - else (SELECT COALESCE(cost, 0) from pennywise_cost_estimate where resource_type = 'microsoft.network/loadbalancers' AND resource_id = lb.og_resource_id limit 1) - end as cost_optimization, - lb.resource_group as resource_group, - sub.display_name as subscription - from - azure_lb as lb - left join azure_subscription as sub on lb.subscription_id = sub.subscription_id - PrimaryTable: azure_lb - ListOfTables: - - azure_lb - - azure_subscription - Parameters: [] + WHERE p -> 'properties' ->> 'backendIPConfigurations' IS NOT NULL + ) THEN lb.name || ' is used.' + ELSE lb.name || ' is unused.' + END AS reason, + CASE + WHEN EXISTS ( + SELECT 1 FROM jsonb_array_elements(backend_address_pools) AS p + WHERE p -> 'properties' ->> 'backendIPConfigurations' IS NOT NULL + ) THEN 0 + ELSE ( + SELECT COALESCE(cost, 0) + FROM pennywise_cost_estimate + WHERE resource_type = 'microsoft.network/loadbalancers' + AND resource_id = lb.og_resource_id + LIMIT 1 + ) + END AS cost_optimization, + lb.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_lb AS lb + LEFT JOIN azure_subscription AS sub + ON lb.subscription_id = sub.subscription_id Severity: low Tags: platform_score_cloud_service_name: @@ -49,5 +57,4 @@ Tags: - Azure Network score_tags: - Orphaned Resources -IntegrationType: - - azure_subscription +Title: Check for Unused Load Balancers \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_approved_extensions_only.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_approved_extensions_only.yaml index f0b56f302..e48b82581 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_approved_extensions_only.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_approved_extensions_only.yaml @@ -1,44 +1,47 @@ +Description: Ensure that only approved extensions are installed on your Microsoft Azure virtual machines. ID: azure_check_for_usage_of_approved_extensions_only -Title: "Check for usage of Approved Extensions Only" -Description: "Ensure that only approved extensions are installed on your Microsoft Azure virtual machines." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when exists( - select 1 from jsonb_array_elements(vm.extensions) as ex - where '{{.azureAllowedVmExtentions}}' not like '%' || (ex ->> 'name') || '%' - ) then 'alarm' - else 'ok' - end as status, - case - when exists( - select 1 from jsonb_array_elements(vm.extensions) as ex - where '{{.azureAllowedVmExtentions}}' not like '%' || (ex ->> 'name') || '%' - ) then 'VM is using a not allowed extention' - else 'VM is only using allowed extentions' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_subscription as sub on sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: - Key: azureAllowedVmExtentions Required: true + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN EXISTS ( + SELECT 1 FROM jsonb_array_elements(vm.extensions) AS ex + WHERE '{{.azureAllowedVmExtentions}}' NOT LIKE '%' || (ex ->> 'name') || '%' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 FROM jsonb_array_elements(vm.extensions) AS ex + WHERE '{{.azureAllowedVmExtentions}}' NOT LIKE '%' || (ex ->> 'name') || '%' + ) THEN 'VM is using a not allowed extension' + ELSE 'VM is only using allowed extensions' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN + azure_subscription AS sub + ON + sub.subscription_id = vm.subscription_id Severity: high Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for usage of Approved Extensions Only \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_byok_for_disk_volumes_encryption.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_byok_for_disk_volumes_encryption.yaml index 7ded62904..5039b7685 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_byok_for_disk_volumes_encryption.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_byok_for_disk_volumes_encryption.yaml @@ -1,33 +1,34 @@ +Description: Use customer-managed keys for Microsoft Azure virtual machine (VM) disk volumes encryption. ID: azure_check_for_usage_of_byok_for_disk_volumes_encryption -Title: "Check for usage of BYOK for Disk Volumes Encryption" -Description: "Use customer-managed keys for Microsoft Azure virtual machine (VM) disk volumes encryption." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_disk + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_disk QueryToExecute: | - select - disk.id as resource, + SELECT + disk.id AS resource, disk.og_account_id, disk.og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'ok' - else 'alarm' - end as status, - case - when encryption_type = 'EncryptionAtRestWithCustomerKey' then 'Disk is encrypted by CMK.' - else 'Disk is encrypted with Service Managed Key instead of CMK.' - end as reason, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithCustomerKey' THEN 'Disk is encrypted by CMK.' + ELSE 'Disk is encrypted with Service Managed Key instead of CMK.' + END AS reason, disk.resource_group, - display_name as subscription - from - azure_compute_disk as disk, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_disk AS disk, + azure_subscription AS sub + WHERE sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk - ListOfTables: - - azure_compute_disk - - azure_subscription - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -38,5 +39,4 @@ Tags: - Azure Virtual Machines score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Check for usage of BYOK for Disk Volumes Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_customer_managed_keys_for_virtual_hard_disk_encryption.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_customer_managed_keys_for_virtual_hard_disk_encryption.yaml index 89ab2393c..f5aa12031 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_customer_managed_keys_for_virtual_hard_disk_encryption.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_customer_managed_keys_for_virtual_hard_disk_encryption.yaml @@ -1,33 +1,34 @@ +Description: Ensure that Customer Managed Keys are used to encrypt Virtual Hard Disk (VHD) volumes. ID: azure_check_for_usage_of_customer_managed_keys_for_virtual_hard_disk_encryption -Title: "Check for usage of Customer Managed Keys for Virtual Hard Disk Encryption" -Description: "Ensure that Customer Managed Keys are used to encrypt Virtual Hard Disk (VHD) volumes." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_disk + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_disk QueryToExecute: | - select - disk.id as resource, + SELECT + disk.id AS resource, disk.og_account_id, disk.og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithPlatformKey' then 'alarm' - else 'ok' - end as status, - case - when encryption_type = 'EncryptionAtRestWithPlatformKey' then 'Disk is encrypted by CMK.' - else 'Disk is encrypted with Platform Key instead of CMK.' - end as reason, + CASE + WHEN encryption_type = 'EncryptionAtRestWithPlatformKey' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithPlatformKey' THEN 'Disk is encrypted by CMK.' + ELSE 'Disk is encrypted with Platform Key instead of CMK.' + END AS reason, disk.resource_group, - display_name as subscription - from - azure_compute_disk as disk, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_disk AS disk, + azure_subscription AS sub + WHERE sub.subscription_id = disk.subscription_id; - PrimaryTable: azure_compute_disk - ListOfTables: - - azure_compute_disk - - azure_subscription - Parameters: [] Severity: high Tags: platform_score_cloud_service_name: @@ -38,5 +39,4 @@ Tags: - Azure Virtual Machines score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Check for usage of Customer Managed Keys for Virtual Hard Disk Encryption \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_endpoint_protection.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_endpoint_protection.yaml index 19003203d..7779853f0 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_endpoint_protection.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_endpoint_protection.yaml @@ -1,39 +1,45 @@ +Description: Ensure that endpoint protection is installed on your Microsoft Azure virtual machines. ID: azure_check_for_usage_of_endpoint_protection -Title: "Check for usage of Endpoint Protection" -Description: "Ensure that endpoint protection is installed on your Microsoft Azure virtual machines." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when exists( - select 1 from jsonb_array_elements(vm.extensions) as ex - where 'EndpointSecurity,Antimalware,EndpointProtection,SCWPAgent,PortalProtectExtension,FileSecurity' ilike '%' || (ex ->> 'name') || '%' - ) then 'ok' - else 'alarm' - end as status, - case - when exists( - select 1 from jsonb_array_elements(vm.extensions) as ex - where 'EndpointSecurity,Antimalware,EndpointProtection,SCWPAgent,PortalProtectExtension,FileSecurity' ilike '%' || (ex ->> 'name') || '%' - ) then 'Azure virtual machine has anti-malware protection' - else 'Azure virtual machine is missing anti-malware protection' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_subscription as sub on sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements(vm.extensions) AS ex + WHERE 'EndpointSecurity,Antimalware,EndpointProtection,SCWPAgent,PortalProtectExtension,FileSecurity' ILIKE '%' || (ex ->> 'name') || '%' + ) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS( + SELECT 1 + FROM jsonb_array_elements(vm.extensions) AS ex + WHERE 'EndpointSecurity,Antimalware,EndpointProtection,SCWPAgent,PortalProtectExtension,FileSecurity' ILIKE '%' || (ex ->> 'name') || '%' + ) THEN 'Azure virtual machine has anti-malware protection' + ELSE 'Azure virtual machine is missing anti-malware protection' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN + azure_subscription AS sub + ON + sub.subscription_id = vm.subscription_id Severity: high -Tags: +Tags: platform_score_cloud_service_name: - Azure Virtual Machines platform_score_use_case: @@ -42,5 +48,4 @@ Tags: - Azure Virtual Machines score_tags: - Unencrypted Traffic -IntegrationType: - - azure_subscription +Title: Check for usage of Endpoint Protection \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_managed_disk_volumes_for_virtual_machines.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_managed_disk_volumes_for_virtual_machines.yaml index 61d7646b6..8f71f5e17 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_managed_disk_volumes_for_virtual_machines.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_usage_of_managed_disk_volumes_for_virtual_machines.yaml @@ -1,35 +1,39 @@ +Description: Ensure that your Microsoft Azure virtual machines are using managed disk volumes. ID: azure_check_for_usage_of_managed_disk_volumes_for_virtual_machines -Title: "Check for usage of Managed Disk Volumes for Virtual Machines" -Description: "Ensure that your Microsoft Azure virtual machines are using managed disk volumes." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.name as resource, - vm.og_resource_id, - vm.og_account_id, - case - when (vm.managed_disk_id is null and not exists ( - select 1 from jsonb_array_elements(data_disks) as d where d ->> 'managedDisk' is not null - )) then 'alarm' - else 'ok' - end as status, - case - when (vm.managed_disk_id is null and not exists ( - select 1 from jsonb_array_elements(data_disks) as d where d ->> 'managedDisk' is not null - )) then vm.name || ' is not using managed disks.' - else vm.name || ' is using managed disks.' - end as reason, - vm.resource_group as resource_group, - sub.display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_subscription as sub on vm.subscription_id = sub.subscription_id - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.name AS resource, + vm.og_resource_id, + vm.og_account_id, + CASE + WHEN (vm.managed_disk_id IS NULL AND NOT EXISTS ( + SELECT 1 FROM jsonb_array_elements(data_disks) AS d WHERE d->>'managedDisk' IS NOT NULL + )) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (vm.managed_disk_id IS NULL AND NOT EXISTS ( + SELECT 1 FROM jsonb_array_elements(data_disks) AS d WHERE d->>'managedDisk' IS NOT NULL + )) THEN vm.name || ' is not using managed disks.' + ELSE vm.name || ' is using managed disks.' + END AS reason, + vm.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN + azure_subscription AS sub + ON + vm.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -40,5 +44,4 @@ Tags: - Azure Virtual Machines score_tags: - Lacking High Availability -IntegrationType: - - azure_subscription +Title: Check for usage of Managed Disk Volumes for Virtual Machines \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_virtual_machine_access_using_microsoft_entra_id_authentication.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_virtual_machine_access_using_microsoft_entra_id_authentication.yaml index cd0ab7d9a..e771b113b 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_virtual_machine_access_using_microsoft_entra_id_authentication.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_virtual_machine_access_using_microsoft_entra_id_authentication.yaml @@ -1,42 +1,49 @@ +Description: Configure your Microsoft Azure virtual machines to use Microsoft Entra ID credentials for secure authentication. ID: azure_check_for_virtual_machine_access_using_microsoft_entra_id_authentication -Title: "Check for Virtual Machine Access using Microsoft Entra ID Authentication" -Description: "Configure your Microsoft Azure virtual machines to use Microsoft Entra ID credentials for secure authentication." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when exists( - select 1 from jsonb_array_elements(vm.extensions) as ex - where ('AADLoginForWindows' = (ex ->> 'name')) or ('AADLoginForLinux' = (ex ->> 'name')) - ) then 'ok' - else 'alarm' - end as status, - case - when exists( - select 1 from jsonb_array_elements(vm.extensions) as ex - where ('AADLoginForWindows' = (ex ->> 'name')) or ('AADLoginForLinux' = (ex ->> 'name')) - ) then 'Azure virtual machine is configured to use Microsoft Entra ID authentication' - else 'Azure virtual machine is not configured to use Microsoft Entra ID authentication' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_subscription as sub on sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(vm.extensions) AS ex + WHERE ('AADLoginForWindows' = (ex ->> 'name')) + OR ('AADLoginForLinux' = (ex ->> 'name')) + ) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements(vm.extensions) AS ex + WHERE ('AADLoginForWindows' = (ex ->> 'name')) + OR ('AADLoginForLinux' = (ex ->> 'name')) + ) + THEN 'Azure virtual machine is configured to use Microsoft Entra ID authentication' + ELSE 'Azure virtual machine is not configured to use Microsoft Entra ID authentication' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN azure_subscription AS sub + ON sub.subscription_id = vm.subscription_id Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Virtual Machine Access using Microsoft Entra ID Authentication \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_virtual_machine_boot_diagnostics.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_virtual_machine_boot_diagnostics.yaml index 9cd9687bf..76c250a6a 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_virtual_machine_boot_diagnostics.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_virtual_machine_boot_diagnostics.yaml @@ -1,38 +1,38 @@ +Description: Ensure that Microsoft Azure virtual machines are configured to use Boot Diagnostics feature. ID: azure_check_for_virtual_machine_boot_diagnostics -Title: "Check for Virtual Machine Boot Diagnostics" -Description: "Ensure that Microsoft Azure virtual machines are configured to use Boot Diagnostics feature." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_virtual_machine + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_virtual_machine QueryToExecute: | - select - vm.id as resource, + SELECT + vm.id AS resource, vm.og_account_id, vm.og_resource_id, - case - when (boot_diagnostics_enabled)::bool then 'ok' - else 'alarm' - end as status, - case - when (boot_diagnostics_enabled)::bool then 'Boot Diagnostics feature is enabled' - else 'Boot Diagnostics feature is not enabled' - end as reason, + CASE + WHEN (boot_diagnostics_enabled)::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (boot_diagnostics_enabled)::bool THEN 'Boot Diagnostics feature is enabled' + ELSE 'Boot Diagnostics feature is not enabled' + END AS reason, vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine as vm, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_virtual_machine AS vm, + azure_subscription AS sub + WHERE sub.subscription_id = vm.subscription_id; - PrimaryTable: azure_compute_virtual_machine - ListOfTables: - - azure_compute_virtual_machine - - azure_subscription - Parameters: [] Severity: medium Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Virtual Machine Boot Diagnostics \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_zone_redundant_virtual_machine_scale_sets.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_zone_redundant_virtual_machine_scale_sets.yaml index eea9324ea..f81685c72 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_check_for_zone_redundant_virtual_machine_scale_sets.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_check_for_zone_redundant_virtual_machine_scale_sets.yaml @@ -1,38 +1,38 @@ +Description: Ensure that Azure virtual machine scale sets are configured for zone redundancy. ID: azure_check_for_zone_redundant_virtual_machine_scale_sets -Title: "Check for Zone-Redundant Virtual Machine Scale Sets" -Description: "Ensure that Azure virtual machine scale sets are configured for zone redundancy." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.id as resource, - vm.og_account_id, - vm.og_resource_id, - case - when (select count(*) from jsonb_array_elements_text(zones)) > 1 then 'ok' - else 'alarm' - end as status, - case - when (select count(*) from jsonb_array_elements_text(zones)) > 1 then 'VM Scale-set is available in more than one zone' - else 'VM Scale-set is not available in more than one zone' - end as reason, - vm.resource_group, - display_name as subscription - from - azure_compute_virtual_machine_scale_set as vm, - azure_subscription as sub - where - sub.subscription_id = vm.subscription_id - PrimaryTable: azure_compute_virtual_machine_scale_set ListOfTables: - azure_compute_virtual_machine_scale_set - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine_scale_set + QueryToExecute: | + SELECT + vm.id AS resource, + vm.og_account_id, + vm.og_resource_id, + CASE + WHEN (SELECT COUNT(*) FROM jsonb_array_elements_text(zones)) > 1 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (SELECT COUNT(*) FROM jsonb_array_elements_text(zones)) > 1 THEN 'VM Scale-set is available in more than one zone' + ELSE 'VM Scale-set is not available in more than one zone' + END AS reason, + vm.resource_group, + display_name AS subscription + FROM + azure_compute_virtual_machine_scale_set AS vm, + azure_subscription AS sub + WHERE + sub.subscription_id = vm.subscription_id Severity: high Tags: platform_score_cloud_service_name: - Azure Virtual Machines score_service_name: - Azure Virtual Machines -IntegrationType: - - azure_subscription +Title: Check for Zone-Redundant Virtual Machine Scale Sets \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_boot_disk_volumes.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_boot_disk_volumes.yaml index d968c4440..47d95ce22 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_boot_disk_volumes.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_boot_disk_volumes.yaml @@ -1,33 +1,36 @@ +Description: Ensure that Azure Disk Encryption is enabled for Azure virtual machine boot volumes to protect data at rest. ID: azure_disk_encryption_for_boot_disk_volumes -Title: "Azure Disk Encryption for Boot Disk Volumes" -Description: "Ensure that Azure Disk Encryption is enabled for Azure virtual machine boot volumes to protect data at rest." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.name as resource, - vm.og_resource_id, - vm.og_account_id, - case - when encryption_settings_collection_enabled then 'ok' - else 'alarm' - end as status, - case - when encryption_settings_collection_enabled then vm.name || ' disk encryption for os disk is enabled.' - else vm.name || ' disk encryption for os disk is not enabled.' - end as reason, - vm.resource_group as resource_group, - sub.display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_compute_disk as d on d.name = vm.os_disk_name - left join azure_subscription as sub on vm.subscription_id = sub.subscription_id - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_disk - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.name AS resource, + vm.og_resource_id, + vm.og_account_id, + CASE + WHEN encryption_settings_collection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encryption_settings_collection_enabled THEN vm.name || ' disk encryption for os disk is enabled.' + ELSE vm.name || ' disk encryption for os disk is not enabled.' + END AS reason, + vm.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN azure_compute_disk AS d + ON d.name = vm.os_disk_name + LEFT JOIN azure_subscription AS sub + ON vm.subscription_id = sub.subscription_id Severity: medium Tags: platform_score_cloud_service_name: @@ -38,5 +41,4 @@ Tags: - Azure Virtual Machines score_tags: - Unencrypted Storage -IntegrationType: - - azure_subscription +Title: Azure Disk Encryption for Boot Disk Volumes \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_non_boot_disk_volumes.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_non_boot_disk_volumes.yaml index 11bd0fae0..ae3a91326 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_non_boot_disk_volumes.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_non_boot_disk_volumes.yaml @@ -1,35 +1,38 @@ +Description: Ensure that Azure Disk Encryption is enabled for Microsoft Azure virtual machines for non-boot volumes. ID: azure_disk_encryption_for_non_boot_disk_volumes -Title: "Azure Disk Encryption for Non Boot Disk Volumes" -Description: "Ensure that Azure Disk Encryption is enabled for Microsoft Azure virtual machines for non-boot volumes." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - vm.name as resource, - vm.og_resource_id, - vm.og_account_id, - case - when d.encryption_settings_collection_enabled then 'ok' - else 'alarm' - end as status, - case - when d.encryption_settings_collection_enabled then vm.name || ' disk encryption for non-boot volume ' || d.name || ' is enabled.' - else vm.name || ' disk encryption for non-boot volume ' || d.name || ' is not enabled.' - end as reason, - vm.resource_group as resource_group, - sub.display_name as subscription - from - azure_compute_virtual_machine as vm - left join azure_compute_disk as d on d.managed_by = vm.id - left join azure_subscription as sub on vm.subscription_id = sub.subscription_id - where - d.name != vm.os_disk_name; - PrimaryTable: azure_compute_virtual_machine ListOfTables: - azure_compute_disk - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_virtual_machine + QueryToExecute: | + SELECT + vm.name AS resource, + vm.og_resource_id, + vm.og_account_id, + CASE + WHEN d.encryption_settings_collection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.encryption_settings_collection_enabled THEN vm.name || ' disk encryption for non-boot volume ' || d.name || ' is enabled.' + ELSE vm.name || ' disk encryption for non-boot volume ' || d.name || ' is not enabled.' + END AS reason, + vm.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_virtual_machine AS vm + LEFT JOIN + azure_compute_disk AS d ON d.managed_by = vm.id + LEFT JOIN + azure_subscription AS sub ON vm.subscription_id = sub.subscription_id + WHERE + d.name != vm.os_disk_name; Severity: medium Tags: platform_score_cloud_service_name: @@ -40,5 +43,4 @@ Tags: - Azure Virtual Machines score_tags: - Unencrypted Storage -IntegrationType: - - azure_subscription +Title: Azure Disk Encryption for Non Boot Disk Volumes \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_unattached_disk_volumes.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_unattached_disk_volumes.yaml index 7695a3257..bf2942d62 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_unattached_disk_volumes.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_disk_encryption_for_unattached_disk_volumes.yaml @@ -1,33 +1,34 @@ +Description: Ensure that Azure Disk Encryption is enabled for unattached Azure virtual machine disk volumes. ID: azure_disk_encryption_for_unattached_disk_volumes -Title: "Azure Disk Encryption for Unattached Disk Volumes" -Description: "Ensure that Azure Disk Encryption is enabled for unattached Azure virtual machine disk volumes." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - d.name as resource, - d.og_resource_id, - d.og_account_id, - case - when d.encryption_settings_collection_enabled then 'ok' - else 'alarm' - end as status, - case - when d.encryption_settings_collection_enabled then d.name || ' disk encryption for unattached volume is enabled.' - else d.name || ' disk encryption for unattached volume is not enabled.' - end as reason, - d.resource_group as resource_group, - sub.display_name as subscription - from - azure_compute_disk as d - left join azure_subscription as sub on d.subscription_id = sub.subscription_id - where - d.managed_by is null; - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + d.name AS resource, + d.og_resource_id, + d.og_account_id, + CASE + WHEN d.encryption_settings_collection_enabled THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.encryption_settings_collection_enabled THEN d.name || ' disk encryption for unattached volume is enabled.' + ELSE d.name || ' disk encryption for unattached volume is not enabled.' + END AS reason, + d.resource_group AS resource_group, + sub.display_name AS subscription + FROM + azure_compute_disk AS d + LEFT JOIN azure_subscription AS sub ON d.subscription_id = sub.subscription_id + WHERE + d.managed_by IS NULL; Severity: medium Tags: platform_score_cloud_service_name: @@ -38,5 +39,4 @@ Tags: - Azure Virtual Machines score_tags: - Unencrypted Storage -IntegrationType: - - azure_subscription +Title: Azure Disk Encryption for Unattached Disk Volumes \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_disks_should_use_standard_snapshots.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_disks_should_use_standard_snapshots.yaml index 8641b75a5..727392d7e 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_disks_should_use_standard_snapshots.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_disks_should_use_standard_snapshots.yaml @@ -4,28 +4,28 @@ Description: "Use standard storage instead of premium storage for managed disk s Query: Engine: odysseus-v0.0.1 QueryToExecute: | - select - ss.id as resource, + SELECT + ss.id AS resource, ss.og_resource_id, ss.og_account_id, - case - when ss.sku_tier = 'Standard' then 'ok' - else 'alarm' - end as status, - case - when ss.sku_tier = 'Standard' then 0 - else (SELECT cost FROM pennywise_cost_estimate where resource_type = 'microsoft.compute/snapshots' and resource_id = ss.og_resource_id limit 1) - end as cost_optimization, - case - when ss.sku_tier = 'Standard' then ss.title || ' has storage type ' || ss.sku_tier || '.' - else ss.title || ' has storage type ' || ss.sku_tier || '.' - end as reason, + CASE + WHEN ss.sku_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN ss.sku_tier = 'Standard' THEN 0 + ELSE (SELECT cost FROM pennywise_cost_estimate WHERE resource_type = 'microsoft.compute/snapshots' AND resource_id = ss.og_resource_id LIMIT 1) + END AS cost_optimization, + CASE + WHEN ss.sku_tier = 'Standard' THEN ss.title || ' has storage type ' || ss.sku_tier || '.' + ELSE ss.title || ' has storage type ' || ss.sku_tier || '.' + END AS reason, ss.resource_group, - display_name as subscription - from - azure_compute_snapshot as ss, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_snapshot AS ss, + azure_subscription AS sub + WHERE ss.subscription_id = sub.subscription_id; PrimaryTable: azure_compute_snapshot ListOfTables: @@ -43,4 +43,4 @@ Tags: score_tags: - Over Utilization IntegrationType: - - azure_subscription + - azure_subscription \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_boot_disk_using_cmk.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_boot_disk_using_cmk.yaml index 338e5a322..16afc0ad3 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_boot_disk_using_cmk.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_boot_disk_using_cmk.yaml @@ -1,35 +1,36 @@ +Description: Ensure that Azure VM managed disk boot volumes are encrypted at rest using customer-managed keys (CMKs). ID: azure_server_side_encryption_for_boot_disk_using_cmk -Title: "Server Side Encryption for Boot Disk using CMK" -Description: "Ensure that Azure VM managed disk boot volumes are encrypted at rest using customer-managed keys (CMKs)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - disk.id as resource, - disk.og_account_id, - disk.og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithPlatformKey' then 'alarm' - else 'ok' - end as status, - case - when encryption_type = 'EncryptionAtRestWithPlatformKey' then 'Disk is encrypted by CMK.' - else 'Disk is encrypted with Platform Key instead of CMK.' - end as reason, - disk.resource_group, - display_name as subscription - from - azure_compute_disk as disk - left join azure_subscription as sub on sub.subscription_id = disk.subscription_id - left join azure_compute_virtual_machine as vm on vm.os_disk_name = disk.name - where - vm.id is not null - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id, + disk.og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithPlatformKey' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithPlatformKey' THEN 'Disk is encrypted by CMK.' + ELSE 'Disk is encrypted with Platform Key instead of CMK.' + END AS reason, + disk.resource_group, + display_name AS subscription + FROM + azure_compute_disk AS disk + LEFT JOIN azure_subscription AS sub ON sub.subscription_id = disk.subscription_id + LEFT JOIN azure_compute_virtual_machine AS vm ON vm.os_disk_name = disk.name + WHERE + vm.id IS NOT NULL Severity: high Tags: platform_score_cloud_service_name: @@ -40,5 +41,4 @@ Tags: - Azure Virtual Machines score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Server Side Encryption for Boot Disk using CMK \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_non_boot_disk_using_cmk.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_non_boot_disk_using_cmk.yaml index e66c8c450..591e5a8b6 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_non_boot_disk_using_cmk.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_non_boot_disk_using_cmk.yaml @@ -1,35 +1,36 @@ +Description: Ensure that Azure VM data disk volumes are encrypted at rest using customer-managed keys (CMKs). ID: azure_server_side_encryption_for_non_boot_disk_using_cmk -Title: "Server Side Encryption for Non-Boot Disk using CMK" -Description: "Ensure that Azure VM data disk volumes are encrypted at rest using customer-managed keys (CMKs)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: | - select - disk.id as resource, - disk.og_account_id, - disk.og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithPlatformKey' then 'alarm' - else 'ok' - end as status, - case - when encryption_type = 'EncryptionAtRestWithPlatformKey' then 'Disk is encrypted by CMK.' - else 'Disk is encrypted with Platform Key instead of CMK.' - end as reason, - disk.resource_group, - display_name as subscription - from - azure_compute_disk as disk - left join azure_subscription as sub on sub.subscription_id = disk.subscription_id - left join azure_compute_virtual_machine as vm on vm.data_disks::text like '%' || disk.id || '%' - where - vm.id is not null - PrimaryTable: azure_compute_disk ListOfTables: - azure_compute_disk - azure_compute_virtual_machine - azure_subscription Parameters: [] + PrimaryTable: azure_compute_disk + QueryToExecute: | + SELECT + disk.id AS resource, + disk.og_account_id, + disk.og_resource_id, + CASE + WHEN encryption_type = 'EncryptionAtRestWithPlatformKey' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithPlatformKey' THEN 'Disk is encrypted by CMK.' + ELSE 'Disk is encrypted with Platform Key instead of CMK.' + END AS reason, + disk.resource_group, + display_name AS subscription + FROM + azure_compute_disk AS disk + LEFT JOIN azure_subscription AS sub ON sub.subscription_id = disk.subscription_id + LEFT JOIN azure_compute_virtual_machine AS vm ON vm.data_disks::text LIKE '%' || disk.id || '%' + WHERE + vm.id IS NOT NULL Severity: high Tags: platform_score_cloud_service_name: @@ -40,5 +41,4 @@ Tags: - Azure Virtual Machines score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Server Side Encryption for Non-Boot Disk using CMK \ No newline at end of file diff --git a/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_unattached_disk_using_cmk.yaml b/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_unattached_disk_using_cmk.yaml index 4f2e97394..c6d12c7a4 100644 --- a/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_unattached_disk_using_cmk.yaml +++ b/compliance/controls/baseline/azure/virtual_machine/azure_server_side_encryption_for_unattached_disk_using_cmk.yaml @@ -1,34 +1,35 @@ +Description: Ensure that unattached managed disk volumes are encrypted at rest using customer-managed keys (CMKs). ID: azure_server_side_encryption_for_unattached_disk_using_cmk -Title: "Server Side Encryption for Unattached Disk using CMK" -Description: "Ensure that unattached managed disk volumes are encrypted at rest using customer-managed keys (CMKs)." +IntegrationType: + - azure_subscription Query: Engine: odysseus-v0.0.1 + ListOfTables: + - azure_compute_disk + - azure_subscription + Parameters: [] + PrimaryTable: azure_compute_disk QueryToExecute: | - select - disk.id as resource, + SELECT + disk.id AS resource, disk.og_account_id, disk.og_resource_id, - case - when encryption_type = 'EncryptionAtRestWithPlatformKey' then 'alarm' - else 'ok' - end as status, - case - when encryption_type = 'EncryptionAtRestWithPlatformKey' then 'Disk is encrypted by CMK.' - else 'Disk is encrypted with Platform Key instead of CMK.' - end as reason, + CASE + WHEN encryption_type = 'EncryptionAtRestWithPlatformKey' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption_type = 'EncryptionAtRestWithPlatformKey' THEN 'Disk is encrypted by CMK.' + ELSE 'Disk is encrypted with Platform Key instead of CMK.' + END AS reason, disk.resource_group, - display_name as subscription - from - azure_compute_disk as disk, - azure_subscription as sub - where + display_name AS subscription + FROM + azure_compute_disk AS disk, + azure_subscription AS sub + WHERE sub.subscription_id = disk.subscription_id - and disk_state = 'Unattached' - PrimaryTable: azure_compute_disk - ListOfTables: - - azure_compute_disk - - azure_subscription - Parameters: [] + AND disk_state = 'Unattached' Severity: high Tags: platform_score_cloud_service_name: @@ -39,5 +40,4 @@ Tags: - Azure Virtual Machines score_tags: - Insecure Keys -IntegrationType: - - azure_subscription +Title: Server Side Encryption for Unattached Disk using CMK \ No newline at end of file diff --git a/compliance/controls/baseline/shared/cost/kaytu_connection_mom_cost_growth.yaml b/compliance/controls/baseline/shared/cost/kaytu_connection_mom_cost_growth.yaml index 8801baaf8..e09db5548 100644 --- a/compliance/controls/baseline/shared/cost/kaytu_connection_mom_cost_growth.yaml +++ b/compliance/controls/baseline/shared/cost/kaytu_connection_mom_cost_growth.yaml @@ -1,10 +1,10 @@ +Description: MoM growth for a connection that has a cost more than a certain amount cannot grow more than a certain percentage ID: og_connection_mom_cost_growth -Title: "MoM growth for a connection that has a cost more than a certain amount cannot grow more than a certain percentage" -Description: "MoM growth for a connection that has a cost more than a certain amount cannot grow more than a certain percentage" +IntegrationType: + - aws_cloud_account + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: "with last30 as (\n SELECT connection_id, SUM(cost_value) as cost_value\n FROM platform_cost\n WHERE period_start::timestamp >= NOW() - interval '31 days' and period_end::timestamp <= NOW()\n GROUP BY connection_id\n),\nlast60to30 as (\n SELECT connection_id, SUM(cost_value) as cost_value\n FROM platform_cost\n WHERE period_start::timestamp >= NOW() - interval '62 days' and period_end::timestamp <= NOW() - interval '31 days'\n GROUP BY connection_id\n),\nlast_valid_60 as (\n SELECT \n l.connection_id as connection_id,\n l.cost_value as last30_cost_value,\n s.cost_value as last60to30_cost_value\n FROM last30 as l JOIN last60to30 as s on (l.connection_id = s.connection_id)\n WHERE l.cost_value > {{.kaytuConnectionMoMCostGrowthMinCost}}\n)\nSELECT \n case \n when aw.account_id IS NOT NULL then aw.account_id\n when az.subscription_id IS NOT NULL then az.subscription_id\n end as resource,\n case\n when aw.og_account_id IS NOT NULL then aw.og_account_id\n when az.og_account_id IS NOT NULL then az.og_account_id\n end as og_account_id,\n case\n when aw.og_resource_id IS NOT NULL then aw.og_resource_id\n when az.og_resource_id IS NOT NULL then az.og_resource_id\n end as og_resource_id,\n case\n when aw.account_id IS NOT NULL then 'aws_account'\n when az.subscription_id IS NOT NULL then 'azure_subscription'\n end as og_table_name, \n case \n when (l.last30_cost_value - l.last60to30_cost_value) / l.last30_cost_value > {{.kaytuConnectionMoMCostGrowthAllowedGrowth}} then 'alarm'\n else 'ok'\n end as status,\n case \n when aw.account_id IS NOT NULL AND (l.last30_cost_value - l.last60to30_cost_value) / l.last30_cost_value > {{.kaytuConnectionMoMCostGrowthAllowedGrowth}} then aw.account_id || ' cost grew from ' || l.last60to30_cost_value || ' to ' || l.last30_cost_value || ' which is more than allowed growth'\n when az.subscription_id IS NOT NULL AND (l.last30_cost_value - l.last60to30_cost_value) / l.last30_cost_value > {{.kaytuConnectionMoMCostGrowthAllowedGrowth}} then az.subscription_id || ' cost grew from ' || l.last60to30_cost_value || ' to ' || l.last30_cost_value || ' which is more than allowed growth'\n else 'Connection did not have more than allowed growth'\n end as reason\nFROM last_valid_60 as l \n left join aws_account as aw on aw.og_account_id = l.connection_id\n left join azure_subscription as az on az.og_account_id = l.connection_id\n" - PrimaryTable: "" ListOfTables: - aws_account - azure_subscription @@ -13,6 +13,69 @@ Query: Required: true - Key: kaytuConnectionMoMCostGrowthAllowedGrowth Required: true + PrimaryTable: "" + QueryToExecute: | + WITH last30 AS ( + SELECT + connection_id, + SUM(cost_value) AS cost_value + FROM platform_cost + WHERE period_start::timestamp >= NOW() - INTERVAL '31 days' + AND period_end::timestamp <= NOW() + GROUP BY connection_id + ), + last60to30 AS ( + SELECT + connection_id, + SUM(cost_value) AS cost_value + FROM platform_cost + WHERE period_start::timestamp >= NOW() - INTERVAL '62 days' + AND period_end::timestamp <= NOW() - INTERVAL '31 days' + GROUP BY connection_id + ), + last_valid_60 AS ( + SELECT + l.connection_id AS connection_id, + l.cost_value AS last30_cost_value, + s.cost_value AS last60to30_cost_value + FROM last30 AS l + JOIN last60to30 AS s ON (l.connection_id = s.connection_id) + WHERE l.cost_value > {{.kaytuConnectionMoMCostGrowthMinCost}} + ) + SELECT + CASE + WHEN aw.account_id IS NOT NULL THEN aw.account_id + WHEN az.subscription_id IS NOT NULL THEN az.subscription_id + END AS resource, + CASE + WHEN aw.og_account_id IS NOT NULL THEN aw.og_account_id + WHEN az.og_account_id IS NOT NULL THEN az.og_account_id + END AS og_account_id, + CASE + WHEN aw.og_resource_id IS NOT NULL THEN aw.og_resource_id + WHEN az.og_resource_id IS NOT NULL THEN az.og_resource_id + END AS og_resource_id, + CASE + WHEN aw.account_id IS NOT NULL THEN 'aws_account' + WHEN az.subscription_id IS NOT NULL THEN 'azure_subscription' + END AS og_table_name, + CASE + WHEN (l.last30_cost_value - l.last60to30_cost_value) / l.last30_cost_value > {{.kaytuConnectionMoMCostGrowthAllowedGrowth}} + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN aw.account_id IS NOT NULL + AND (l.last30_cost_value - l.last60to30_cost_value) / l.last30_cost_value > {{.kaytuConnectionMoMCostGrowthAllowedGrowth}} + THEN aw.account_id || ' cost grew from ' || l.last60to30_cost_value || ' to ' || l.last30_cost_value || ' which is more than allowed growth' + WHEN az.subscription_id IS NOT NULL + AND (l.last30_cost_value - l.last60to30_cost_value) / l.last30_cost_value > {{.kaytuConnectionMoMCostGrowthAllowedGrowth}} + THEN az.subscription_id || ' cost grew from ' || l.last60to30_cost_value || ' to ' || l.last30_cost_value || ' which is more than allowed growth' + ELSE 'Connection did not have more than allowed growth' + END AS reason + FROM last_valid_60 AS l + LEFT JOIN aws_account AS aw ON aw.og_account_id = l.connection_id + LEFT JOIN azure_subscription AS az ON az.og_account_id = l.connection_id Severity: high Tags: platform_score_cloud_service_name: @@ -23,6 +86,4 @@ Tags: - TODO score_tags: - TODO -IntegrationType: - - aws_cloud_account - - azure_subscription +Title: MoM growth for a connection that has a cost more than a certain amount cannot grow more than a certain percentage \ No newline at end of file diff --git a/compliance/controls/baseline/shared/cost/kaytu_mom_cost_growth_15.yaml b/compliance/controls/baseline/shared/cost/kaytu_mom_cost_growth_15.yaml index f5393e7b5..798c8a1fa 100644 --- a/compliance/controls/baseline/shared/cost/kaytu_mom_cost_growth_15.yaml +++ b/compliance/controls/baseline/shared/cost/kaytu_mom_cost_growth_15.yaml @@ -1,10 +1,10 @@ +Description: MoM growth for a service that is >$100 cannot grow more than 15% ID: og_mom_cost_growth_15 -Title: "MoM growth for a service that is >$100 cannot grow more than 15%" -Description: "MoM growth for a service that is >$100 cannot grow more than 15%" +IntegrationType: + - aws_cloud_account + - azure_subscription Query: Engine: odysseus-v0.0.1 - QueryToExecute: "with last30 as (\n SELECT connection_id, metric_id, metric_name, SUM(cost_value) as cost_value\n FROM platform_cost\n WHERE period_start::timestamp >= NOW() - interval '31 days' and period_end::timestamp <= NOW()\n GROUP BY connection_id, metric_id, metric_name\n),\nlast60to30 as (\n SELECT connection_id, metric_id, metric_name, SUM(cost_value) as cost_value\n FROM platform_cost\n WHERE period_start::timestamp >= NOW() - interval '62 days' and period_end::timestamp <= NOW() - interval '31 days'\n GROUP BY connection_id, metric_id, metric_name\n),\nlast_valid_60 as (\n SELECT \n l.connection_id as connection_id,\n l.metric_id as metric_id,\n l.metric_name as metric_name,\n l.cost_value as last30_cost_value,\n s.cost_value as last60to30_cost_value\n FROM last30 as l JOIN last60to30 as s on (l.connection_id = s.connection_id and l.metric_id = s.metric_id)\n WHERE l.cost_value > {{.kaytuMoMCostGrowthMinCost}}\n)\nSELECT \n case \n when aw.account_id IS NOT NULL then aw.account_id || ' - ' || l.metric_id\n when az.subscription_id IS NOT NULL then az.subscription_id || ' - ' || l.metric_id\n end as resource,\n case\n when aw.og_account_id IS NOT NULL then aw.og_account_id\n when az.og_account_id IS NOT NULL then az.og_account_id\n end as og_account_id,\n case\n when aw.og_resource_id IS NOT NULL then aw.og_resource_id\n when az.og_resource_id IS NOT NULL then az.og_resource_id\n end as og_resource_id,\n case\n when aw.account_id IS NOT NULL then 'aws_account'\n when az.subscription_id IS NOT NULL then 'azure_subscription'\n end as og_table_name, \n case \n when (l.last30_cost_value - l.last60to30_cost_value) / l.last30_cost_value > {{.kaytuMoMCostGrowthAllowedGrowth}} then 'alarm'\n else 'ok'\n end as status,\n case \n when (l.last30_cost_value - l.last60to30_cost_value) / l.last30_cost_value > {{.kaytuMoMCostGrowthAllowedGrowth}} then l.metric_name || ' cost grew from ' || l.last60to30_cost_value || ' to ' || l.last30_cost_value || ' which is more than allowed growth'\n else l.metric_name || ' did not have more than allowed growth'\n end as reason\nFROM last_valid_60 as l \n left join aws_account as aw on aw.og_account_id = l.connection_id\n left join azure_subscription as az on az.og_account_id = l.connection_id\n" - PrimaryTable: "" ListOfTables: - aws_account - azure_subscription @@ -13,6 +13,64 @@ Query: Required: true - Key: kaytuMoMCostGrowthAllowedGrowth Required: true + PrimaryTable: "" + QueryToExecute: | + WITH last30 AS ( + SELECT connection_id, metric_id, metric_name, SUM(cost_value) AS cost_value + FROM platform_cost + WHERE period_start::timestamp >= NOW() - INTERVAL '31 days' + AND period_end::timestamp <= NOW() + GROUP BY connection_id, metric_id, metric_name + ), + last60to30 AS ( + SELECT connection_id, metric_id, metric_name, SUM(cost_value) AS cost_value + FROM platform_cost + WHERE period_start::timestamp >= NOW() - INTERVAL '62 days' + AND period_end::timestamp <= NOW() - INTERVAL '31 days' + GROUP BY connection_id, metric_id, metric_name + ), + last_valid_60 AS ( + SELECT + l.connection_id AS connection_id, + l.metric_id AS metric_id, + l.metric_name AS metric_name, + l.cost_value AS last30_cost_value, + s.cost_value AS last60to30_cost_value + FROM last30 AS l + JOIN last60to30 AS s + ON (l.connection_id = s.connection_id AND l.metric_id = s.metric_id) + WHERE l.cost_value > {{.kaytuMoMCostGrowthMinCost}} + ) + SELECT + CASE + WHEN aw.account_id IS NOT NULL THEN aw.account_id || ' - ' || l.metric_id + WHEN az.subscription_id IS NOT NULL THEN az.subscription_id || ' - ' || l.metric_id + END AS resource, + CASE + WHEN aw.og_account_id IS NOT NULL THEN aw.og_account_id + WHEN az.og_account_id IS NOT NULL THEN az.og_account_id + END AS og_account_id, + CASE + WHEN aw.og_resource_id IS NOT NULL THEN aw.og_resource_id + WHEN az.og_resource_id IS NOT NULL THEN az.og_resource_id + END AS og_resource_id, + CASE + WHEN aw.account_id IS NOT NULL THEN 'aws_account' + WHEN az.subscription_id IS NOT NULL THEN 'azure_subscription' + END AS og_table_name, + CASE + WHEN (l.last30_cost_value - l.last60to30_cost_value) / l.last30_cost_value > {{.kaytuMoMCostGrowthAllowedGrowth}} + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (l.last30_cost_value - l.last60to30_cost_value) / l.last30_cost_value > {{.kaytuMoMCostGrowthAllowedGrowth}} + THEN l.metric_name || ' cost grew from ' || l.last60to30_cost_value || ' to ' || l.last30_cost_value || ' which is more than allowed growth' + ELSE l.metric_name || ' did not have more than allowed growth' + END AS reason + FROM last_valid_60 AS l + LEFT JOIN aws_account AS aw ON aw.og_account_id = l.connection_id + LEFT JOIN azure_subscription AS az ON az.og_account_id = l.connection_id Severity: high Tags: platform_score_cloud_service_name: @@ -23,6 +81,4 @@ Tags: - TODO score_tags: - TODO -IntegrationType: - - aws_cloud_account - - azure_subscription +Title: MoM growth for a service that is >$100 cannot grow more than 15% \ No newline at end of file diff --git a/compliance/controls/bulk_update_yaml.sh b/compliance/controls/bulk_update_yaml.sh deleted file mode 100755 index 559334636..000000000 --- a/compliance/controls/bulk_update_yaml.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash - -# Description: -# This script traverses all subdirectories to find YAML files containing the 'Connector' key -# and renames the key to 'IntegrationType' while mapping specific values. - -# Define the root directory (current directory) -ROOT_DIR="." - -# Create or clear the log files -> processed_files.log -> error_files.log -> error_messages.log - -# Find all .yaml and .yml files -find "$ROOT_DIR" -type f \( -iname "*.yaml" -o -iname "*.yml" \) -print0 | while IFS= read -r -d '' file; do - # Check if the file contains the 'Connector:' key - if grep -q '^Connector:' "$file"; then - echo "Processing: $file" - - # Apply the yq transformation with enhanced handling - if yq eval -i ' - .IntegrationType = ( - if type == "array" then - .Connector | map( - { - "aws": "aws_cloud_account", - "azure": "azure_subscription" - }[.] // . - ) - else - { - "aws": "aws_cloud_account", - "azure": "azure_subscription" - }[.] // . - end - ) | - del(.Connector) - ' "$file"; then - echo "$file processed successfully." >> processed_files.log - else - echo "Error processing $file" >> error_files.log - # Capture detailed error messages - yq eval -i ' - .IntegrationType = ( - if type == "array" then - .Connector | map( - { - "aws": "aws_cloud_account", - "azure": "azure_subscription" - }[.] // . - ) - else - { - "aws": "aws_cloud_account", - "azure": "azure_subscription" - }[.] // . - end - ) | - del(.Connector) - ' "$file" 2>> error_messages.log - fi - fi -done - -echo "Bulk update completed. Check 'processed_files.log' for details." -echo "Any errors are logged in 'error_files.log' and 'error_messages.log'." diff --git a/compliance/controls/error_files.log b/compliance/controls/error_files.log deleted file mode 100644 index e69de29bb..000000000 diff --git a/compliance/controls/error_messages.log b/compliance/controls/error_messages.log deleted file mode 100644 index e69de29bb..000000000 diff --git a/compliance/controls/pending/aws/aws_backup_report_plan_configured.yaml b/compliance/controls/pending/aws/aws_backup_report_plan_configured.yaml old mode 100755 new mode 100644 index 97ca4ac27..ae4e6488a --- a/compliance/controls/pending/aws/aws_backup_report_plan_configured.yaml +++ b/compliance/controls/pending/aws/aws_backup_report_plan_configured.yaml @@ -1,13 +1,48 @@ +Description: Ensure that there is a minimum of one backup report plan in each region. The rule will be considered non-compliant if a region with backup plans does not have any backup report plans. ID: aws_backup_report_plan_configured -Title: "Backup report plan should exist in a region where backup plan is enabled" -Description: "Ensure that there is a minimum of one backup report plan in each region. The rule will be considered non-compliant if a region with backup plans does not have any backup report plans." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with backup_plan_configured_regions as (\n select\n distinct region,\n account_id\n from\n aws_backup_plan\n group by\n region,\n account_id\n), backup_report_plan_configured as (\n select\n distinct region,\n account_id\n from\n aws_backup_report_plan\n group by\n region,\n account_id\n)\nselect\n 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource,\n case\n when cp.region is not null and rp.region is not null then 'ok'\n when cp.region is not null and rp.region is null then 'alarm'\n else 'info'\n end as status,\n case\n when cp.region is not null and rp.region is not null then 'Backup report plan(s) exist in region ' || r.region || '.'\n when cp.region is not null and rp.region is null then 'No backup report plan(s) exist in region ' || r.region || '.'\n else 'No backup plan(s) configured in region ' || r.region || '.'\n end as reason\n \nfrom\n aws_region as r\n left join backup_plan_configured_regions as cp on r.account_id = cp.account_id and r.region = cp.region\n left join backup_report_plan_configured as rp on r.account_id = rp.account_id and r.region = rp.region;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH backup_plan_configured_regions AS ( + SELECT + DISTINCT region, + account_id + FROM + aws_backup_plan + GROUP BY + region, + account_id + ), backup_report_plan_configured AS ( + SELECT + DISTINCT region, + account_id + FROM + aws_backup_report_plan + GROUP BY + region, + account_id + ) + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + CASE + WHEN cp.region IS NOT NULL AND rp.region IS NOT NULL THEN 'ok' + WHEN cp.region IS NOT NULL AND rp.region IS NULL THEN 'alarm' + ELSE 'info' + END AS status, + CASE + WHEN cp.region IS NOT NULL AND rp.region IS NOT NULL THEN 'Backup report plan(s) exist in region ' || r.region || '.' + WHEN cp.region IS NOT NULL AND rp.region IS NULL THEN 'No backup report plan(s) exist in region ' || r.region || '.' + ELSE 'No backup plan(s) configured in region ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN backup_plan_configured_regions AS cp ON r.account_id = cp.account_id AND r.region = cp.region + LEFT JOIN backup_report_plan_configured AS rp ON r.account_id = rp.account_id AND r.region = rp.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Backup report plan should exist in a region where backup plan is enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_compute_service_v100_2_7.yaml b/compliance/controls/pending/aws/aws_cis_compute_service_v100_2_7.yaml old mode 100755 new mode 100644 index 506305948..0cf68021d --- a/compliance/controls/pending/aws/aws_cis_compute_service_v100_2_7.yaml +++ b/compliance/controls/pending/aws/aws_cis_compute_service_v100_2_7.yaml @@ -1,13 +1,32 @@ +Description: When an EC2 instance is launched a specified custom security group should be assigned to the instance. ID: aws_cis_compute_service_v100_2_7 -Title: "2.7 Ensure Default EC2 Security groups are not being used" -Description: "When an EC2 instance is launched a specified custom security group should be assigned to the instance." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn resource,\n case\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) = 0 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has inbound and outbound rules.'\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) = 0\n then 'Default security group ' || group_id || ' has inbound rules.'\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has outbound rules.'\n else 'Default security group ' || group_id || ' has no inbound or outbound rules.'\n end reason\n \n \nfrom\n aws_vpc_security_group\nwhere\n group_name = 'default';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has inbound and outbound rules.' + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) = 0 + THEN 'Default security group ' || group_id || ' has inbound rules.' + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has outbound rules.' + ELSE 'Default security group ' || group_id || ' has no inbound or outbound rules.' + END AS reason + FROM + aws_vpc_security_group + WHERE + group_name = 'default'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.7 Ensure Default EC2 Security groups are not being used \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_compute_service_v100_3_4.yaml b/compliance/controls/pending/aws/aws_cis_compute_service_v100_3_4.yaml old mode 100755 new mode 100644 index 2f8f97b44..7903da5b5 --- a/compliance/controls/pending/aws/aws_cis_compute_service_v100_3_4.yaml +++ b/compliance/controls/pending/aws/aws_cis_compute_service_v100_3_4.yaml @@ -1,55 +1,55 @@ +Description: Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should identify which IP address need access. ID: aws_cis_compute_service_v100_3_4 -Title: "3.4 Ensure SSH is restricted to only IP address that should have this access" -Description: "Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should identify which IP address need access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: [] + Parameters: [] + PrimaryTable: "" QueryToExecute: | - with open_ports as ( - select + WITH open_ports AS ( + SELECT name, - jsonb_array_elements(networking -> 'Ports') as port - from + JSONB_ARRAY_ELEMENTS(networking -> 'Ports') AS port + FROM aws_lightsail_instance ), - port_cidrs as ( - select + port_cidrs AS ( + SELECT op.name, - (op.port ->> 'FromPort')::int as from_port, - (op.port ->> 'ToPort')::int as to_port, - op.port ->> 'Protocol' as protocol, - jsonb_array_elements_text(op.port -> 'Cidrs') as cidr - from + (op.port ->> 'FromPort')::int AS from_port, + (op.port ->> 'ToPort')::int AS to_port, + op.port ->> 'Protocol' AS protocol, + JSONB_ARRAY_ELEMENTS_TEXT(op.port -> 'Cidrs') AS cidr + FROM open_ports op ), - unrestricted_ssh_ports as ( - select + unrestricted_ssh_ports AS ( + SELECT name - from + FROM port_cidrs - where + WHERE from_port = 22 - and to_port = 22 - and protocol = 'tcp' - and cidr = '0.0.0.0/0' + AND to_port = 22 + AND protocol = 'tcp' + AND cidr = '0.0.0.0/0' ) - select - i.name as resource, - case - when usp.name is null then 'ok' - else 'alarm' - end as status, - case - when usp.name is null then i.name || ' has SSH (22) restricted to specific IP addresses.' - else i.name || ' has SSH (22) open to the world (0.0.0.0/0).' - end as reason, + SELECT + i.name AS resource, + CASE + WHEN usp.name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN usp.name IS NULL THEN i.name || ' has SSH (22) restricted to specific IP addresses.' + ELSE i.name || ' has SSH (22) open to the world (0.0.0.0/0).' + END AS reason, i.tags - from + FROM aws_lightsail_instance i - left join unrestricted_ssh_ports usp on i.name = usp.name; - PrimaryTable: "" - ListOfTables: [] - Parameters: [] + LEFT JOIN unrestricted_ssh_ports usp ON i.name = usp.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.4 Ensure SSH is restricted to only IP address that should have this access \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_1_10.yaml b/compliance/controls/pending/aws/aws_cis_v120_1_10.yaml old mode 100755 new mode 100644 index a954e8ddc..ce22ab891 --- a/compliance/controls/pending/aws/aws_cis_v120_1_10.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_1_10.yaml @@ -1,13 +1,30 @@ +Description: IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords. ID: aws_cis_v120_1_10 -Title: "1.10 Ensure IAM password policy prevents password reuse" -Description: "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when password_reuse_prevention >= 24 then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n when password_reuse_prevention is null then 'Password reuse prevention not set.'\n else 'Password reuse prevention set to ' || password_reuse_prevention || '.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN password_reuse_prevention >= 24 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN password_reuse_prevention IS NULL THEN 'Password reuse prevention not set.' + ELSE 'Password reuse prevention set to ' || password_reuse_prevention || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON + a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.10 Ensure IAM password policy prevents password reuse \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_1_14.yaml b/compliance/controls/pending/aws/aws_cis_v120_1_14.yaml old mode 100755 new mode 100644 index 6fdc6d9e8..82752980a --- a/compliance/controls/pending/aws/aws_cis_v120_1_14.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_1_14.yaml @@ -1,13 +1,29 @@ +Description: The root account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root account be protected with a hardware MFA. ID: aws_cis_v120_1_14 -Title: "1.14 Ensure hardware MFA is enabled for the \\\"root\\\" account" -Description: "The root account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root account be protected with a hardware MFA." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || s.partition || ':::' || s.account_id as resource,\n case\n when s.account_mfa_enabled and d.serial_number is null then 'ok'\n else 'alarm'\n end status,\n case\n when s.account_mfa_enabled = false then 'MFA not enabled for root account.'\n when d.serial_number is not null then 'MFA enabled for root account, but the MFA associated is a virtual device.'\n else 'Hardware MFA device enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary as s\n left join aws_iam_virtual_mfa_device as d on (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || s.partition || ':::' || s.account_id AS resource, + CASE + WHEN s.account_mfa_enabled AND d.serial_number IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.account_mfa_enabled = FALSE THEN 'MFA not enabled for root account.' + WHEN d.serial_number IS NOT NULL THEN 'MFA enabled for root account, but the MFA associated is a virtual device.' + ELSE 'Hardware MFA device enabled for root account.' + END AS reason + FROM + aws_iam_account_summary AS s + LEFT JOIN + aws_iam_virtual_mfa_device AS d + ON (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.14 Ensure hardware MFA is enabled for the "root" account \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_1_5.yaml b/compliance/controls/pending/aws/aws_cis_v120_1_5.yaml old mode 100755 new mode 100644 index a65993d2d..e25c01586 --- a/compliance/controls/pending/aws/aws_cis_v120_1_5.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_1_5.yaml @@ -1,13 +1,29 @@ +Description: Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one uppercase letter. ID: aws_cis_v120_1_5 -Title: "1.5 Ensure IAM password policy requires at least one uppercase letter" -Description: "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one uppercase letter." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when require_uppercase_characters then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n when require_uppercase_characters then 'Uppercase character required.'\n else 'Uppercase character not required.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN require_uppercase_characters THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN require_uppercase_characters THEN 'Uppercase character required.' + ELSE 'Uppercase character not required.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.5 Ensure IAM password policy requires at least one uppercase letter \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_1_6.yaml b/compliance/controls/pending/aws/aws_cis_v120_1_6.yaml old mode 100755 new mode 100644 index 0e8eb9a6d..517a3eaf0 --- a/compliance/controls/pending/aws/aws_cis_v120_1_6.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_1_6.yaml @@ -1,13 +1,27 @@ +Description: Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one lowercase letter. ID: aws_cis_v120_1_6 -Title: "1.6 Ensure IAM password policy require at least one lowercase letter" -Description: "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one lowercase letter." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when require_lowercase_characters then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n when require_lowercase_characters then 'Lowercase character required.'\n else 'Lowercase character not required.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN require_lowercase_characters THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN require_lowercase_characters THEN 'Lowercase character required.' + ELSE 'Lowercase character not required.' + END AS reason + FROM + aws_account AS a + LEFT JOIN aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.6 Ensure IAM password policy require at least one lowercase letter \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_1_7.yaml b/compliance/controls/pending/aws/aws_cis_v120_1_7.yaml old mode 100755 new mode 100644 index c260cbef0..5eef1782a --- a/compliance/controls/pending/aws/aws_cis_v120_1_7.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_1_7.yaml @@ -1,13 +1,30 @@ +Description: Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure passwords are comprised of different character sets. It is recommended that the password policy require at least one symbol. ID: aws_cis_v120_1_7 -Title: "1.7 Ensure IAM password policy require at least one symbol" -Description: "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are comprised of different character sets. It is recommended that the password policy require at least one symbol." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when require_symbols then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n when require_symbols then 'Symbol required.'\n else 'Symbol not required.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN require_symbols THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN require_symbols THEN 'Symbol required.' + ELSE 'Symbol not required.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON + a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.7 Ensure IAM password policy requires at least one symbol \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_1_9.yaml b/compliance/controls/pending/aws/aws_cis_v120_1_9.yaml old mode 100755 new mode 100644 index 69973c784..4c123f9e6 --- a/compliance/controls/pending/aws/aws_cis_v120_1_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_1_9.yaml @@ -1,13 +1,27 @@ +Description: Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure passwords are at least a given length. It is recommended that the password policy require a minimum password length of 14. ID: aws_cis_v120_1_9 -Title: "1.9 Ensure IAM password policy requires minimum length of 14 or greater" -Description: "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when minimum_password_length >= 14 then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n else 'Minimum password length set to ' || minimum_password_length || '.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN minimum_password_length >= 14 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + ELSE 'Minimum password length set to ' || minimum_password_length || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.9 Ensure IAM password policy requires minimum length of 14 or greater \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_2_1.yaml b/compliance/controls/pending/aws/aws_cis_v120_2_1.yaml old mode 100755 new mode 100644 index 02cb21361..5d7d7c2fc --- a/compliance/controls/pending/aws/aws_cis_v120_2_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_2_1.yaml @@ -1,13 +1,50 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation). ID: aws_cis_v120_2_1 -Title: "2.1 Ensure CloudTrail is enabled in all regions" -Description: "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as e\n where\n (is_logging and is_multi_region_trail and e ->> 'ReadWriteType' = 'All')\n),\nadvanced_event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements_text(advanced_event_selectors) as a\n where\n -- when readOnly = true, then it is readOnly, when readOnly = false then it is writeOnly, if advanced_event_selectors is not null then it is both ReadWriteType\n (is_logging and is_multi_region_trail and advanced_event_selectors is not null and (not a like '%readOnly%'))\n)\nselect\n a.title as resource,\n case\n when d.account_id is null and ad.account_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when d.account_id is null and ad.account_id is null then 'cloudtrail disabled.'\n else 'cloudtrail enabled.'\n end as reason\n\n \nfrom\n aws_account as a\n left join event_selectors_trail_details as d on d.account_id = a.account_id\n left join advanced_event_selectors_trail_details as ad on ad.account_id = a.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH event_selectors_trail_details AS ( + SELECT DISTINCT + account_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS e + WHERE + is_logging + AND is_multi_region_trail + AND e ->> 'ReadWriteType' = 'All' + ), + advanced_event_selectors_trail_details AS ( + SELECT DISTINCT + account_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements_text(advanced_event_selectors) AS a + WHERE + is_logging + AND is_multi_region_trail + AND advanced_event_selectors IS NOT NULL + AND NOT a LIKE '%readOnly%' + ) + SELECT + a.title AS resource, + CASE + WHEN d.account_id IS NULL AND ad.account_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.account_id IS NULL AND ad.account_id IS NULL THEN 'cloudtrail disabled.' + ELSE 'cloudtrail enabled.' + END AS reason + FROM + aws_account AS a + LEFT JOIN event_selectors_trail_details AS d ON d.account_id = a.account_id + LEFT JOIN advanced_event_selectors_trail_details AS ad ON ad.account_id = a.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1 Ensure CloudTrail is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_3_1.yaml b/compliance/controls/pending/aws/aws_cis_v120_3_1.yaml old mode 100755 new mode 100644 index 91ba71b57..7eee7c27d --- a/compliance/controls/pending/aws/aws_cis_v120_3_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_3_1.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls. ID: aws_cis_v120_3_1 -Title: "3.1 Ensure a log metric filter and alarm exist for unauthorized API calls" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\$\\.errorCode\\s*=\\s*\"\\*UnauthorizedOperation\".+\\$\\.errorCode\\s*=\\s*\"AccessDenied\\*\".+\\$\\.sourceIPAddress\\s*!=\\s*\"delivery.logs.amazonaws.com\".+\\$\\.eventName\\s*!=\\s*\"HeadBucket\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for unauthorized API calls.'\n else filter_name || ' forwards events for unauthorized API calls.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\$.errorCode\s*=\s*"*UnauthorizedOperation".+\$.errorCode\s*=\s*"AccessDenied*".+\$.sourceIPAddress\s*!=\s*"delivery.logs.amazonaws.com".+\$.eventName\s*!=\s*"HeadBucket"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for unauthorized API calls.' + ELSE filter_name || ' forwards events for unauthorized API calls.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.1 Ensure a log metric filter and alarm exist for unauthorized API calls \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_3_10.yaml b/compliance/controls/pending/aws/aws_cis_v120_3_10.yaml old mode 100755 new mode 100644 index 313c512ad..2b291def3 --- a/compliance/controls/pending/aws/aws_cis_v120_3_10.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_3_10.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for changes to Security Groups. ID: aws_cis_v120_3_10 -Title: "3.10 Ensure a log metric filter and alarm exist for security group changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established changes to Security Groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*AuthorizeSecurityGroupIngress.+\\$\\.eventName\\s*=\\s*AuthorizeSecurityGroupEgress.+\\$\\.eventName\\s*=\\s*RevokeSecurityGroupIngress.+\\$\\.eventName\\s*=\\s*RevokeSecurityGroupEgress.+\\$\\.eventName\\s*=\\s*CreateSecurityGroup.+\\$\\.eventName\\s*=\\s*DeleteSecurityGroup'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for security group changes.'\n else filter_name || ' forwards events for security group changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*RevokeSecurityGroupIngress.+\$\.eventName\s*=\s*RevokeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for security group changes.' + ELSE filter_name || ' forwards events for security group changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.10 Ensure a log metric filter and alarm exist for security group changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_3_2.yaml b/compliance/controls/pending/aws/aws_cis_v120_3_2.yaml old mode 100755 new mode 100644 index d4c0d237e..aead5bea6 --- a/compliance/controls/pending/aws/aws_cis_v120_3_2.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_3_2.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA). ID: aws_cis_v120_3_2 -Title: "3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\(\\s*\\$\\.eventName\\s*=\\s*\"ConsoleLogin\"\\)\\s+&&\\s+\\(\\s*\\$.additionalEventData\\.MFAUsed\\s*!=\\s*\"Yes\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console sign-in without MFA.'\n else filter_name || ' forwards events for console sign-in without MFA.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\(\s*\$\.eventName\s*=\s*"ConsoleLogin"\)\s+&&\s+\(\s*\$.additionalEventData\.MFAUsed\s*!=\s*"Yes"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console sign-in without MFA.' + ELSE filter_name || ' forwards events for console sign-in without MFA.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_3_3.yaml b/compliance/controls/pending/aws/aws_cis_v120_3_3.yaml old mode 100755 new mode 100644 index 26979f9cb..7691730ce --- a/compliance/controls/pending/aws/aws_cis_v120_3_3.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_3_3.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for root login attempts. ID: aws_cis_v120_3_3 -Title: "3.3 Ensure a log metric filter and alarm exist for usage of \\\"root\\\" account" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for root login attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.userIdentity\\.type\\s*=\\s*\"Root\".+\\$\\.userIdentity\\.invokedBy NOT EXISTS.+\\$\\.eventType\\s*!=\\s*\"AwsServiceEvent\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for usage of \"root\" account.'\n else filter_name || ' forwards events for usage of \"root\" account.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.userIdentity.type\s*=\s*"Root".+\$.userIdentity.invokedBy NOT EXISTS.+\$.eventType\s*!=\s*"AwsServiceEvent"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for usage of "root" account.' + ELSE filter_name || ' forwards events for usage of "root" account.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.3 Ensure a log metric filter and alarm exist for usage of "root" account \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_3_4.yaml b/compliance/controls/pending/aws/aws_cis_v120_3_4.yaml old mode 100755 new mode 100644 index 75b285fff..857121aa5 --- a/compliance/controls/pending/aws/aws_cis_v120_3_4.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_3_4.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes made to Identity and Access Management (IAM) policies. ID: aws_cis_v120_3_4 -Title: "3.4 Ensure a log metric filter and alarm exist for IAM policy changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*DeleteGroupPolicy.+\\$\\.eventName\\s*=\\s*DeleteRolePolicy.+\\$\\.eventName\\s*=\\s*DeleteUserPolicy.+\\$\\.eventName\\s*=\\s*PutGroupPolicy.+\\$\\.eventName\\s*=\\s*PutRolePolicy.+\\$\\.eventName\\s*=\\s*PutUserPolicy.+\\$\\.eventName\\s*=\\s*CreatePolicy.+\\$\\.eventName\\s*=\\s*DeletePolicy.+\\$\\.eventName\\s*=\\s*CreatePolicyVersion.+\\$\\.eventName\\s*=\\s*DeletePolicyVersion.+\\$\\.eventName\\s*=\\s*AttachRolePolicy.+\\$\\.eventName\\s*=\\s*DetachRolePolicy.+\\$\\.eventName\\s*=\\s*AttachUserPolicy.+\\$\\.eventName\\s*=\\s*DetachUserPolicy.+\\$\\.eventName\\s*=\\s*AttachGroupPolicy.+\\$\\.eventName\\s*=\\s*DetachGroupPolicy'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for IAM policy changes.'\n else filter_name || ' forwards events for IAM policy changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*DeleteGroupPolicy.+\$.eventName\s*=\s*DeleteRolePolicy.+\$.eventName\s*=\s*DeleteUserPolicy.+\$.eventName\s*=\s*PutGroupPolicy.+\$.eventName\s*=\s*PutRolePolicy.+\$.eventName\s*=\s*PutUserPolicy.+\$.eventName\s*=\s*CreatePolicy.+\$.eventName\s*=\s*DeletePolicy.+\$.eventName\s*=\s*CreatePolicyVersion.+\$.eventName\s*=\s*DeletePolicyVersion.+\$.eventName\s*=\s*AttachRolePolicy.+\$.eventName\s*=\s*DetachRolePolicy.+\$.eventName\s*=\s*AttachUserPolicy.+\$.eventName\s*=\s*DetachUserPolicy.+\$.eventName\s*=\s*AttachGroupPolicy.+\$.eventName\s*=\s*DetachGroupPolicy' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for IAM policy changes.' + ELSE filter_name || ' forwards events for IAM policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.4 Ensure a log metric filter and alarm exist for IAM policy changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_3_6.yaml b/compliance/controls/pending/aws/aws_cis_v120_3_6.yaml old mode 100755 new mode 100644 index 6dc6f4613..ad19393b9 --- a/compliance/controls/pending/aws/aws_cis_v120_3_6.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_3_6.yaml @@ -1,13 +1,90 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts. ID: aws_cis_v120_3_6 -Title: "3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*ConsoleLogin.+\\$\\.errorMessage\\s*=\\s*\"Failed authentication\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console authentication failures.'\n else f.filter_name || ' forwards events for console authentication failures.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*ConsoleLogin.+\$\..errorMessage\s*=\s*"Failed authentication"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console authentication failures.' + ELSE f.filter_name || ' forwards events for console authentication failures.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_3_7.yaml b/compliance/controls/pending/aws/aws_cis_v120_3_7.yaml old mode 100755 new mode 100644 index 91a0d0174..f84a76700 --- a/compliance/controls/pending/aws/aws_cis_v120_3_7.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_3_7.yaml @@ -1,13 +1,90 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion. ID: aws_cis_v120_3_7 -Title: "3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*kms.amazonaws.com.+\\$\\.eventName\\s*=\\s*DisableKey.+\\$\\.eventName\\s*=\\s*ScheduleKeyDeletion'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for disabling/deletion of CMKs.'\n else filter_name || ' forwards events for disabling/deletion of CMKs.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*kms.amazonaws.com.+\$\.eventName\s*=\s*DisableKey.+\$\.eventName\s*=\s*ScheduleKeyDeletion' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for disabling/deletion of CMKs.' + ELSE filter_name || ' forwards events for disabling/deletion of CMKs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_3_8.yaml b/compliance/controls/pending/aws/aws_cis_v120_3_8.yaml old mode 100755 new mode 100644 index 9a41a4a59..c47cc62c8 --- a/compliance/controls/pending/aws/aws_cis_v120_3_8.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_3_8.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies. ID: aws_cis_v120_3_8 -Title: "3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*s3.amazonaws.com.+\\$\\.eventName\\s*=\\s*PutBucketAcl.+\\$\\.eventName\\s*=\\s*PutBucketPolicy.+\\$\\.eventName\\s*=\\s*PutBucketCors.+\\$\\.eventName\\s*=\\s*PutBucketLifecycle.+\\$\\.eventName\\s*=\\s*PutBucketReplication.+\\$\\.eventName\\s*=\\s*DeleteBucketPolicy.+\\$\\.eventName\\s*=\\s*DeleteBucketCors.+\\$\\.eventName\\s*=\\s*DeleteBucketLifecycle.+\\$\\.eventName\\s*=\\s*DeleteBucketReplication'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for S3 bucket policy changes.'\n else filter_name || ' forwards events for S3 bucket policy changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*s3.amazonaws.com.+\$.eventName\s*=\s*PutBucketAcl.+\$.eventName\s*=\s*PutBucketPolicy.+\$.eventName\s*=\s*PutBucketCors.+\$.eventName\s*=\s*PutBucketLifecycle.+\$.eventName\s*=\s*PutBucketReplication.+\$.eventName\s*=\s*DeleteBucketPolicy.+\$.eventName\s*=\s*DeleteBucketCors.+\$.eventName\s*=\s*DeleteBucketLifecycle.+\$.eventName\s*=\s*DeleteBucketReplication' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for S3 bucket policy changes.' + ELSE filter_name || ' forwards events for S3 bucket policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_3_9.yaml b/compliance/controls/pending/aws/aws_cis_v120_3_9.yaml old mode 100755 new mode 100644 index e8f65afb2..34daf0b6e --- a/compliance/controls/pending/aws/aws_cis_v120_3_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_3_9.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations. ID: aws_cis_v120_3_9 -Title: "3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*config.amazonaws.com.+\\$\\.eventName\\s*=\\s*StopConfigurationRecorder.+\\$\\.eventName\\s*=\\s*DeleteDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutConfigurationRecorder'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for AWS Config configuration changes.'\n else filter_name || ' forwards events for AWS Config configuration changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*config.amazonaws.com.+\$\.eventName\s*=\s*StopConfigurationRecorder.+\$\.eventName\s*=\s*DeleteDeliveryChannel.+\$\.eventName\s*=\s*PutDeliveryChannel.+\$\.eventName\s*=\s*PutConfigurationRecorder' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for AWS Config configuration changes.' + ELSE filter_name || ' forwards events for AWS Config configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v120_4_3.yaml b/compliance/controls/pending/aws/aws_cis_v120_4_3.yaml old mode 100755 new mode 100644 index 2d3453cb0..8582901dc --- a/compliance/controls/pending/aws/aws_cis_v120_4_3.yaml +++ b/compliance/controls/pending/aws/aws_cis_v120_4_3.yaml @@ -1,13 +1,29 @@ +Description: A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. The default VPC in every region should have its default security group updated to comply. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation. ID: aws_cis_v120_4_3 -Title: "4.3 Ensure the default security group of every VPC restricts all traffic" -Description: "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. The default VPC in every region should have its default security group updated to comply. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn resource,\n case\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) = 0 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has inbound and outbound rules.'\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) = 0\n then 'Default security group ' || group_id || ' has inbound rules.'\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has outbound rules.'\n else 'Default security group ' || group_id || ' has no inbound or outbound rules.'\n end reason\n \n \nfrom\n aws_vpc_security_group\nwhere\n group_name = 'default';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) > 0 THEN 'Default security group ' || group_id || ' has inbound and outbound rules.' + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'Default security group ' || group_id || ' has inbound rules.' + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) > 0 THEN 'Default security group ' || group_id || ' has outbound rules.' + ELSE 'Default security group ' || group_id || ' has no inbound or outbound rules.' + END AS reason + FROM + aws_vpc_security_group + WHERE + group_name = 'default'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.3 Ensure the default security group of every VPC restricts all traffic \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_1_6.yaml b/compliance/controls/pending/aws/aws_cis_v130_1_6.yaml old mode 100755 new mode 100644 index ea4a459fa..c2ed8479f --- a/compliance/controls/pending/aws/aws_cis_v130_1_6.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_1_6.yaml @@ -1,13 +1,30 @@ +Description: The root user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root user account be protected with a hardware MFA. ID: aws_cis_v130_1_6 -Title: "1.6 Ensure hardware MFA is enabled for the \\\"root user\\\" account" -Description: "The root user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root user account be protected with a hardware MFA." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || s.partition || ':::' || s.account_id as resource,\n case\n when s.account_mfa_enabled and d.serial_number is null then 'ok'\n else 'alarm'\n end status,\n case\n when s.account_mfa_enabled = false then 'MFA not enabled for root account.'\n when d.serial_number is not null then 'MFA enabled for root account, but the MFA associated is a virtual device.'\n else 'Hardware MFA device enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary as s\n left join aws_iam_virtual_mfa_device as d on (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || s.partition || ':::' || s.account_id AS resource, + CASE + WHEN s.account_mfa_enabled AND d.serial_number IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN s.account_mfa_enabled = FALSE THEN 'MFA not enabled for root account.' + WHEN d.serial_number IS NOT NULL THEN 'MFA enabled for root account, but the MFA associated is a virtual device.' + ELSE 'Hardware MFA device enabled for root account.' + END reason + FROM + aws_iam_account_summary AS s + LEFT JOIN + aws_iam_virtual_mfa_device AS d + ON + (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.6 Ensure hardware MFA is enabled for the "root user" account \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_1_9.yaml b/compliance/controls/pending/aws/aws_cis_v130_1_9.yaml old mode 100755 new mode 100644 index 8b7762dcb..ed2355d2c --- a/compliance/controls/pending/aws/aws_cis_v130_1_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_1_9.yaml @@ -1,13 +1,29 @@ +Description: IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords. ID: aws_cis_v130_1_9 -Title: "1.9 Ensure IAM password policy prevents password reuse" -Description: "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when password_reuse_prevention >= 24 then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n when password_reuse_prevention is null then 'Password reuse prevention not set.'\n else 'Password reuse prevention set to ' || password_reuse_prevention || '.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN password_reuse_prevention >= 24 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN password_reuse_prevention IS NULL THEN 'Password reuse prevention not set.' + ELSE 'Password reuse prevention set to ' || password_reuse_prevention || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.9 Ensure IAM password policy prevents password reuse \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_3_1.yaml b/compliance/controls/pending/aws/aws_cis_v130_3_1.yaml old mode 100755 new mode 100644 index 6dedaf70c..b72cb15d6 --- a/compliance/controls/pending/aws/aws_cis_v130_3_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_3_1.yaml @@ -1,13 +1,52 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation). ID: aws_cis_v130_3_1 -Title: "3.1 Ensure CloudTrail is enabled in all regions" -Description: "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as e\n where\n (is_logging and is_multi_region_trail and e ->> 'ReadWriteType' = 'All')\n),\nadvanced_event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements_text(advanced_event_selectors) as a\n where\n -- when readOnly = true, then it is readOnly, when readOnly = false then it is writeOnly, if advanced_event_selectors is not null then it is both ReadWriteType\n (is_logging and is_multi_region_trail and advanced_event_selectors is not null and (not a like '%readOnly%'))\n)\nselect\n a.title as resource,\n case\n when d.account_id is null and ad.account_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when d.account_id is null and ad.account_id is null then 'cloudtrail disabled.'\n else 'cloudtrail enabled.'\n end as reason\n\n \nfrom\n aws_account as a\n left join event_selectors_trail_details as d on d.account_id = a.account_id\n left join advanced_event_selectors_trail_details as ad on ad.account_id = a.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH event_selectors_trail_details AS ( + SELECT + DISTINCT account_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS e + WHERE + is_logging + AND is_multi_region_trail + AND e ->> 'ReadWriteType' = 'All' + ), + advanced_event_selectors_trail_details AS ( + SELECT + DISTINCT account_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements_text(advanced_event_selectors) AS a + WHERE + is_logging + AND is_multi_region_trail + AND advanced_event_selectors IS NOT NULL + AND (NOT a LIKE '%readOnly%') + ) + SELECT + a.title AS resource, + CASE + WHEN d.account_id IS NULL + AND ad.account_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.account_id IS NULL + AND ad.account_id IS NULL THEN 'cloudtrail disabled.' + ELSE 'cloudtrail enabled.' + END AS reason + FROM + aws_account AS a + LEFT JOIN event_selectors_trail_details AS d ON d.account_id = a.account_id + LEFT JOIN advanced_event_selectors_trail_details AS ad ON ad.account_id = a.account_id Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.1 Ensure CloudTrail is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_3_9.yaml b/compliance/controls/pending/aws/aws_cis_v130_3_9.yaml old mode 100755 new mode 100644 index 42df9197f..c297e647c --- a/compliance/controls/pending/aws/aws_cis_v130_3_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_3_9.yaml @@ -1,13 +1,52 @@ +Description: VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet "Rejects" for VPCs. ID: aws_cis_v130_3_9 -Title: "3.9 Ensure VPC flow logging is enabled in all VPCs" -Description: "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \\\"Rejects\\\" for VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vpcs as (\n select\n arn,\n account_id,\n region,\n owner_id,\n vpc_id,\n tags,\n _ctx\n from\n aws_vpc\n order by\n vpc_id\n),\nflowlogs as (\n select\n resource_id,\n account_id,\n region\n from\n aws_vpc_flow_log\n order by\n resource_id\n)\nselect\n v.arn as resource,\n case\n when v.account_id <> v.owner_id then 'skip'\n when f.resource_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when v.account_id <> v.owner_id then v.vpc_id || ' is a shared VPC.'\n when f.resource_id is not null then v.vpc_id || ' flow logging enabled.'\n else v.vpc_id || ' flow logging disabled.'\n end as reason\n \n \nfrom\n vpcs as v\n left join flowlogs as f on v.vpc_id = f.resource_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH vpcs AS ( + SELECT + arn, + account_id, + region, + owner_id, + vpc_id, + tags, + _ctx + FROM + aws_vpc + ORDER BY + vpc_id + ), + flowlogs AS ( + SELECT + resource_id, + account_id, + region + FROM + aws_vpc_flow_log + ORDER BY + resource_id + ) + SELECT + v.arn AS resource, + CASE + WHEN v.account_id <> v.owner_id THEN 'skip' + WHEN f.resource_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.account_id <> v.owner_id THEN v.vpc_id || ' is a shared VPC.' + WHEN f.resource_id IS NOT NULL THEN v.vpc_id || ' flow logging enabled.' + ELSE v.vpc_id || ' flow logging disabled.' + END AS reason + FROM + vpcs AS v + LEFT JOIN flowlogs AS f ON v.vpc_id = f.resource_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.9 Ensure VPC flow logging is enabled in all VPCs \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_1.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_1.yaml old mode 100755 new mode 100644 index df709acab..e2f03adb8 --- a/compliance/controls/pending/aws/aws_cis_v130_4_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_1.yaml @@ -1,13 +1,90 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls. ID: aws_cis_v130_4_1 -Title: "4.1 Ensure a log metric filter and alarm exist for unauthorized API calls" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\$\\.errorCode\\s*=\\s*\"\\*UnauthorizedOperation\".+\\$\\.errorCode\\s*=\\s*\"AccessDenied\\*\".+\\$\\.sourceIPAddress\\s*!=\\s*\"delivery.logs.amazonaws.com\".+\\$\\.eventName\\s*!=\\s*\"HeadBucket\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for unauthorized API calls.'\n else filter_name || ' forwards events for unauthorized API calls.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '$.errorCode\s*=\s*"*UnauthorizedOperation".+$.errorCode\s*=\s*"AccessDenied*".+$.sourceIPAddress\s*!=\s*"delivery.logs.amazonaws.com".+$.eventName\s*!=\s*"HeadBucket"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for unauthorized API calls.' + ELSE filter_name || ' forwards events for unauthorized API calls.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.1 Ensure a log metric filter and alarm exist for unauthorized API calls \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_10.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_10.yaml old mode 100755 new mode 100644 index 62564ee42..c942683b7 --- a/compliance/controls/pending/aws/aws_cis_v130_4_10.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_10.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups. ID: aws_cis_v130_4_10 -Title: "4.10 Ensure a log metric filter and alarm exist for security group changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*AuthorizeSecurityGroupIngress.+\\$\\.eventName\\s*=\\s*AuthorizeSecurityGroupEgress.+\\$\\.eventName\\s*=\\s*RevokeSecurityGroupIngress.+\\$\\.eventName\\s*=\\s*RevokeSecurityGroupEgress.+\\$\\.eventName\\s*=\\s*CreateSecurityGroup.+\\$\\.eventName\\s*=\\s*DeleteSecurityGroup'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for security group changes.'\n else filter_name || ' forwards events for security group changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$.eventName\s*=\s*RevokeSecurityGroupIngress.+\$.eventName\s*=\s*RevokeSecurityGroupEgress.+\$.eventName\s*=\s*CreateSecurityGroup.+\$.eventName\s*=\s*DeleteSecurityGroup' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for security group changes.' + ELSE filter_name || ' forwards events for security group changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.10 Ensure a log metric filter and alarm exist for security group changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_11.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_11.yaml old mode 100755 new mode 100644 index c443ff863..30a116cdf --- a/compliance/controls/pending/aws/aws_cis_v130_4_11.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_11.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs. ID: aws_cis_v130_4_11 -Title: "4.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL)" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateNetworkAcl.+\\$\\.eventName\\s*=\\s*CreateNetworkAclEntry.+\\$\\.eventName\\s*=\\s*DeleteNetworkAcl.+\\$\\.eventName\\s*=\\s*DeleteNetworkAclEntry.+\\$\\.eventName\\s*=\\s*ReplaceNetworkAclEntry.+\\$\\.eventName\\s*=\\s*ReplaceNetworkAclAssociation'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for changes to NACLs.'\n else filter_name || ' forwards events for changes to NACLs.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateNetworkAcl.+\$.eventName\s*=\s*CreateNetworkAclEntry.+\$.eventName\s*=\s*DeleteNetworkAcl.+\$.eventName\s*=\s*DeleteNetworkAclEntry.+\$.eventName\s*=\s*ReplaceNetworkAclEntry.+\$.eventName\s*=\s*ReplaceNetworkAclAssociation' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to NACLs.' + ELSE filter_name || ' forwards events for changes to NACLs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_12.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_12.yaml old mode 100755 new mode 100644 index 7a27554d2..3a0d80c89 --- a/compliance/controls/pending/aws/aws_cis_v130_4_12.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_12.yaml @@ -1,13 +1,95 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways. ID: aws_cis_v130_4_12 -Title: "4.12 Ensure a log metric filter and alarm exist for changes to network gateways" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateCustomerGateway.+\\$\\.eventName\\s*=\\s*DeleteCustomerGateway.+\\$\\.eventName\\s*=\\s*AttachInternetGateway.+\\$\\.eventName\\s*=\\s*CreateInternetGateway.+\\$\\.eventName\\s*=\\s*DeleteInternetGateway.+\\$\\.eventName\\s*=\\s*DetachInternetGateway'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for changes to network gateways.'\n else filter_name || ' forwards events for changes to network gateways.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ ' + \s*\$\.eventName\s*=\s*CreateCustomerGateway + .+\$\.eventName\s*=\s*DeleteCustomerGateway + .+\$\.eventName\s*=\s*AttachInternetGateway + .+\$\.eventName\s*=\s*CreateInternetGateway + .+\$\.eventName\s*=\s*DeleteInternetGateway + .+\$\.eventName\s*=\s*DetachInternetGateway' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to network gateways.' + ELSE filter_name || ' forwards events for changes to network gateways.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.12 Ensure a log metric filter and alarm exist for changes to network gateways \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_14.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_14.yaml old mode 100755 new mode 100644 index 992100f7b..bc23221c9 --- a/compliance/controls/pending/aws/aws_cis_v130_4_14.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_14.yaml @@ -1,13 +1,90 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs. ID: aws_cis_v130_4_14 -Title: "4.14 Ensure a log metric filter and alarm exist for VPC changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateVpc.+\\$\\.eventName\\s*=\\s*DeleteVpc.+\\$\\.eventName\\s*=\\s*ModifyVpcAttribute.+\\$\\.eventName\\s*=\\s*AcceptVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*CreateVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*DeleteVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*RejectVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*AttachClassicLinkVpc.+\\$\\.eventName\\s*=\\s*DetachClassicLinkVpc.+\\$\\.eventName\\s*=\\s*DisableVpcClassicLink.+\\$\\.eventName\\s*=\\s*EnableVpcClassicLink'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for VPC changes.'\n else filter_name || ' forwards events for VPC changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateVpc.+\$.eventName\s*=\s*DeleteVpc.+\$.eventName\s*=\s*ModifyVpcAttribute.+\$.eventName\s*=\s*AcceptVpcPeeringConnection.+\$.eventName\s*=\s*CreateVpcPeeringConnection.+\$.eventName\s*=\s*DeleteVpcPeeringConnection.+\$.eventName\s*=\s*RejectVpcPeeringConnection.+\$.eventName\s*=\s*AttachClassicLinkVpc.+\$.eventName\s*=\s*DetachClassicLinkVpc.+\$.eventName\s*=\s*DisableVpcClassicLink.+\$.eventName\s*=\s*EnableVpcClassicLink' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for VPC changes.' + ELSE filter_name || ' forwards events for VPC changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.14 Ensure a log metric filter and alarm exist for VPC changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_15.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_15.yaml old mode 100755 new mode 100644 index 74da5e315..729ad29a1 --- a/compliance/controls/pending/aws/aws_cis_v130_4_15.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_15.yaml @@ -1,13 +1,90 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account. ID: aws_cis_v130_4_15 -Title: "4.15 Ensure a log metric filter and alarm exists for AWS Organizations changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*organizations.amazonaws.com.+\\$\\.eventName\\s*=\\s*\"?AcceptHandshake\"?.+\\$\\.eventName\\s*=\\s*\"?AttachPolicy\"?.+\\$\\.eventName\\s*=\\s*\"?CreateAccount\"?.+\\$\\.eventName\\s*=\\s*\"?CreateOrganizationalUnit\"?.+\\$\\.eventName\\s*=\\s*\"?CreatePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DeclineHandshake\"?.+\\$\\.eventName\\s*=\\s*\"?DeleteOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?DeleteOrganizationalUnit\"?.+\\$\\.eventName\\s*=\\s*\"?DeletePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DetachPolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DisablePolicyType\"?.+\\$\\.eventName\\s*=\\s*\"?EnablePolicyType\"?.+\\$\\.eventName\\s*=\\s*\"?InviteAccountToOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?LeaveOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?MoveAccount\"?.+\\$\\.eventName\\s*=\\s*\"?RemoveAccountFromOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?UpdatePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?UpdateOrganizationalUnit\"?'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exists for AWS Organizations changes.'\n else filter_name || ' forwards relevant events for AWS Organizations changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ + '\\s*\\$\\.eventSource\\s*=\\s*organizations.amazonaws.com.+\\$\\.eventName\\s*=\\s*"?AcceptHandshake"?.+\\$\\.eventName\\s*=\\s*"?AttachPolicy"?.+\\$\\.eventName\\s*=\\s*"?CreateAccount"?.+\\$\\.eventName\\s*=\\s*"?CreateOrganizationalUnit"?.+\\$\\.eventName\\s*=\\s*"?CreatePolicy"?.+\\$\\.eventName\\s*=\\s*"?DeclineHandshake"?.+\\$\\.eventName\\s*=\\s*"?DeleteOrganization"?.+\\$\\.eventName\\s*=\\s*"?DeleteOrganizationalUnit"?.+\\$\\.eventName\\s*=\\s*"?DeletePolicy"?.+\\$\\.eventName\\s*=\\s*"?DetachPolicy"?.+\\$\\.eventName\\s*=\\s*"?DisablePolicyType"?.+\\$\\.eventName\\s*=\\s*"?EnablePolicyType"?.+\\$\\.eventName\\s*=\\s*"?InviteAccountToOrganization"?.+\\$\\.eventName\\s*=\\s*"?LeaveOrganization"?.+\\$\\.eventName\\s*=\\s*"?MoveAccount"?.+\\$\\.eventName\\s*=\\s*"?RemoveAccountFromOrganization"?.+\\$\\.eventName\\s*=\\s*"?UpdatePolicy"?.+\\$\\.eventName\\s*=\\s*"?UpdateOrganizationalUnit"?' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exists for AWS Organizations changes.' + ELSE filter_name || ' forwards relevant events for AWS Organizations changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.15 Ensure a log metric filter and alarm exists for AWS Organizations changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_2.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_2.yaml old mode 100755 new mode 100644 index 738fdf270..35a550024 --- a/compliance/controls/pending/aws/aws_cis_v130_4_2.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_2.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA). ID: aws_cis_v130_4_2 -Title: "4.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\(\\s*\\$\\.eventName\\s*=\\s*\"ConsoleLogin\"\\)\\s+&&\\s+\\(\\s*\\$.additionalEventData\\.MFAUsed\\s*!=\\s*\"Yes\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console sign-in without MFA.'\n else filter_name || ' forwards events for console sign-in without MFA.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\(\s*\$\.eventName\s*=\s*"ConsoleLogin"\)\s+&&\s+\(\s*\$.additionalEventData\.MFAUsed\s*!=\s*"Yes"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console sign-in without MFA.' + ELSE filter_name || ' forwards events for console sign-in without MFA.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_4.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_4.yaml old mode 100755 new mode 100644 index 109c6bcc4..ac0b1c7e5 --- a/compliance/controls/pending/aws/aws_cis_v130_4_4.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_4.yaml @@ -1,13 +1,86 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes made to Identity and Access Management (IAM) policies. ID: aws_cis_v130_4_4 -Title: "4.4 Ensure a log metric filter and alarm exist for IAM policy changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*DeleteGroupPolicy.+\\$\\.eventName\\s*=\\s*DeleteRolePolicy.+\\$\\.eventName\\s*=\\s*DeleteUserPolicy.+\\$\\.eventName\\s*=\\s*PutGroupPolicy.+\\$\\.eventName\\s*=\\s*PutRolePolicy.+\\$\\.eventName\\s*=\\s*PutUserPolicy.+\\$\\.eventName\\s*=\\s*CreatePolicy.+\\$\\.eventName\\s*=\\s*DeletePolicy.+\\$\\.eventName\\s*=\\s*CreatePolicyVersion.+\\$\\.eventName\\s*=\\s*DeletePolicyVersion.+\\$\\.eventName\\s*=\\s*AttachRolePolicy.+\\$\\.eventName\\s*=\\s*DetachRolePolicy.+\\$\\.eventName\\s*=\\s*AttachUserPolicy.+\\$\\.eventName\\s*=\\s*DetachUserPolicy.+\\$\\.eventName\\s*=\\s*AttachGroupPolicy.+\\$\\.eventName\\s*=\\s*DetachGroupPolicy'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for IAM policy changes.'\n else filter_name || ' forwards events for IAM policy changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*DeleteGroupPolicy.+\$.eventName\s*=\s*DeleteRolePolicy.+\$.eventName\s*=\s*DeleteUserPolicy.+\$.eventName\s*=\s*PutGroupPolicy.+\$.eventName\s*=\s*PutRolePolicy.+\$.eventName\s*=\s*PutUserPolicy.+\$.eventName\s*=\s*CreatePolicy.+\$.eventName\s*=\s*DeletePolicy.+\$.eventName\s*=\s*CreatePolicyVersion.+\$.eventName\s*=\s*DeletePolicyVersion.+\$.eventName\s*=\s*AttachRolePolicy.+\$.eventName\s*=\s*DetachRolePolicy.+\$.eventName\s*=\s*AttachUserPolicy.+\$.eventName\s*=\s*DetachUserPolicy.+\$.eventName\s*=\s*AttachGroupPolicy.+\$.eventName\s*=\s*DetachGroupPolicy' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for IAM policy changes.' + ELSE filter_name || ' forwards events for IAM policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.4 Ensure a log metric filter and alarm exist for IAM policy changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_5.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_5.yaml old mode 100755 new mode 100644 index 55c63d1b7..8199a94ea --- a/compliance/controls/pending/aws/aws_cis_v130_4_5.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_5.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations. ID: aws_cis_v130_4_5 -Title: "4.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateTrail.+\\$\\.eventName\\s*=\\s*UpdateTrail.+\\$\\.eventName\\s*=\\s*DeleteTrail.+\\$\\.eventName\\s*=\\s*StartLogging.+\\$\\.eventName\\s*=\\s*StopLogging'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for CloudTrail configuration changes.'\n else filter_name || ' forwards events for CloudTrail configuration changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateTrail.+\$.eventName\s*=\s*UpdateTrail.+\$.eventName\s*=\s*DeleteTrail.+\$.eventName\s*=\s*StartLogging.+\$.eventName\s*=\s*StopLogging' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for CloudTrail configuration changes.' + ELSE filter_name || ' forwards events for CloudTrail configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_6.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_6.yaml old mode 100755 new mode 100644 index 98175c1ec..9cb85f9d0 --- a/compliance/controls/pending/aws/aws_cis_v130_4_6.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_6.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts. ID: aws_cis_v130_4_6 -Title: "4.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*ConsoleLogin.+\\$\\.errorMessage\\s*=\\s*\"Failed authentication\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console authentication failures.'\n else f.filter_name || ' forwards events for console authentication failures.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*ConsoleLogin.+\$.errorMessage\s*=\s*"Failed authentication"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console authentication failures.' + ELSE f.filter_name || ' forwards events for console authentication failures.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_7.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_7.yaml old mode 100755 new mode 100644 index 3abadde8f..9a7c3fd0e --- a/compliance/controls/pending/aws/aws_cis_v130_4_7.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_7.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion. ID: aws_cis_v130_4_7 -Title: "4.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*kms.amazonaws.com.+\\$\\.eventName\\s*=\\s*DisableKey.+\\$\\.eventName\\s*=\\s*ScheduleKeyDeletion'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for disabling/deletion of CMKs.'\n else filter_name || ' forwards events for disabling/deletion of CMKs.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*kms.amazonaws.com.+\$.eventName\s*=\s*DisableKey.+\$.eventName\s*=\s*ScheduleKeyDeletion' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for disabling/deletion of CMKs.' + ELSE filter_name || ' forwards events for disabling/deletion of CMKs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_4_9.yaml b/compliance/controls/pending/aws/aws_cis_v130_4_9.yaml old mode 100755 new mode 100644 index 8edad967b..44770ee65 --- a/compliance/controls/pending/aws/aws_cis_v130_4_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_4_9.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations. ID: aws_cis_v130_4_9 -Title: "4.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*config.amazonaws.com.+\\$\\.eventName\\s*=\\s*StopConfigurationRecorder.+\\$\\.eventName\\s*=\\s*DeleteDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutConfigurationRecorder'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for AWS Config configuration changes.'\n else filter_name || ' forwards events for AWS Config configuration changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*config.amazonaws.com.+\$.eventName\s*=\s*StopConfigurationRecorder.+\$.eventName\s*=\s*DeleteDeliveryChannel.+\$.eventName\s*=\s*PutDeliveryChannel.+\$.eventName\s*=\s*PutConfigurationRecorder' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for AWS Config configuration changes.' + ELSE filter_name || ' forwards events for AWS Config configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_5_1.yaml b/compliance/controls/pending/aws/aws_cis_v130_5_1.yaml old mode 100755 new mode 100644 index dadba3a9f..8aa452cd0 --- a/compliance/controls/pending/aws/aws_cis_v130_5_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_5_1.yaml @@ -1,13 +1,84 @@ +Description: The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_cis_v130_5_1 -Title: "5.1 Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bad_rules as (\n select\n network_acl_id,\n count(*) as num_bad_rules,\n tags,\n region,\n account_id\n from\n aws_vpc_network_acl,\n jsonb_array_elements(entries) as att\n where\n att ->> 'Egress' = 'false' -- as per aws egress = false indicates the ingress\n and (\n att ->> 'CidrBlock' = '0.0.0.0/0'\n or att ->> 'Ipv6CidrBlock' = '::/0'\n )\n and att ->> 'RuleAction' = 'allow'\n and (\n (\n att ->> 'Protocol' = '-1' -- all traffic\n and att ->> 'PortRange' is null\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 22\n and (att -> 'PortRange' ->> 'To') :: int >= 22\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 3389\n and (att -> 'PortRange' ->> 'To') :: int >= 3389\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n )\n group by\n network_acl_id,\n region,\n account_id,\n tags\n order by\n network_acl_id,\n region,\n account_id,\n tags\n),\naws_vpc_network_acls as (\n select\n network_acl_id,\n tags,\n partition,\n region,\n account_id\n from\n aws_vpc_network_acl\n order by\n network_acl_id,\n region,\n account_id\n)\nselect\n 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id as resource,\n case\n when bad_rules.network_acl_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when bad_rules.network_acl_id is null then acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n else acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n end as reason\n \n \nfrom\n aws_vpc_network_acls as acl\n left join bad_rules on bad_rules.network_acl_id = acl.network_acl_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH bad_rules AS ( + SELECT + network_acl_id, + COUNT(*) AS num_bad_rules, + tags, + region, + account_id + FROM + aws_vpc_network_acl, + JSONB_ARRAY_ELEMENTS(entries) AS att + WHERE + att ->> 'Egress' = 'false' + AND ( + att ->> 'CidrBlock' = '0.0.0.0/0' + OR att ->> 'Ipv6CidrBlock' = '::/0' + ) + AND att ->> 'RuleAction' = 'allow' + AND ( + ( + att ->> 'Protocol' = '-1' + AND att ->> 'PortRange' IS NULL + ) + OR ( + (att -> 'PortRange' ->> 'From')::INT <= 22 + AND (att -> 'PortRange' ->> 'To')::INT >= 22 + AND att ->> 'Protocol' IN ('6', '17') + ) + OR ( + (att -> 'PortRange' ->> 'From')::INT <= 3389 + AND (att -> 'PortRange' ->> 'To')::INT >= 3389 + AND att ->> 'Protocol' IN ('6', '17') + ) + ) + GROUP BY + network_acl_id, + region, + account_id, + tags + ORDER BY + network_acl_id, + region, + account_id, + tags + ), + aws_vpc_network_acls AS ( + SELECT + network_acl_id, + tags, + partition, + region, + account_id + FROM + aws_vpc_network_acl + ORDER BY + network_acl_id, + region, + account_id + ) + SELECT + 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id AS resource, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + aws_vpc_network_acls AS acl + LEFT JOIN bad_rules ON bad_rules.network_acl_id = acl.network_acl_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.1 Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v130_5_3.yaml b/compliance/controls/pending/aws/aws_cis_v130_5_3.yaml old mode 100755 new mode 100644 index c4352edfd..754466cc8 --- a/compliance/controls/pending/aws/aws_cis_v130_5_3.yaml +++ b/compliance/controls/pending/aws/aws_cis_v130_5_3.yaml @@ -1,13 +1,32 @@ +Description: A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. ID: aws_cis_v130_5_3 -Title: "5.3 Ensure the default security group of every VPC restricts all traffic" -Description: "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn resource,\n case\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) = 0 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has inbound and outbound rules.'\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) = 0\n then 'Default security group ' || group_id || ' has inbound rules.'\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has outbound rules.'\n else 'Default security group ' || group_id || ' has no inbound or outbound rules.'\n end reason\n \n \nfrom\n aws_vpc_security_group\nwhere\n group_name = 'default';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has inbound and outbound rules.' + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) = 0 + THEN 'Default security group ' || group_id || ' has inbound rules.' + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has outbound rules.' + ELSE 'Default security group ' || group_id || ' has no inbound or outbound rules.' + END AS reason + FROM + aws_vpc_security_group + WHERE + group_name = 'default'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.3 Ensure the default security group of every VPC restricts all traffic \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_1_6.yaml b/compliance/controls/pending/aws/aws_cis_v140_1_6.yaml old mode 100755 new mode 100644 index 1c09f6259..9739d6692 --- a/compliance/controls/pending/aws/aws_cis_v140_1_6.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_1_6.yaml @@ -1,13 +1,28 @@ +Description: The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root user account be protected with a hardware MFA. ID: aws_cis_v140_1_6 -Title: "1.6 Ensure hardware MFA is enabled for the 'root' user account" -Description: "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root user account be protected with a hardware MFA." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || s.partition || ':::' || s.account_id as resource,\n case\n when s.account_mfa_enabled and d.serial_number is null then 'ok'\n else 'alarm'\n end status,\n case\n when s.account_mfa_enabled = false then 'MFA not enabled for root account.'\n when d.serial_number is not null then 'MFA enabled for root account, but the MFA associated is a virtual device.'\n else 'Hardware MFA device enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary as s\n left join aws_iam_virtual_mfa_device as d on (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || s.partition || ':::' || s.account_id AS resource, + CASE + WHEN s.account_mfa_enabled AND d.serial_number IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.account_mfa_enabled = FALSE THEN 'MFA not enabled for root account.' + WHEN d.serial_number IS NOT NULL THEN 'MFA enabled for root account, but the MFA associated is a virtual device.' + ELSE 'Hardware MFA device enabled for root account.' + END AS reason + FROM + aws_iam_account_summary AS s + LEFT JOIN aws_iam_virtual_mfa_device AS d + ON (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.6 Ensure hardware MFA is enabled for the 'root' user account \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_1_8.yaml b/compliance/controls/pending/aws/aws_cis_v140_1_8.yaml old mode 100755 new mode 100644 index da288d2ee..1bfc681e8 --- a/compliance/controls/pending/aws/aws_cis_v140_1_8.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_1_8.yaml @@ -1,13 +1,27 @@ +Description: Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14. ID: aws_cis_v140_1_8 -Title: "1.8 Ensure IAM password policy requires minimum length of 14 or greater" -Description: "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when minimum_password_length >= 14 then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n else 'Minimum password length set to ' || minimum_password_length || '.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN minimum_password_length >= 14 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + ELSE 'Minimum password length set to ' || minimum_password_length || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.8 Ensure IAM password policy requires minimum length of 14 or greater \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_1_9.yaml b/compliance/controls/pending/aws/aws_cis_v140_1_9.yaml old mode 100755 new mode 100644 index 5d130e6a5..4ab96142e --- a/compliance/controls/pending/aws/aws_cis_v140_1_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_1_9.yaml @@ -1,13 +1,30 @@ +Description: IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords. ID: aws_cis_v140_1_9 -Title: "1.9 Ensure IAM password policy prevents password reuse" -Description: "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when password_reuse_prevention >= 24 then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n when password_reuse_prevention is null then 'Password reuse prevention not set.'\n else 'Password reuse prevention set to ' || password_reuse_prevention || '.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN password_reuse_prevention >= 24 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN password_reuse_prevention IS NULL THEN 'Password reuse prevention not set.' + ELSE 'Password reuse prevention set to ' || password_reuse_prevention || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON + a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.9 Ensure IAM password policy prevents password reuse \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_2_1_5.yaml b/compliance/controls/pending/aws/aws_cis_v140_2_1_5.yaml old mode 100755 new mode 100644 index 194cd7c89..524566110 --- a/compliance/controls/pending/aws/aws_cis_v140_2_1_5.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_2_1_5.yaml @@ -1,13 +1,42 @@ +Description: Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principle with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, Block public access (bucket settings) prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, Block public access (account settings) prevents all buckets, and contained objects, from becoming publicly accessible across the entire account. ID: aws_cis_v140_2_1_5 -Title: "2.1.5 Ensure that S3 Buckets are configured with 'Block public access (bucket settings)'" -Description: "Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principle with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, Block public access (bucket settings) prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, Block public access (account settings) prevents all buckets, and contained objects, from becoming publicly accessible across the entire account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when (bucket.block_public_acls or s3account.block_public_acls)\n and (bucket.block_public_policy or s3account.block_public_policy)\n and (bucket.ignore_public_acls or s3account.ignore_public_acls)\n and (bucket.restrict_public_buckets or s3account.restrict_public_buckets)\n then 'ok'\n else 'alarm'\n end as status,\n case\n when (bucket.block_public_acls or s3account.block_public_acls)\n and (bucket.block_public_policy or s3account.block_public_policy)\n and (bucket.ignore_public_acls or s3account.ignore_public_acls)\n and (bucket.restrict_public_buckets or s3account.restrict_public_buckets)\n then name || ' all public access blocks enabled.'\n else name || ' not enabled for: ' ||\n concat_ws(', ',\n case when not (bucket.block_public_acls or s3account.block_public_acls) then 'block_public_acls' end,\n case when not (bucket.block_public_policy or s3account.block_public_policy) then 'block_public_policy' end,\n case when not (bucket.ignore_public_acls or s3account.ignore_public_acls) then 'ignore_public_acls' end,\n case when not (bucket.restrict_public_buckets or s3account.restrict_public_buckets) then 'restrict_public_buckets' end\n ) || '.'\n end as reason\n \n \nfrom\n aws_s3_bucket as bucket,\n aws_s3_account_settings as s3account\nwhere\n s3account.account_id = bucket.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN name || ' all public access blocks enabled.' + ELSE name || ' not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT (bucket.block_public_acls OR s3account.block_public_acls) THEN 'block_public_acls' END, + CASE WHEN NOT (bucket.block_public_policy OR s3account.block_public_policy) THEN 'block_public_policy' END, + CASE WHEN NOT (bucket.ignore_public_acls OR s3account.ignore_public_acls) THEN 'ignore_public_acls' END, + CASE WHEN NOT (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) THEN 'restrict_public_buckets' END + ) || '.' + END AS reason + FROM + aws_s3_bucket AS bucket, + aws_s3_account_settings AS s3account + WHERE + s3account.account_id = bucket.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.5 Ensure that S3 Buckets are configured with 'Block public access (bucket settings)' \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_3_1.yaml b/compliance/controls/pending/aws/aws_cis_v140_3_1.yaml old mode 100755 new mode 100644 index c0e59cbef..ef180d5a2 --- a/compliance/controls/pending/aws/aws_cis_v140_3_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_3_1.yaml @@ -1,13 +1,58 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to + you. The recorded information includes the identity of the API caller, the time of the API call, the source IP + address of the API caller, the request parameters, and the response elements returned by the AWS service. + CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, + SDKs, command line tools, and higher-level AWS services (such as CloudFormation). ID: aws_cis_v140_3_1 -Title: "3.1 Ensure CloudTrail is enabled in all regions" -Description: "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as e\n where\n (is_logging and is_multi_region_trail and e ->> 'ReadWriteType' = 'All')\n),\nadvanced_event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements_text(advanced_event_selectors) as a\n where\n -- when readOnly = true, then it is readOnly, when readOnly = false then it is writeOnly, if advanced_event_selectors is not null then it is both ReadWriteType\n (is_logging and is_multi_region_trail and advanced_event_selectors is not null and (not a like '%readOnly%'))\n)\nselect\n a.title as resource,\n case\n when d.account_id is null and ad.account_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when d.account_id is null and ad.account_id is null then 'cloudtrail disabled.'\n else 'cloudtrail enabled.'\n end as reason\n\n \nfrom\n aws_account as a\n left join event_selectors_trail_details as d on d.account_id = a.account_id\n left join advanced_event_selectors_trail_details as ad on ad.account_id = a.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH event_selectors_trail_details AS ( + SELECT DISTINCT + account_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS e + WHERE + (is_logging + AND is_multi_region_trail + AND e ->> 'ReadWriteType' = 'All') + ), + advanced_event_selectors_trail_details AS ( + SELECT DISTINCT + account_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements_text(advanced_event_selectors) AS a + WHERE + (is_logging + AND is_multi_region_trail + AND advanced_event_selectors IS NOT NULL + AND (NOT a LIKE '%readOnly%')) + ) + SELECT + a.title AS resource, + CASE + WHEN d.account_id IS NULL + AND ad.account_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.account_id IS NULL + AND ad.account_id IS NULL THEN 'cloudtrail disabled.' + ELSE 'cloudtrail enabled.' + END AS reason + FROM + aws_account AS a + LEFT JOIN event_selectors_trail_details AS d + ON d.account_id = a.account_id + LEFT JOIN advanced_event_selectors_trail_details AS ad + ON ad.account_id = a.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.1 Ensure CloudTrail is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_1.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_1.yaml old mode 100755 new mode 100644 index 174338b95..31d103561 --- a/compliance/controls/pending/aws/aws_cis_v140_4_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_1.yaml @@ -1,13 +1,93 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls. ID: aws_cis_v140_4_1 -Title: "4.1 Ensure a log metric filter and alarm exist for unauthorized API calls" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\$\\.errorCode\\s*=\\s*\"\\*UnauthorizedOperation\".+\\$\\.errorCode\\s*=\\s*\"AccessDenied\\*\".+\\$\\.sourceIPAddress\\s*!=\\s*\"delivery.logs.amazonaws.com\".+\\$\\.eventName\\s*!=\\s*\"HeadBucket\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for unauthorized API calls.'\n else filter_name || ' forwards events for unauthorized API calls.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '$.errorCode\\s*=\\s*"*UnauthorizedOperation"' + AND filter.filter_pattern ~ '$.errorCode\\s*=\\s*"AccessDenied*"' + AND filter.filter_pattern ~ '$.sourceIPAddress\\s*!=\\s*"delivery.logs.amazonaws.com"' + AND filter.filter_pattern ~ '$.eventName\\s*!=\\s*"HeadBucket"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for unauthorized API calls.' + ELSE filter_name || ' forwards events for unauthorized API calls.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.1 Ensure a log metric filter and alarm exist for unauthorized API calls \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_10.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_10.yaml old mode 100755 new mode 100644 index 204a3c19d..c6405bc33 --- a/compliance/controls/pending/aws/aws_cis_v140_4_10.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_10.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups. ID: aws_cis_v140_4_10 -Title: "4.10 Ensure a log metric filter and alarm exist for security group changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*AuthorizeSecurityGroupIngress.+\\$\\.eventName\\s*=\\s*AuthorizeSecurityGroupEgress.+\\$\\.eventName\\s*=\\s*RevokeSecurityGroupIngress.+\\$\\.eventName\\s*=\\s*RevokeSecurityGroupEgress.+\\$\\.eventName\\s*=\\s*CreateSecurityGroup.+\\$\\.eventName\\s*=\\s*DeleteSecurityGroup'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for security group changes.'\n else filter_name || ' forwards events for security group changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*RevokeSecurityGroupIngress.+\$\.eventName\s*=\s*RevokeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for security group changes.' + ELSE filter_name || ' forwards events for security group changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.10 Ensure a log metric filter and alarm exist for security group changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_11.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_11.yaml old mode 100755 new mode 100644 index 73b66e35e..f2ca03c56 --- a/compliance/controls/pending/aws/aws_cis_v140_4_11.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_11.yaml @@ -1,13 +1,90 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs. ID: aws_cis_v140_4_11 -Title: "4.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL)" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateNetworkAcl.+\\$\\.eventName\\s*=\\s*CreateNetworkAclEntry.+\\$\\.eventName\\s*=\\s*DeleteNetworkAcl.+\\$\\.eventName\\s*=\\s*DeleteNetworkAclEntry.+\\$\\.eventName\\s*=\\s*ReplaceNetworkAclEntry.+\\$\\.eventName\\s*=\\s*ReplaceNetworkAclAssociation'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for changes to NACLs.'\n else filter_name || ' forwards events for changes to NACLs.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateNetworkAcl.+\$\.eventName\s*=\s*CreateNetworkAclEntry.+\$\.eventName\s*=\s*DeleteNetworkAcl.+\$\.eventName\s*=\s*DeleteNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclAssociation' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to NACLs.' + ELSE filter_name || ' forwards events for changes to NACLs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_12.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_12.yaml old mode 100755 new mode 100644 index 15f80755d..24c1e5863 --- a/compliance/controls/pending/aws/aws_cis_v140_4_12.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_12.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways. ID: aws_cis_v140_4_12 -Title: "4.12 Ensure a log metric filter and alarm exist for changes to network gateways" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateCustomerGateway.+\\$\\.eventName\\s*=\\s*DeleteCustomerGateway.+\\$\\.eventName\\s*=\\s*AttachInternetGateway.+\\$\\.eventName\\s*=\\s*CreateInternetGateway.+\\$\\.eventName\\s*=\\s*DeleteInternetGateway.+\\$\\.eventName\\s*=\\s*DetachInternetGateway'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for changes to network gateways.'\n else filter_name || ' forwards events for changes to network gateways.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateCustomerGateway.+\$.eventName\s*=\s*DeleteCustomerGateway.+\$.eventName\s*=\s*AttachInternetGateway.+\$.eventName\s*=\s*CreateInternetGateway.+\$.eventName\s*=\s*DeleteInternetGateway.+\$.eventName\s*=\s*DetachInternetGateway' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to network gateways.' + ELSE filter_name || ' forwards events for changes to network gateways.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.12 Ensure a log metric filter and alarm exist for changes to network gateways \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_13.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_13.yaml old mode 100755 new mode 100644 index 555cc422f..ed6c8b44d --- a/compliance/controls/pending/aws/aws_cis_v140_4_13.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_13.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables. ID: aws_cis_v140_4_13 -Title: "4.13 Ensure a log metric filter and alarm exist for route table changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateRoute.+\\$\\.eventName\\s*=\\s*CreateRouteTable.+\\$\\.eventName\\s*=\\s*ReplaceRoute.+\\$\\.eventName\\s*=\\s*ReplaceRouteTableAssociation.+\\$\\.eventName\\s*=\\s*DeleteRouteTable.+\\$\\.eventName\\s*=\\s*DeleteRoute.+\\$\\.eventName\\s*=\\s*DisassociateRouteTable'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for route table changes.'\n else filter_name || ' forwards events for route table changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateRoute.+\\$\\.eventName\\s*=\\s*CreateRouteTable.+\\$\\.eventName\\s*=\\s*ReplaceRoute.+\\$\\.eventName\\s*=\\s*ReplaceRouteTableAssociation.+\\$\\.eventName\\s*=\\s*DeleteRouteTable.+\\$\\.eventName\\s*=\\s*DeleteRoute.+\\$\\.eventName\\s*=\\s*DisassociateRouteTable' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for route table changes.' + ELSE filter_name || ' forwards events for route table changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.13 Ensure a log metric filter and alarm exist for route table changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_15.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_15.yaml old mode 100755 new mode 100644 index 2e5e48999..4d6e2242d --- a/compliance/controls/pending/aws/aws_cis_v140_4_15.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_15.yaml @@ -1,13 +1,109 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account. ID: aws_cis_v140_4_15 -Title: "4.15 Ensure a log metric filter and alarm exists for AWS Organizations changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*organizations.amazonaws.com.+\\$\\.eventName\\s*=\\s*\"?AcceptHandshake\"?.+\\$\\.eventName\\s*=\\s*\"?AttachPolicy\"?.+\\$\\.eventName\\s*=\\s*\"?CreateAccount\"?.+\\$\\.eventName\\s*=\\s*\"?CreateOrganizationalUnit\"?.+\\$\\.eventName\\s*=\\s*\"?CreatePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DeclineHandshake\"?.+\\$\\.eventName\\s*=\\s*\"?DeleteOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?DeleteOrganizationalUnit\"?.+\\$\\.eventName\\s*=\\s*\"?DeletePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DetachPolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DisablePolicyType\"?.+\\$\\.eventName\\s*=\\s*\"?EnablePolicyType\"?.+\\$\\.eventName\\s*=\\s*\"?InviteAccountToOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?LeaveOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?MoveAccount\"?.+\\$\\.eventName\\s*=\\s*\"?RemoveAccountFromOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?UpdatePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?UpdateOrganizationalUnit\"?'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exists for AWS Organizations changes.'\n else filter_name || ' forwards relevant events for AWS Organizations changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ ' + \s*\$\.eventSource\s*=\s*organizations.amazonaws.com + .+ \$\.eventName\s*=\s*"?AcceptHandshake"? + .+ \$\.eventName\s*=\s*"?AttachPolicy"? + .+ \$\.eventName\s*=\s*"?CreateAccount"? + .+ \$\.eventName\s*=\s*"?CreateOrganizationalUnit"? + .+ \$\.eventName\s*=\s*"?CreatePolicy"? + .+ \$\.eventName\s*=\s*"?DeclineHandshake"? + .+ \$\.eventName\s*=\s*"?DeleteOrganization"? + .+ \$\.eventName\s*=\s*"?DeleteOrganizationalUnit"? + .+ \$\.eventName\s*=\s*"?DeletePolicy"? + .+ \$\.eventName\s*=\s*"?DetachPolicy"? + .+ \$\.eventName\s*=\s*"?DisablePolicyType"? + .+ \$\.eventName\s*=\s*"?EnablePolicyType"? + .+ \$\.eventName\s*=\s*"?InviteAccountToOrganization"? + .+ \$\.eventName\s*=\s*"?LeaveOrganization"? + .+ \$\.eventName\s*=\s*"?MoveAccount"? + .+ \$\.eventName\s*=\s*"?RemoveAccountFromOrganization"? + .+ \$\.eventName\s*=\s*"?UpdatePolicy"? + .+ \$\.eventName\s*=\s*"?UpdateOrganizationalUnit"? + ' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exists for AWS Organizations changes.' + ELSE filter_name || ' forwards relevant events for AWS Organizations changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.15 Ensure a log metric filter and alarm exists for AWS Organizations changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_2.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_2.yaml old mode 100755 new mode 100644 index 9c3a81ba0..969903263 --- a/compliance/controls/pending/aws/aws_cis_v140_4_2.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_2.yaml @@ -1,13 +1,90 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA). ID: aws_cis_v140_4_2 -Title: "4.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\(\\s*\\$\\.eventName\\s*=\\s*\"ConsoleLogin\"\\)\\s+&&\\s+\\(\\s*\\$.additionalEventData\\.MFAUsed\\s*!=\\s*\"Yes\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console sign-in without MFA.'\n else filter_name || ' forwards events for console sign-in without MFA.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\(\s*\$\.eventName\s*=\s*"ConsoleLogin"\)\s+&&\s+\(\s*\$.additionalEventData\.MFAUsed\s*!=\s*"Yes"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console sign-in without MFA.' + ELSE filter_name || ' forwards events for console sign-in without MFA.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_3.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_3.yaml old mode 100755 new mode 100644 index 4547f6ada..9a9bed75d --- a/compliance/controls/pending/aws/aws_cis_v140_4_3.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_3.yaml @@ -1,13 +1,96 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for root login attempts. ID: aws_cis_v140_4_3 -Title: "4.3 Ensure a log metric filter and alarm exist for usage of 'root' account" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for root login attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.userIdentity\\.type\\s*=\\s*\"Root\".+\\$\\.userIdentity\\.invokedBy NOT EXISTS.+\\$\\.eventType\\s*!=\\s*\"AwsServiceEvent\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for usage of \"root\" account.'\n else filter_name || ' forwards events for usage of \"root\" account.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.userIdentity.type\s*=\s*"Root".+\$.userIdentity.invokedBy NOT EXISTS.+\$.eventType\s*!=\s*"AwsServiceEvent"' + ORDER BY + filter_name + ), + + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for usage of "root" account.' + ELSE filter_name || ' forwards events for usage of "root" account.' + END AS reason + + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.3 Ensure a log metric filter and alarm exist for usage of 'root' account \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_4.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_4.yaml old mode 100755 new mode 100644 index 0d4bd0541..3bdbcf10b --- a/compliance/controls/pending/aws/aws_cis_v140_4_4.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_4.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies. ID: aws_cis_v140_4_4 -Title: "4.4 Ensure a log metric filter and alarm exist for IAM policy changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*DeleteGroupPolicy.+\\$\\.eventName\\s*=\\s*DeleteRolePolicy.+\\$\\.eventName\\s*=\\s*DeleteUserPolicy.+\\$\\.eventName\\s*=\\s*PutGroupPolicy.+\\$\\.eventName\\s*=\\s*PutRolePolicy.+\\$\\.eventName\\s*=\\s*PutUserPolicy.+\\$\\.eventName\\s*=\\s*CreatePolicy.+\\$\\.eventName\\s*=\\s*DeletePolicy.+\\$\\.eventName\\s*=\\s*CreatePolicyVersion.+\\$\\.eventName\\s*=\\s*DeletePolicyVersion.+\\$\\.eventName\\s*=\\s*AttachRolePolicy.+\\$\\.eventName\\s*=\\s*DetachRolePolicy.+\\$\\.eventName\\s*=\\s*AttachUserPolicy.+\\$\\.eventName\\s*=\\s*DetachUserPolicy.+\\$\\.eventName\\s*=\\s*AttachGroupPolicy.+\\$\\.eventName\\s*=\\s*DetachGroupPolicy'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for IAM policy changes.'\n else filter_name || ' forwards events for IAM policy changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*DeleteGroupPolicy.+\$.eventName\s*=\s*DeleteRolePolicy.+\$.eventName\s*=\s*DeleteUserPolicy.+\$.eventName\s*=\s*PutGroupPolicy.+\$.eventName\s*=\s*PutRolePolicy.+\$.eventName\s*=\s*PutUserPolicy.+\$.eventName\s*=\s*CreatePolicy.+\$.eventName\s*=\s*DeletePolicy.+\$.eventName\s*=\s*CreatePolicyVersion.+\$.eventName\s*=\s*DeletePolicyVersion.+\$.eventName\s*=\s*AttachRolePolicy.+\$.eventName\s*=\s*DetachRolePolicy.+\$.eventName\s*=\s*AttachUserPolicy.+\$.eventName\s*=\s*DetachUserPolicy.+\$.eventName\s*=\s*AttachGroupPolicy.+\$.eventName\s*=\s*DetachGroupPolicy' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for IAM policy changes.' + ELSE filter_name || ' forwards events for IAM policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.4 Ensure a log metric filter and alarm exist for IAM policy changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_6.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_6.yaml old mode 100755 new mode 100644 index 604ccee5e..a8bb9bf03 --- a/compliance/controls/pending/aws/aws_cis_v140_4_6.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_6.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts. ID: aws_cis_v140_4_6 -Title: "4.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*ConsoleLogin.+\\$\\.errorMessage\\s*=\\s*\"Failed authentication\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console authentication failures.'\n else f.filter_name || ' forwards events for console authentication failures.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*ConsoleLogin.+\$.errorMessage\s*=\s*"Failed authentication"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console authentication failures.' + ELSE f.filter_name || ' forwards events for console authentication failures.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_4_9.yaml b/compliance/controls/pending/aws/aws_cis_v140_4_9.yaml old mode 100755 new mode 100644 index 6fe521a66..81997e97c --- a/compliance/controls/pending/aws/aws_cis_v140_4_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_4_9.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations. ID: aws_cis_v140_4_9 -Title: "4.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*config.amazonaws.com.+\\$\\.eventName\\s*=\\s*StopConfigurationRecorder.+\\$\\.eventName\\s*=\\s*DeleteDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutConfigurationRecorder'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for AWS Config configuration changes.'\n else filter_name || ' forwards events for AWS Config configuration changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*config.amazonaws.com.+\$\.eventName\s*=\s*StopConfigurationRecorder.+\$\.eventName\s*=\s*DeleteDeliveryChannel.+\$\.eventName\s*=\s*PutDeliveryChannel.+\$\.eventName\s*=\s*PutConfigurationRecorder' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for AWS Config configuration changes.' + ELSE filter_name || ' forwards events for AWS Config configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v140_5_3.yaml b/compliance/controls/pending/aws/aws_cis_v140_5_3.yaml old mode 100755 new mode 100644 index 0c16e186b..3c79cd6aa --- a/compliance/controls/pending/aws/aws_cis_v140_5_3.yaml +++ b/compliance/controls/pending/aws/aws_cis_v140_5_3.yaml @@ -1,13 +1,32 @@ +Description: A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. ID: aws_cis_v140_5_3 -Title: "5.3 Ensure the default security group of every VPC restricts all traffic" -Description: "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn resource,\n case\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) = 0 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has inbound and outbound rules.'\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) = 0\n then 'Default security group ' || group_id || ' has inbound rules.'\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has outbound rules.'\n else 'Default security group ' || group_id || ' has no inbound or outbound rules.'\n end reason\n \n \nfrom\n aws_vpc_security_group\nwhere\n group_name = 'default';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) = 0 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has inbound and outbound rules.' + WHEN jsonb_array_length(ip_permissions) > 0 AND jsonb_array_length(ip_permissions_egress) = 0 + THEN 'Default security group ' || group_id || ' has inbound rules.' + WHEN jsonb_array_length(ip_permissions) = 0 AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has outbound rules.' + ELSE 'Default security group ' || group_id || ' has no inbound or outbound rules.' + END AS reason + FROM + aws_vpc_security_group + WHERE + group_name = 'default'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.3 Ensure the default security group of every VPC restricts all traffic \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_1_20.yaml b/compliance/controls/pending/aws/aws_cis_v150_1_20.yaml old mode 100755 new mode 100644 index efd7b6457..3c939b1f6 --- a/compliance/controls/pending/aws/aws_cis_v150_1_20.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_1_20.yaml @@ -1,13 +1,29 @@ +Description: Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region. ID: aws_cis_v150_1_20 -Title: "1.20 Ensure that IAM Access analyzer is enabled for all regions" -Description: "Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource,\n case\n -- Skip any regions that are disabled in the account.\n when r.opt_in_status = 'not-opted-in' then 'skip'\n when aa.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.'\n when aa.arn is not null then aa.name || ' enabled in ' || r.region || '.'\n else 'Access Analyzer not enabled in ' || r.region || '.'\n end as reason\n \nfrom\n aws_region as r\n left join aws_accessanalyzer_analyzer as aa on r.account_id = aa.account_id and r.region = aa.region;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN aa.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN aa.arn IS NOT NULL THEN aa.name || ' enabled in ' || r.region || '.' + ELSE 'Access Analyzer not enabled in ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN aws_accessanalyzer_analyzer AS aa + ON r.account_id = aa.account_id AND r.region = aa.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.20 Ensure that IAM Access analyzer is enabled for all regions \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_1_6.yaml b/compliance/controls/pending/aws/aws_cis_v150_1_6.yaml old mode 100755 new mode 100644 index 4e2085c6d..ae0e004e2 --- a/compliance/controls/pending/aws/aws_cis_v150_1_6.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_1_6.yaml @@ -1,13 +1,28 @@ +Description: The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root user account be protected with a hardware MFA. ID: aws_cis_v150_1_6 -Title: "1.6 Ensure hardware MFA is enabled for the 'root' user account" -Description: "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root user account be protected with a hardware MFA." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || s.partition || ':::' || s.account_id as resource,\n case\n when s.account_mfa_enabled and d.serial_number is null then 'ok'\n else 'alarm'\n end status,\n case\n when s.account_mfa_enabled = false then 'MFA not enabled for root account.'\n when d.serial_number is not null then 'MFA enabled for root account, but the MFA associated is a virtual device.'\n else 'Hardware MFA device enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary as s\n left join aws_iam_virtual_mfa_device as d on (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || s.partition || ':::' || s.account_id AS resource, + CASE + WHEN s.account_mfa_enabled AND d.serial_number IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.account_mfa_enabled = FALSE THEN 'MFA not enabled for root account.' + WHEN d.serial_number IS NOT NULL THEN 'MFA enabled for root account, but the MFA associated is a virtual device.' + ELSE 'Hardware MFA device enabled for root account.' + END AS reason + FROM + aws_iam_account_summary AS s + LEFT JOIN + aws_iam_virtual_mfa_device AS d ON (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.6 Ensure hardware MFA is enabled for the 'root' user account \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_2_1_5.yaml b/compliance/controls/pending/aws/aws_cis_v150_2_1_5.yaml old mode 100755 new mode 100644 index dce7c00c3..ca1124c09 --- a/compliance/controls/pending/aws/aws_cis_v150_2_1_5.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_2_1_5.yaml @@ -1,13 +1,42 @@ +Description: Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principle with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, Block public access (bucket settings) prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, Block public access (account settings) prevents all buckets, and contained objects, from becoming publicly accessible across the entire account. ID: aws_cis_v150_2_1_5 -Title: "2.1.5 Ensure that S3 Buckets are configured with 'Block public access (bucket settings)'" -Description: "Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principle with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, Block public access (bucket settings) prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, Block public access (account settings) prevents all buckets, and contained objects, from becoming publicly accessible across the entire account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when (bucket.block_public_acls or s3account.block_public_acls)\n and (bucket.block_public_policy or s3account.block_public_policy)\n and (bucket.ignore_public_acls or s3account.ignore_public_acls)\n and (bucket.restrict_public_buckets or s3account.restrict_public_buckets)\n then 'ok'\n else 'alarm'\n end as status,\n case\n when (bucket.block_public_acls or s3account.block_public_acls)\n and (bucket.block_public_policy or s3account.block_public_policy)\n and (bucket.ignore_public_acls or s3account.ignore_public_acls)\n and (bucket.restrict_public_buckets or s3account.restrict_public_buckets)\n then name || ' all public access blocks enabled.'\n else name || ' not enabled for: ' ||\n concat_ws(', ',\n case when not (bucket.block_public_acls or s3account.block_public_acls) then 'block_public_acls' end,\n case when not (bucket.block_public_policy or s3account.block_public_policy) then 'block_public_policy' end,\n case when not (bucket.ignore_public_acls or s3account.ignore_public_acls) then 'ignore_public_acls' end,\n case when not (bucket.restrict_public_buckets or s3account.restrict_public_buckets) then 'restrict_public_buckets' end\n ) || '.'\n end as reason\n \n \nfrom\n aws_s3_bucket as bucket,\n aws_s3_account_settings as s3account\nwhere\n s3account.account_id = bucket.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN name || ' all public access blocks enabled.' + ELSE name || ' not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT (bucket.block_public_acls OR s3account.block_public_acls) THEN 'block_public_acls' END, + CASE WHEN NOT (bucket.block_public_policy OR s3account.block_public_policy) THEN 'block_public_policy' END, + CASE WHEN NOT (bucket.ignore_public_acls OR s3account.ignore_public_acls) THEN 'ignore_public_acls' END, + CASE WHEN NOT (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) THEN 'restrict_public_buckets' END + ) || '.' + END AS reason + FROM + aws_s3_bucket AS bucket, + aws_s3_account_settings AS s3account + WHERE + s3account.account_id = bucket.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.5 Ensure that S3 Buckets are configured with 'Block public access (bucket settings)' \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_3_1.yaml b/compliance/controls/pending/aws/aws_cis_v150_3_1.yaml old mode 100755 new mode 100644 index c51593a38..2045272a1 --- a/compliance/controls/pending/aws/aws_cis_v150_3_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_3_1.yaml @@ -1,13 +1,45 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation). ID: aws_cis_v150_3_1 -Title: "3.1 Ensure CloudTrail is enabled in all regions" -Description: "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as e\n where\n (is_logging and is_multi_region_trail and e ->> 'ReadWriteType' = 'All')\n),\nadvanced_event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements_text(advanced_event_selectors) as a\n where\n -- when readOnly = true, then it is readOnly, when readOnly = false then it is writeOnly, if advanced_event_selectors is not null then it is both ReadWriteType\n (is_logging and is_multi_region_trail and advanced_event_selectors is not null and (not a like '%readOnly%'))\n)\nselect\n a.title as resource,\n case\n when d.account_id is null and ad.account_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when d.account_id is null and ad.account_id is null then 'cloudtrail disabled.'\n else 'cloudtrail enabled.'\n end as reason\n\n \nfrom\n aws_account as a\n left join event_selectors_trail_details as d on d.account_id = a.account_id\n left join advanced_event_selectors_trail_details as ad on ad.account_id = a.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH event_selectors_trail_details AS ( + SELECT + DISTINCT account_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS e + WHERE + (is_logging AND is_multi_region_trail AND e ->> 'ReadWriteType' = 'All') + ), + advanced_event_selectors_trail_details AS ( + SELECT + DISTINCT account_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements_text(advanced_event_selectors) AS a + WHERE + (is_logging AND is_multi_region_trail AND advanced_event_selectors IS NOT NULL AND (NOT a LIKE '%readOnly%')) + ) + SELECT + a.title AS resource, + CASE + WHEN d.account_id IS NULL AND ad.account_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.account_id IS NULL AND ad.account_id IS NULL THEN 'cloudtrail disabled.' + ELSE 'cloudtrail enabled.' + END AS reason + FROM + aws_account AS a + LEFT JOIN event_selectors_trail_details AS d ON d.account_id = a.account_id + LEFT JOIN advanced_event_selectors_trail_details AS ad ON ad.account_id = a.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.1 Ensure CloudTrail is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_4_1.yaml b/compliance/controls/pending/aws/aws_cis_v150_4_1.yaml old mode 100755 new mode 100644 index 3e4b2b937..2ebf0b502 --- a/compliance/controls/pending/aws/aws_cis_v150_4_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_4_1.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls. ID: aws_cis_v150_4_1 -Title: "4.1 Ensure a log metric filter and alarm exist for unauthorized API calls" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\$\\.errorCode\\s*=\\s*\"\\*UnauthorizedOperation\".+\\$\\.errorCode\\s*=\\s*\"AccessDenied\\*\".+\\$\\.sourceIPAddress\\s*!=\\s*\"delivery.logs.amazonaws.com\".+\\$\\.eventName\\s*!=\\s*\"HeadBucket\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for unauthorized API calls.'\n else filter_name || ' forwards events for unauthorized API calls.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '$.errorCode\s*=\s*"*UnauthorizedOperation".+$\.errorCode\s*=\s*"AccessDenied*".+$\.sourceIPAddress\s*!=\s*"delivery.logs.amazonaws.com".+$\.eventName\s*!=\s*"HeadBucket"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for unauthorized API calls.' + ELSE filter_name || ' forwards events for unauthorized API calls.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.1 Ensure a log metric filter and alarm exist for unauthorized API calls \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_4_11.yaml b/compliance/controls/pending/aws/aws_cis_v150_4_11.yaml old mode 100755 new mode 100644 index eec405ec5..cad25db7a --- a/compliance/controls/pending/aws/aws_cis_v150_4_11.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_4_11.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs. ID: aws_cis_v150_4_11 -Title: "4.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL)" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateNetworkAcl.+\\$\\.eventName\\s*=\\s*CreateNetworkAclEntry.+\\$\\.eventName\\s*=\\s*DeleteNetworkAcl.+\\$\\.eventName\\s*=\\s*DeleteNetworkAclEntry.+\\$\\.eventName\\s*=\\s*ReplaceNetworkAclEntry.+\\$\\.eventName\\s*=\\s*ReplaceNetworkAclAssociation'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for changes to NACLs.'\n else filter_name || ' forwards events for changes to NACLs.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateNetworkAcl.+\$.eventName\s*=\s*CreateNetworkAclEntry.+\$.eventName\s*=\s*DeleteNetworkAcl.+\$.eventName\s*=\s*DeleteNetworkAclEntry.+\$.eventName\s*=\s*ReplaceNetworkAclEntry.+\$.eventName\s*=\s*ReplaceNetworkAclAssociation' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to NACLs.' + ELSE filter_name || ' forwards events for changes to NACLs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_4_12.yaml b/compliance/controls/pending/aws/aws_cis_v150_4_12.yaml old mode 100755 new mode 100644 index cec633368..0a8cac464 --- a/compliance/controls/pending/aws/aws_cis_v150_4_12.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_4_12.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways. ID: aws_cis_v150_4_12 -Title: "4.12 Ensure a log metric filter and alarm exist for changes to network gateways" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateCustomerGateway.+\\$\\.eventName\\s*=\\s*DeleteCustomerGateway.+\\$\\.eventName\\s*=\\s*AttachInternetGateway.+\\$\\.eventName\\s*=\\s*CreateInternetGateway.+\\$\\.eventName\\s*=\\s*DeleteInternetGateway.+\\$\\.eventName\\s*=\\s*DetachInternetGateway'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for changes to network gateways.'\n else filter_name || ' forwards events for changes to network gateways.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateCustomerGateway.+\$.eventName\s*=\s*DeleteCustomerGateway.+\$.eventName\s*=\s*AttachInternetGateway.+\$.eventName\s*=\s*CreateInternetGateway.+\$.eventName\s*=\s*DeleteInternetGateway.+\$.eventName\s*=\s*DetachInternetGateway' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to network gateways.' + ELSE filter_name || ' forwards events for changes to network gateways.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.12 Ensure a log metric filter and alarm exist for changes to network gateways \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_4_13.yaml b/compliance/controls/pending/aws/aws_cis_v150_4_13.yaml old mode 100755 new mode 100644 index 7e04ae1d1..cf42aad0b --- a/compliance/controls/pending/aws/aws_cis_v150_4_13.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_4_13.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables. ID: aws_cis_v150_4_13 -Title: "4.13 Ensure a log metric filter and alarm exist for route table changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateRoute.+\\$\\.eventName\\s*=\\s*CreateRouteTable.+\\$\\.eventName\\s*=\\s*ReplaceRoute.+\\$\\.eventName\\s*=\\s*ReplaceRouteTableAssociation.+\\$\\.eventName\\s*=\\s*DeleteRouteTable.+\\$\\.eventName\\s*=\\s*DeleteRoute.+\\$\\.eventName\\s*=\\s*DisassociateRouteTable'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for route table changes.'\n else filter_name || ' forwards events for route table changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateRoute.+\$.eventName\s*=\s*CreateRouteTable.+\$.eventName\s*=\s*ReplaceRoute.+\$.eventName\s*=\s*ReplaceRouteTableAssociation.+\$.eventName\s*=\s*DeleteRouteTable.+\$.eventName\s*=\s*DeleteRoute.+\$.eventName\s*=\s*DisassociateRouteTable' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for route table changes.' + ELSE filter_name || ' forwards events for route table changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.13 Ensure a log metric filter and alarm exist for route table changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_4_15.yaml b/compliance/controls/pending/aws/aws_cis_v150_4_15.yaml old mode 100755 new mode 100644 index 067827acc..a3de8c352 --- a/compliance/controls/pending/aws/aws_cis_v150_4_15.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_4_15.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account. ID: aws_cis_v150_4_15 -Title: "4.15 Ensure a log metric filter and alarm exists for AWS Organizations changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*organizations.amazonaws.com.+\\$\\.eventName\\s*=\\s*\"?AcceptHandshake\"?.+\\$\\.eventName\\s*=\\s*\"?AttachPolicy\"?.+\\$\\.eventName\\s*=\\s*\"?CreateAccount\"?.+\\$\\.eventName\\s*=\\s*\"?CreateOrganizationalUnit\"?.+\\$\\.eventName\\s*=\\s*\"?CreatePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DeclineHandshake\"?.+\\$\\.eventName\\s*=\\s*\"?DeleteOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?DeleteOrganizationalUnit\"?.+\\$\\.eventName\\s*=\\s*\"?DeletePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DetachPolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DisablePolicyType\"?.+\\$\\.eventName\\s*=\\s*\"?EnablePolicyType\"?.+\\$\\.eventName\\s*=\\s*\"?InviteAccountToOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?LeaveOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?MoveAccount\"?.+\\$\\.eventName\\s*=\\s*\"?RemoveAccountFromOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?UpdatePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?UpdateOrganizationalUnit\"?'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exists for AWS Organizations changes.'\n else filter_name || ' forwards relevant events for AWS Organizations changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*organizations.amazonaws.com.+\$.eventName\s*=\s*"?AcceptHandshake"?.+\$.eventName\s*=\s*"?AttachPolicy"?.+\$.eventName\s*=\s*"?CreateAccount"?.+\$.eventName\s*=\s*"?CreateOrganizationalUnit"?.+\$.eventName\s*=\s*"?CreatePolicy"?.+\$.eventName\s*=\s*"?DeclineHandshake"?.+\$.eventName\s*=\s*"?DeleteOrganization"?.+\$.eventName\s*=\s*"?DeleteOrganizationalUnit"?.+\$.eventName\s*=\s*"?DeletePolicy"?.+\$.eventName\s*=\s*"?DetachPolicy"?.+\$.eventName\s*=\s*"?DisablePolicyType"?.+\$.eventName\s*=\s*"?EnablePolicyType"?.+\$.eventName\s*=\s*"?InviteAccountToOrganization"?.+\$.eventName\s*=\s*"?LeaveOrganization"?.+\$.eventName\s*=\s*"?MoveAccount"?.+\$.eventName\s*=\s*"?RemoveAccountFromOrganization"?.+\$.eventName\s*=\s*"?UpdatePolicy"?.+\$.eventName\s*=\s*"?UpdateOrganizationalUnit"?' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exists for AWS Organizations changes.' + ELSE filter_name || ' forwards relevant events for AWS Organizations changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.15 Ensure a log metric filter and alarm exists for AWS Organizations changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_4_2.yaml b/compliance/controls/pending/aws/aws_cis_v150_4_2.yaml old mode 100755 new mode 100644 index 9d1117ef9..a03dd5ab3 --- a/compliance/controls/pending/aws/aws_cis_v150_4_2.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_4_2.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA). ID: aws_cis_v150_4_2 -Title: "4.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\(\\s*\\$\\.eventName\\s*=\\s*\"ConsoleLogin\"\\)\\s+&&\\s+\\(\\s*\\$.additionalEventData\\.MFAUsed\\s*!=\\s*\"Yes\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console sign-in without MFA.'\n else filter_name || ' forwards events for console sign-in without MFA.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\(\s*\$\.eventName\s*=\s*\"ConsoleLogin\"\)\s+&&\s+\(\s*\$.additionalEventData\.MFAUsed\s*!=\s*\"Yes\"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console sign-in without MFA.' + ELSE filter_name || ' forwards events for console sign-in without MFA.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_4_4.yaml b/compliance/controls/pending/aws/aws_cis_v150_4_4.yaml old mode 100755 new mode 100644 index cede2bd23..363da1634 --- a/compliance/controls/pending/aws/aws_cis_v150_4_4.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_4_4.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies. ID: aws_cis_v150_4_4 -Title: "4.4 Ensure a log metric filter and alarm exist for IAM policy changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*DeleteGroupPolicy.+\\$\\.eventName\\s*=\\s*DeleteRolePolicy.+\\$\\.eventName\\s*=\\s*DeleteUserPolicy.+\\$\\.eventName\\s*=\\s*PutGroupPolicy.+\\$\\.eventName\\s*=\\s*PutRolePolicy.+\\$\\.eventName\\s*=\\s*PutUserPolicy.+\\$\\.eventName\\s*=\\s*CreatePolicy.+\\$\\.eventName\\s*=\\s*DeletePolicy.+\\$\\.eventName\\s*=\\s*CreatePolicyVersion.+\\$\\.eventName\\s*=\\s*DeletePolicyVersion.+\\$\\.eventName\\s*=\\s*AttachRolePolicy.+\\$\\.eventName\\s*=\\s*DetachRolePolicy.+\\$\\.eventName\\s*=\\s*AttachUserPolicy.+\\$\\.eventName\\s*=\\s*DetachUserPolicy.+\\$\\.eventName\\s*=\\s*AttachGroupPolicy.+\\$\\.eventName\\s*=\\s*DetachGroupPolicy'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for IAM policy changes.'\n else filter_name || ' forwards events for IAM policy changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*DeleteGroupPolicy.+\$.eventName\s*=\s*DeleteRolePolicy.+\$.eventName\s*=\s*DeleteUserPolicy.+\$.eventName\s*=\s*PutGroupPolicy.+\$.eventName\s*=\s*PutRolePolicy.+\$.eventName\s*=\s*PutUserPolicy.+\$.eventName\s*=\s*CreatePolicy.+\$.eventName\s*=\s*DeletePolicy.+\$.eventName\s*=\s*CreatePolicyVersion.+\$.eventName\s*=\s*DeletePolicyVersion.+\$.eventName\s*=\s*AttachRolePolicy.+\$.eventName\s*=\s*DetachRolePolicy.+\$.eventName\s*=\s*AttachUserPolicy.+\$.eventName\s*=\s*DetachUserPolicy.+\$.eventName\s*=\s*AttachGroupPolicy.+\$.eventName\s*=\s*DetachGroupPolicy' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for IAM policy changes.' + ELSE filter_name || ' forwards events for IAM policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.4 Ensure a log metric filter and alarm exist for IAM policy changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_4_6.yaml b/compliance/controls/pending/aws/aws_cis_v150_4_6.yaml old mode 100755 new mode 100644 index cfd2666ad..d69714a2d --- a/compliance/controls/pending/aws/aws_cis_v150_4_6.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_4_6.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts. ID: aws_cis_v150_4_6 -Title: "4.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*ConsoleLogin.+\\$\\.errorMessage\\s*=\\s*\"Failed authentication\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console authentication failures.'\n else f.filter_name || ' forwards events for console authentication failures.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*ConsoleLogin.+\\$\\.errorMessage\\s*=\\s*"Failed authentication"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console authentication failures.' + ELSE f.filter_name || ' forwards events for console authentication failures.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_4_9.yaml b/compliance/controls/pending/aws/aws_cis_v150_4_9.yaml old mode 100755 new mode 100644 index bef177ebf..8dcf0c0b6 --- a/compliance/controls/pending/aws/aws_cis_v150_4_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_4_9.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations. ID: aws_cis_v150_4_9 -Title: "4.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*config.amazonaws.com.+\\$\\.eventName\\s*=\\s*StopConfigurationRecorder.+\\$\\.eventName\\s*=\\s*DeleteDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutConfigurationRecorder'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for AWS Config configuration changes.'\n else filter_name || ' forwards events for AWS Config configuration changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*config.amazonaws.com.+\$.eventName\s*=\s*StopConfigurationRecorder.+\$.eventName\s*=\s*DeleteDeliveryChannel.+\$.eventName\s*=\s*PutDeliveryChannel.+\$.eventName\s*=\s*PutConfigurationRecorder' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for AWS Config configuration changes.' + ELSE filter_name || ' forwards events for AWS Config configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v150_5_1.yaml b/compliance/controls/pending/aws/aws_cis_v150_5_1.yaml old mode 100755 new mode 100644 index be63af7af..adac2fc0a --- a/compliance/controls/pending/aws/aws_cis_v150_5_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v150_5_1.yaml @@ -1,13 +1,85 @@ +Description: The Network Access Control List (NACL) function provides stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389. ID: aws_cis_v150_5_1 -Title: "5.1 Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bad_rules as (\n select\n network_acl_id,\n count(*) as num_bad_rules,\n tags,\n region,\n account_id\n from\n aws_vpc_network_acl,\n jsonb_array_elements(entries) as att\n where\n att ->> 'Egress' = 'false' -- as per aws egress = false indicates the ingress\n and (\n att ->> 'CidrBlock' = '0.0.0.0/0'\n or att ->> 'Ipv6CidrBlock' = '::/0'\n )\n and att ->> 'RuleAction' = 'allow'\n and (\n (\n att ->> 'Protocol' = '-1' -- all traffic\n and att ->> 'PortRange' is null\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 22\n and (att -> 'PortRange' ->> 'To') :: int >= 22\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 3389\n and (att -> 'PortRange' ->> 'To') :: int >= 3389\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n )\n group by\n network_acl_id,\n region,\n account_id,\n tags\n order by\n network_acl_id,\n region,\n account_id,\n tags\n),\naws_vpc_network_acls as (\n select\n network_acl_id,\n tags,\n partition,\n region,\n account_id\n from\n aws_vpc_network_acl\n order by\n network_acl_id,\n region,\n account_id\n)\nselect\n 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id as resource,\n case\n when bad_rules.network_acl_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when bad_rules.network_acl_id is null then acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n else acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n end as reason\n \n \nfrom\n aws_vpc_network_acls as acl\n left join bad_rules on bad_rules.network_acl_id = acl.network_acl_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH bad_rules AS ( + SELECT + network_acl_id, + COUNT(*) AS num_bad_rules, + tags, + region, + account_id + FROM + aws_vpc_network_acl, + jsonb_array_elements(entries) AS att + WHERE + att ->> 'Egress' = 'false' + AND ( + att ->> 'CidrBlock' = '0.0.0.0/0' + OR att ->> 'Ipv6CidrBlock' = '::/0' + ) + AND att ->> 'RuleAction' = 'allow' + AND ( + ( + att ->> 'Protocol' = '-1' + AND att ->> 'PortRange' IS NULL + ) + OR ( + (att -> 'PortRange' ->> 'From') :: INT <= 22 + AND (att -> 'PortRange' ->> 'To') :: INT >= 22 + AND att ->> 'Protocol' IN ('6', '17') + ) + OR ( + (att -> 'PortRange' ->> 'From') :: INT <= 3389 + AND (att -> 'PortRange' ->> 'To') :: INT >= 3389 + AND att ->> 'Protocol' IN ('6', '17') + ) + ) + GROUP BY + network_acl_id, + region, + account_id, + tags + ORDER BY + network_acl_id, + region, + account_id, + tags + ), + aws_vpc_network_acls AS ( + SELECT + network_acl_id, + tags, + partition, + region, + account_id + FROM + aws_vpc_network_acl + ORDER BY + network_acl_id, + region, + account_id + ) + SELECT + 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id AS resource, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + aws_vpc_network_acls AS acl + LEFT JOIN + bad_rules ON bad_rules.network_acl_id = acl.network_acl_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.1 Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_1_22.yaml b/compliance/controls/pending/aws/aws_cis_v200_1_22.yaml old mode 100755 new mode 100644 index 2efa5d0ef..76d0efdac --- a/compliance/controls/pending/aws/aws_cis_v200_1_22.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_1_22.yaml @@ -1,13 +1,51 @@ +Description: AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment a user has sudo permissions, and can access the internet. So it is feasible to install file transfer software (for example) and move data from CloudShell to external internet servers. ID: aws_cis_v200_1_22 -Title: "1.22 Ensure access to AWSCloudShellFullAccess is restricted" -Description: "AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment a user has sudo permissions, and can access the internet. So it is feasible to install file transfer software (for example) and move data from CloudShell to external internet servers." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'User ' || title || ' has access to AWSCloudShellFullAccess.'\n else 'User ' || title || ' access to AWSCloudShellFullAccess is restricted.'\n end as reason\n \nfrom\n aws_iam_user\nunion\nselect\n arn as resource,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'Role ' || title || ' has access to AWSCloudShellFullAccess.'\n else 'Role ' || title || ' access to AWSCloudShellFullAccess is restricted.'\n end as reason\n \nfrom\n aws_iam_role\nunion\nselect\n arn as resource,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'Group ' || title || ' has access to AWSCloudShellFullAccess.'\n else 'Group ' || title || ' access to AWSCloudShellFullAccess is restricted.'\n end as reason\n \nfrom\n aws_iam_group;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' THEN 'User ' || title || ' has access to AWSCloudShellFullAccess.' + ELSE 'User ' || title || ' access to AWSCloudShellFullAccess is restricted.' + END AS reason + FROM + aws_iam_user + UNION + SELECT + arn AS resource, + CASE + WHEN attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' THEN 'Role ' || title || ' has access to AWSCloudShellFullAccess.' + ELSE 'Role ' || title || ' access to AWSCloudShellFullAccess is restricted.' + END AS reason + FROM + aws_iam_role + UNION + SELECT + arn AS resource, + CASE + WHEN attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' THEN 'Group ' || title || ' has access to AWSCloudShellFullAccess.' + ELSE 'Group ' || title || ' access to AWSCloudShellFullAccess is restricted.' + END AS reason + FROM + aws_iam_group; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.22 Ensure access to AWSCloudShellFullAccess is restricted \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_1_6.yaml b/compliance/controls/pending/aws/aws_cis_v200_1_6.yaml old mode 100755 new mode 100644 index 2ba864d7c..cba897a9e --- a/compliance/controls/pending/aws/aws_cis_v200_1_6.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_1_6.yaml @@ -1,13 +1,30 @@ +Description: The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root user account be protected with a hardware MFA. ID: aws_cis_v200_1_6 -Title: "1.6 Ensure hardware MFA is enabled for the 'root' user account" -Description: "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root user account be protected with a hardware MFA." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || s.partition || ':::' || s.account_id as resource,\n case\n when s.account_mfa_enabled and d.serial_number is null then 'ok'\n else 'alarm'\n end status,\n case\n when s.account_mfa_enabled = false then 'MFA not enabled for root account.'\n when d.serial_number is not null then 'MFA enabled for root account, but the MFA associated is a virtual device.'\n else 'Hardware MFA device enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary as s\n left join aws_iam_virtual_mfa_device as d on (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || s.partition || ':::' || s.account_id AS resource, + CASE + WHEN s.account_mfa_enabled AND d.serial_number IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN s.account_mfa_enabled = FALSE THEN 'MFA not enabled for root account.' + WHEN d.serial_number IS NOT NULL THEN 'MFA enabled for root account, but the MFA associated is a virtual device.' + ELSE 'Hardware MFA device enabled for root account.' + END reason + FROM + aws_iam_account_summary AS s + LEFT JOIN + aws_iam_virtual_mfa_device AS d + ON + (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.6 Ensure hardware MFA is enabled for the 'root' user account \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_1_9.yaml b/compliance/controls/pending/aws/aws_cis_v200_1_9.yaml old mode 100755 new mode 100644 index a4df7e8fb..3168f6950 --- a/compliance/controls/pending/aws/aws_cis_v200_1_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_1_9.yaml @@ -1,13 +1,30 @@ +Description: IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords. ID: aws_cis_v200_1_9 -Title: "1.9 Ensure IAM password policy prevents password reuse" -Description: "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when password_reuse_prevention >= 24 then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n when password_reuse_prevention is null then 'Password reuse prevention not set.'\n else 'Password reuse prevention set to ' || password_reuse_prevention || '.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN password_reuse_prevention >= 24 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN password_reuse_prevention IS NULL THEN 'Password reuse prevention not set.' + ELSE 'Password reuse prevention set to ' || password_reuse_prevention || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol + ON + a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.9 Ensure IAM password policy prevents password reuse \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_3_1.yaml b/compliance/controls/pending/aws/aws_cis_v200_3_1.yaml old mode 100755 new mode 100644 index 686e4bcbb..b28878461 --- a/compliance/controls/pending/aws/aws_cis_v200_3_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_3_1.yaml @@ -1,13 +1,41 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation). ID: aws_cis_v200_3_1 -Title: "3.1 Ensure CloudTrail is enabled in all regions" -Description: "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as e\n where\n (is_logging and is_multi_region_trail and e ->> 'ReadWriteType' = 'All')\n),\nadvanced_event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements_text(advanced_event_selectors) as a\n where\n -- when readOnly = true, then it is readOnly, when readOnly = false then it is writeOnly, if advanced_event_selectors is not null then it is both ReadWriteType\n (is_logging and is_multi_region_trail and advanced_event_selectors is not null and (not a like '%readOnly%'))\n)\nselect\n a.title as resource,\n case\n when d.account_id is null and ad.account_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when d.account_id is null and ad.account_id is null then 'cloudtrail disabled.'\n else 'cloudtrail enabled.'\n end as reason\n\n \nfrom\n aws_account as a\n left join event_selectors_trail_details as d on d.account_id = a.account_id\n left join advanced_event_selectors_trail_details as ad on ad.account_id = a.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH event_selectors_trail_details AS ( + SELECT DISTINCT account_id + FROM aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS e + WHERE is_logging AND is_multi_region_trail AND e ->> 'ReadWriteType' = 'All' + ), + advanced_event_selectors_trail_details AS ( + SELECT DISTINCT account_id + FROM aws_cloudtrail_trail, + jsonb_array_elements_text(advanced_event_selectors) AS a + WHERE is_logging + AND is_multi_region_trail + AND advanced_event_selectors IS NOT NULL + AND NOT a LIKE '%readOnly%' + ) + SELECT + a.title AS resource, + CASE + WHEN d.account_id IS NULL AND ad.account_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.account_id IS NULL AND ad.account_id IS NULL THEN 'cloudtrail disabled.' + ELSE 'cloudtrail enabled.' + END AS reason + FROM aws_account AS a + LEFT JOIN event_selectors_trail_details AS d ON d.account_id = a.account_id + LEFT JOIN advanced_event_selectors_trail_details AS ad ON ad.account_id = a.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.1 Ensure CloudTrail is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_1.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_1.yaml old mode 100755 new mode 100644 index 3246c3c6f..952782803 --- a/compliance/controls/pending/aws/aws_cis_v200_4_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_1.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. ID: aws_cis_v200_4_1 -Title: "4.1 Ensure unauthorized API calls are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\$\\.errorCode\\s*=\\s*\"\\*UnauthorizedOperation\".+\\$\\.errorCode\\s*=\\s*\"AccessDenied\\*\".+\\$\\.sourceIPAddress\\s*!=\\s*\"delivery.logs.amazonaws.com\".+\\$\\.eventName\\s*!=\\s*\"HeadBucket\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for unauthorized API calls.'\n else filter_name || ' forwards events for unauthorized API calls.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '$.errorCode\\s*=\\s*"\\*UnauthorizedOperation".+$.errorCode\\s*=\\s*"AccessDenied\\*".+$.sourceIPAddress\\s*!=\\s*"delivery.logs.amazonaws.com".+$.eventName\\s*!=\\s*"HeadBucket"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for unauthorized API calls.' + ELSE filter_name || ' forwards events for unauthorized API calls.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.1 Ensure unauthorized API calls are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_10.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_10.yaml old mode 100755 new mode 100644 index 22d6bfbd7..f7a8d7f71 --- a/compliance/controls/pending/aws/aws_cis_v200_4_10.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_10.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. ID: aws_cis_v200_4_10 -Title: "4.10 Ensure security group changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*AuthorizeSecurityGroupIngress.+\\$\\.eventName\\s*=\\s*AuthorizeSecurityGroupEgress.+\\$\\.eventName\\s*=\\s*RevokeSecurityGroupIngress.+\\$\\.eventName\\s*=\\s*RevokeSecurityGroupEgress.+\\$\\.eventName\\s*=\\s*CreateSecurityGroup.+\\$\\.eventName\\s*=\\s*DeleteSecurityGroup'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for security group changes.'\n else filter_name || ' forwards events for security group changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se->>'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*RevokeSecurityGroupIngress.+\$\.eventName\s*=\s*RevokeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for security group changes.' + ELSE filter_name || ' forwards events for security group changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.10 Ensure security group changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_11.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_11.yaml old mode 100755 new mode 100644 index eaf80e179..370f79660 --- a/compliance/controls/pending/aws/aws_cis_v200_4_11.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_11.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs. ID: aws_cis_v200_4_11 -Title: "4.11 Ensure Network Access Control Lists (NACL) changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateNetworkAcl.+\\$\\.eventName\\s*=\\s*CreateNetworkAclEntry.+\\$\\.eventName\\s*=\\s*DeleteNetworkAcl.+\\$\\.eventName\\s*=\\s*DeleteNetworkAclEntry.+\\$\\.eventName\\s*=\\s*ReplaceNetworkAclEntry.+\\$\\.eventName\\s*=\\s*ReplaceNetworkAclAssociation'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for changes to NACLs.'\n else filter_name || ' forwards events for changes to NACLs.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\\s*\\$.eventName\\s*=\\s*CreateNetworkAcl.+\\$.eventName\\s*=\\s*CreateNetworkAclEntry.+\\$.eventName\\s*=\\s*DeleteNetworkAcl.+\\$.eventName\\s*=\\s*DeleteNetworkAclEntry.+\\$.eventName\\s*=\\s*ReplaceNetworkAclEntry.+\\$.eventName\\s*=\\s*ReplaceNetworkAclAssociation' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for changes to NACLs.' + ELSE filter_name || ' forwards events for changes to NACLs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.11 Ensure Network Access Control Lists (NACL) changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_13.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_13.yaml old mode 100755 new mode 100644 index d305e3c0b..e55a1c277 --- a/compliance/controls/pending/aws/aws_cis_v200_4_13.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_13.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables. ID: aws_cis_v200_4_13 -Title: "4.13 Ensure route table changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateRoute.+\\$\\.eventName\\s*=\\s*CreateRouteTable.+\\$\\.eventName\\s*=\\s*ReplaceRoute.+\\$\\.eventName\\s*=\\s*ReplaceRouteTableAssociation.+\\$\\.eventName\\s*=\\s*DeleteRouteTable.+\\$\\.eventName\\s*=\\s*DeleteRoute.+\\$\\.eventName\\s*=\\s*DisassociateRouteTable'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for route table changes.'\n else filter_name || ' forwards events for route table changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*ReplaceRoute.+\$\.eventName\s*=\s*ReplaceRouteTableAssociation.+\$\.eventName\s*=\s*DeleteRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for route table changes.' + ELSE filter_name || ' forwards events for route table changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.13 Ensure route table changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_14.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_14.yaml old mode 100755 new mode 100644 index 9718093d7..1cd562482 --- a/compliance/controls/pending/aws/aws_cis_v200_4_14.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_14.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs. ID: aws_cis_v200_4_14 -Title: "4.14 Ensure VPC changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateVpc.+\\$\\.eventName\\s*=\\s*DeleteVpc.+\\$\\.eventName\\s*=\\s*ModifyVpcAttribute.+\\$\\.eventName\\s*=\\s*AcceptVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*CreateVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*DeleteVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*RejectVpcPeeringConnection.+\\$\\.eventName\\s*=\\s*AttachClassicLinkVpc.+\\$\\.eventName\\s*=\\s*DetachClassicLinkVpc.+\\$\\.eventName\\s*=\\s*DisableVpcClassicLink.+\\$\\.eventName\\s*=\\s*EnableVpcClassicLink'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for VPC changes.'\n else filter_name || ' forwards events for VPC changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateVpc.+\s*\$\.eventName\s*=\s*DeleteVpc.+\s*\$\.eventName\s*=\s*ModifyVpcAttribute.+\s*\$\.eventName\s*=\s*AcceptVpcPeeringConnection.+\s*\$\.eventName\s*=\s*CreateVpcPeeringConnection.+\s*\$\.eventName\s*=\s*DeleteVpcPeeringConnection.+\s*\$\.eventName\s*=\s*RejectVpcPeeringConnection.+\s*\$\.eventName\s*=\s*AttachClassicLinkVpc.+\s*\$\.eventName\s*=\s*DetachClassicLinkVpc.+\s*\$\.eventName\s*=\s*DisableVpcClassicLink.+\s*\$\.eventName\s*=\s*EnableVpcClassicLink' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for VPC changes.' + ELSE filter_name || ' forwards events for VPC changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.14 Ensure VPC changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_15.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_15.yaml old mode 100755 new mode 100644 index 5d2aba4b8..1b32dfb25 --- a/compliance/controls/pending/aws/aws_cis_v200_4_15.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_15.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account. ID: aws_cis_v200_4_15 -Title: "4.15 Ensure AWS Organizations changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*organizations.amazonaws.com.+\\$\\.eventName\\s*=\\s*\"?AcceptHandshake\"?.+\\$\\.eventName\\s*=\\s*\"?AttachPolicy\"?.+\\$\\.eventName\\s*=\\s*\"?CreateAccount\"?.+\\$\\.eventName\\s*=\\s*\"?CreateOrganizationalUnit\"?.+\\$\\.eventName\\s*=\\s*\"?CreatePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DeclineHandshake\"?.+\\$\\.eventName\\s*=\\s*\"?DeleteOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?DeleteOrganizationalUnit\"?.+\\$\\.eventName\\s*=\\s*\"?DeletePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DetachPolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DisablePolicyType\"?.+\\$\\.eventName\\s*=\\s*\"?EnablePolicyType\"?.+\\$\\.eventName\\s*=\\s*\"?InviteAccountToOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?LeaveOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?MoveAccount\"?.+\\$\\.eventName\\s*=\\s*\"?RemoveAccountFromOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?UpdatePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?UpdateOrganizationalUnit\"?'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exists for AWS Organizations changes.'\n else filter_name || ' forwards relevant events for AWS Organizations changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*organizations.amazonaws.com.+\$.eventName\s*=\s*"?AcceptHandshake"?.+\$.eventName\s*=\s*"?AttachPolicy"?.+\$.eventName\s*=\s*"?CreateAccount"?.+\$.eventName\s*=\s*"?CreateOrganizationalUnit"?.+\$.eventName\s*=\s*"?CreatePolicy"?.+\$.eventName\s*=\s*"?DeclineHandshake"?.+\$.eventName\s*=\s*"?DeleteOrganization"?.+\$.eventName\s*=\s*"?DeleteOrganizationalUnit"?.+\$.eventName\s*=\s*"?DeletePolicy"?.+\$.eventName\s*=\s*"?DetachPolicy"?.+\$.eventName\s*=\s*"?DisablePolicyType"?.+\$.eventName\s*=\s*"?EnablePolicyType"?.+\$.eventName\s*=\s*"?InviteAccountToOrganization"?.+\$.eventName\s*=\s*"?LeaveOrganization"?.+\$.eventName\s*=\s*"?MoveAccount"?.+\$.eventName\s*=\s*"?RemoveAccountFromOrganization"?.+\$.eventName\s*=\s*"?UpdatePolicy"?.+\$.eventName\s*=\s*"?UpdateOrganizationalUnit"?' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exists for AWS Organizations changes.' + ELSE filter_name || ' forwards relevant events for AWS Organizations changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.15 Ensure AWS Organizations changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_16.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_16.yaml old mode 100755 new mode 100644 index 0566e45a9..d790aaeaa --- a/compliance/controls/pending/aws/aws_cis_v200_4_16.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_16.yaml @@ -1,13 +1,32 @@ +Description: Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products. ID: aws_cis_v200_4_16 -Title: "4.16 Ensure AWS Security Hub is enabled" -Description: "Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource,\n case\n when r.region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) then 'skip'\n -- Skip any regions that are disabled in the account.\n when r.opt_in_status = 'not-opted-in' then 'skip'\n when h.hub_arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when r.region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) then r.region || ' region not supported.'\n when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.'\n when h.hub_arn is not null then 'Security Hub enabled in ' || r.region || '.'\n else 'Security Hub disabled in ' || r.region || '.'\n end as reason\n \nfrom\n aws_region as r\n left join aws_securityhub_hub as h on r.account_id = h.account_id and r.name = h.region;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + CASE + WHEN r.region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) THEN 'skip' + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN h.hub_arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.region = ANY(ARRAY['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) THEN r.region || ' region not supported.' + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN h.hub_arn IS NOT NULL THEN 'Security Hub enabled in ' || r.region || '.' + ELSE 'Security Hub disabled in ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN + aws_securityhub_hub AS h + ON r.account_id = h.account_id AND r.name = h.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.16 Ensure AWS Security Hub is enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_2.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_2.yaml old mode 100755 new mode 100644 index 81b935a77..6214c7da3 --- a/compliance/controls/pending/aws/aws_cis_v200_4_2.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_2.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. ID: aws_cis_v200_4_2 -Title: "4.2 Ensure management console sign-in without MFA is monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\(\\s*\\$\\.eventName\\s*=\\s*\"ConsoleLogin\"\\)\\s+&&\\s+\\(\\s*\\$.additionalEventData\\.MFAUsed\\s*!=\\s*\"Yes\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console sign-in without MFA.'\n else filter_name || ' forwards events for console sign-in without MFA.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\(\s*\$\.eventName\s*=\s*"ConsoleLogin"\)\s+&&\s+\(\s*\$.additionalEventData\.MFAUsed\s*!=\s*"Yes"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console sign-in without MFA.' + ELSE filter_name || ' forwards events for console sign-in without MFA.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.2 Ensure management console sign-in without MFA is monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_4.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_4.yaml old mode 100755 new mode 100644 index fcf80a66c..4dc8b63d0 --- a/compliance/controls/pending/aws/aws_cis_v200_4_4.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_4.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes made to Identity and Access Management (IAM) policies. ID: aws_cis_v200_4_4 -Title: "4.4 Ensure IAM policy changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*DeleteGroupPolicy.+\\$\\.eventName\\s*=\\s*DeleteRolePolicy.+\\$\\.eventName\\s*=\\s*DeleteUserPolicy.+\\$\\.eventName\\s*=\\s*PutGroupPolicy.+\\$\\.eventName\\s*=\\s*PutRolePolicy.+\\$\\.eventName\\s*=\\s*PutUserPolicy.+\\$\\.eventName\\s*=\\s*CreatePolicy.+\\$\\.eventName\\s*=\\s*DeletePolicy.+\\$\\.eventName\\s*=\\s*CreatePolicyVersion.+\\$\\.eventName\\s*=\\s*DeletePolicyVersion.+\\$\\.eventName\\s*=\\s*AttachRolePolicy.+\\$\\.eventName\\s*=\\s*DetachRolePolicy.+\\$\\.eventName\\s*=\\s*AttachUserPolicy.+\\$\\.eventName\\s*=\\s*DetachUserPolicy.+\\$\\.eventName\\s*=\\s*AttachGroupPolicy.+\\$\\.eventName\\s*=\\s*DetachGroupPolicy'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for IAM policy changes.'\n else filter_name || ' forwards events for IAM policy changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*DeleteGroupPolicy.+\$\.eventName\s*=\s*DeleteRolePolicy.+\$\.eventName\s*=\s*DeleteUserPolicy.+\$\.eventName\s*=\s*PutGroupPolicy.+\$\.eventName\s*=\s*PutRolePolicy.+\$\.eventName\s*=\s*PutUserPolicy.+\$\.eventName\s*=\s*CreatePolicy.+\$\.eventName\s*=\s*DeletePolicy.+\$\.eventName\s*=\s*CreatePolicyVersion.+\$\.eventName\s*=\s*DeletePolicyVersion.+\$\.eventName\s*=\s*AttachRolePolicy.+\$\.eventName\s*=\s*DetachRolePolicy.+\$\.eventName\s*=\s*AttachUserPolicy.+\$\.eventName\s*=\s*DetachUserPolicy.+\$\.eventName\s*=\s*AttachGroupPolicy.+\$\.eventName\s*=\s*DetachGroupPolicy' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for IAM policy changes.' + ELSE filter_name || ' forwards events for IAM policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.4 Ensure IAM policy changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_5.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_5.yaml old mode 100755 new mode 100644 index 9e9ad7979..1104c1b17 --- a/compliance/controls/pending/aws/aws_cis_v200_4_5.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_5.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, where metric filters and alarms can be established. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies. ID: aws_cis_v200_4_5 -Title: "4.5 Ensure CloudTrail configuration changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, where metric filters and alarms can be established. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateTrail.+\\$\\.eventName\\s*=\\s*UpdateTrail.+\\$\\.eventName\\s*=\\s*DeleteTrail.+\\$\\.eventName\\s*=\\s*StartLogging.+\\$\\.eventName\\s*=\\s*StopLogging'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for CloudTrail configuration changes.'\n else filter_name || ' forwards events for CloudTrail configuration changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateTrail.+\$.eventName\s*=\s*UpdateTrail.+\$.eventName\s*=\s*DeleteTrail.+\$.eventName\s*=\s*StartLogging.+\$.eventName\s*=\s*StopLogging' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for CloudTrail configuration changes.' + ELSE filter_name || ' forwards events for CloudTrail configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.5 Ensure CloudTrail configuration changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_7.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_7.yaml old mode 100755 new mode 100644 index d57cf4187..eefe3bd67 --- a/compliance/controls/pending/aws/aws_cis_v200_4_7.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_7.yaml @@ -1,13 +1,90 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion. ID: aws_cis_v200_4_7 -Title: "4.7 Ensure disabling or scheduled deletion of customer created CMKs is monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*kms.amazonaws.com.+\\$\\.eventName\\s*=\\s*DisableKey.+\\$\\.eventName\\s*=\\s*ScheduleKeyDeletion'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for disabling/deletion of CMKs.'\n else filter_name || ' forwards events for disabling/deletion of CMKs.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*kms.amazonaws.com.+\$.eventName\s*=\s*DisableKey.+\$.eventName\s*=\s*ScheduleKeyDeletion' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for disabling/deletion of CMKs.' + ELSE filter_name || ' forwards events for disabling/deletion of CMKs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.7 Ensure disabling or scheduled deletion of customer created CMKs is monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_8.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_8.yaml old mode 100755 new mode 100644 index 85b71dd83..17b178da7 --- a/compliance/controls/pending/aws/aws_cis_v200_4_8.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_8.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies. ID: aws_cis_v200_4_8 -Title: "4.8 Ensure S3 bucket policy changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*s3.amazonaws.com.+\\$\\.eventName\\s*=\\s*PutBucketAcl.+\\$\\.eventName\\s*=\\s*PutBucketPolicy.+\\$\\.eventName\\s*=\\s*PutBucketCors.+\\$\\.eventName\\s*=\\s*PutBucketLifecycle.+\\$\\.eventName\\s*=\\s*PutBucketReplication.+\\$\\.eventName\\s*=\\s*DeleteBucketPolicy.+\\$\\.eventName\\s*=\\s*DeleteBucketCors.+\\$\\.eventName\\s*=\\s*DeleteBucketLifecycle.+\\$\\.eventName\\s*=\\s*DeleteBucketReplication'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for S3 bucket policy changes.'\n else filter_name || ' forwards events for S3 bucket policy changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*s3.amazonaws.com.+\$\.eventName\s*=\s*PutBucketAcl.+\$\.eventName\s*=\s*PutBucketPolicy.+\$\.eventName\s*=\s*PutBucketCors.+\$\.eventName\s*=\s*PutBucketLifecycle.+\$\.eventName\s*=\s*PutBucketReplication.+\$\.eventName\s*=\s*DeleteBucketPolicy.+\$\.eventName\s*=\s*DeleteBucketCors.+\$\.eventName\s*=\s*DeleteBucketLifecycle.+\$\.eventName\s*=\s*DeleteBucketReplication' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for S3 bucket policy changes.' + ELSE filter_name || ' forwards events for S3 bucket policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.8 Ensure S3 bucket policy changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_4_9.yaml b/compliance/controls/pending/aws/aws_cis_v200_4_9.yaml old mode 100755 new mode 100644 index f30340564..1e56222f0 --- a/compliance/controls/pending/aws/aws_cis_v200_4_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_4_9.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to AWS Config's configurations. ID: aws_cis_v200_4_9 -Title: "4.9 Ensure AWS Config configuration changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to AWS Config's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*config.amazonaws.com.+\\$\\.eventName\\s*=\\s*StopConfigurationRecorder.+\\$\\.eventName\\s*=\\s*DeleteDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutConfigurationRecorder'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for AWS Config configuration changes.'\n else filter_name || ' forwards events for AWS Config configuration changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*config.amazonaws.com.+\$.eventName\s*=\s*StopConfigurationRecorder.+\$.eventName\s*=\s*DeleteDeliveryChannel.+\$.eventName\s*=\s*PutDeliveryChannel.+\$.eventName\s*=\s*PutConfigurationRecorder' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for AWS Config configuration changes.' + ELSE filter_name || ' forwards events for AWS Config configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.9 Ensure AWS Config configuration changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v200_5_1.yaml b/compliance/controls/pending/aws/aws_cis_v200_5_1.yaml old mode 100755 new mode 100644 index 4cd54df24..708efb045 --- a/compliance/controls/pending/aws/aws_cis_v200_5_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v200_5_1.yaml @@ -1,13 +1,84 @@ +Description: The Network Access Control List (NACL) function provides stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389, using either the TCP (6), UDP (17), or ALL (-1) protocols. ID: aws_cis_v200_5_1 -Title: "5.1 Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389, using either the TCP (6), UDP (17) or ALL (-1) protocols." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bad_rules as (\n select\n network_acl_id,\n count(*) as num_bad_rules,\n tags,\n region,\n account_id\n from\n aws_vpc_network_acl,\n jsonb_array_elements(entries) as att\n where\n att ->> 'Egress' = 'false' -- as per aws egress = false indicates the ingress\n and (\n att ->> 'CidrBlock' = '0.0.0.0/0'\n or att ->> 'Ipv6CidrBlock' = '::/0'\n )\n and att ->> 'RuleAction' = 'allow'\n and (\n (\n att ->> 'Protocol' = '-1' -- all traffic\n and att ->> 'PortRange' is null\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 22\n and (att -> 'PortRange' ->> 'To') :: int >= 22\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 3389\n and (att -> 'PortRange' ->> 'To') :: int >= 3389\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n )\n group by\n network_acl_id,\n region,\n account_id,\n tags\n order by\n network_acl_id,\n region,\n account_id,\n tags\n),\naws_vpc_network_acls as (\n select\n network_acl_id,\n tags,\n partition,\n region,\n account_id\n from\n aws_vpc_network_acl\n order by\n network_acl_id,\n region,\n account_id\n)\nselect\n 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id as resource,\n case\n when bad_rules.network_acl_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when bad_rules.network_acl_id is null then acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n else acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n end as reason\n \n \nfrom\n aws_vpc_network_acls as acl\n left join bad_rules on bad_rules.network_acl_id = acl.network_acl_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH bad_rules AS ( + SELECT + network_acl_id, + COUNT(*) AS num_bad_rules, + tags, + region, + account_id + FROM + aws_vpc_network_acl, + jsonb_array_elements(entries) AS att + WHERE + att ->> 'Egress' = 'false' + AND ( + att ->> 'CidrBlock' = '0.0.0.0/0' + OR att ->> 'Ipv6CidrBlock' = '::/0' + ) + AND att ->> 'RuleAction' = 'allow' + AND ( + ( + att ->> 'Protocol' = '-1' + AND att ->> 'PortRange' IS NULL + ) + OR ( + (att -> 'PortRange' ->> 'From')::int <= 22 + AND (att -> 'PortRange' ->> 'To')::int >= 22 + AND att ->> 'Protocol' IN ('6', '17') + ) + OR ( + (att -> 'PortRange' ->> 'From')::int <= 3389 + AND (att -> 'PortRange' ->> 'To')::int >= 3389 + AND att ->> 'Protocol' IN ('6', '17') + ) + ) + GROUP BY + network_acl_id, + region, + account_id, + tags + ORDER BY + network_acl_id, + region, + account_id, + tags + ), + aws_vpc_network_acls AS ( + SELECT + network_acl_id, + tags, + partition, + region, + account_id + FROM + aws_vpc_network_acl + ORDER BY + network_acl_id, + region, + account_id + ) + SELECT + 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id AS resource, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + aws_vpc_network_acls AS acl + LEFT JOIN bad_rules ON bad_rules.network_acl_id = acl.network_acl_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.1 Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_1_13.yaml b/compliance/controls/pending/aws/aws_cis_v300_1_13.yaml old mode 100755 new mode 100644 index 9a6efe8eb..8b5977704 --- a/compliance/controls/pending/aws/aws_cis_v300_1_13.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_1_13.yaml @@ -1,13 +1,33 @@ +Description: Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK). ID: aws_cis_v300_1_13 -Title: "1.13 Ensure there is only one active access key available for any single IAM user" -Description: "Access keys are long-term credentials for an IAM user or the AWS account root user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n u.arn as resource,\n case\n when count(k.*) > 1 then 'alarm'\n else 'ok'\n end as status,\n u.name || ' has ' || count(k.*) || ' active access key(s).' as reason\n \n \nfrom\n aws_iam_user as u\n left join aws_iam_access_key as k on u.name = k.user_name and u.account_id = k.account_id\nwhere\n k.status = 'Active' or k.status is null\ngroup by\n u.arn,\n u.name,\n u.account_id,\n u.tags,\n u._ctx;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + u.arn AS resource, + CASE + WHEN COUNT(k.*) > 1 THEN 'alarm' + ELSE 'ok' + END AS status, + u.name || ' has ' || COUNT(k.*) || ' active access key(s).' AS reason + FROM + aws_iam_user AS u + LEFT JOIN aws_iam_access_key AS k + ON u.name = k.user_name + AND u.account_id = k.account_id + WHERE + k.status = 'Active' OR k.status IS NULL + GROUP BY + u.arn, + u.name, + u.account_id, + u.tags, + u._ctx; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.13 Ensure there is only one active access key available for any single IAM user \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_1_22.yaml b/compliance/controls/pending/aws/aws_cis_v300_1_22.yaml old mode 100755 new mode 100644 index b19372a42..f8b0dfd5d --- a/compliance/controls/pending/aws/aws_cis_v300_1_22.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_1_22.yaml @@ -1,13 +1,55 @@ +Description: AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment a user has sudo permissions, and can access the internet. So it is feasible to install file transfer software (for example) and move data from CloudShell to external internet servers. ID: aws_cis_v300_1_22 -Title: "1.22 Ensure access to AWSCloudShellFullAccess is restricted" -Description: "AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment a user has sudo permissions, and can access the internet. So it is feasible to install file transfer software (for example) and move data from CloudShell to external internet servers." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'User ' || title || ' has access to AWSCloudShellFullAccess.'\n else 'User ' || title || ' access to AWSCloudShellFullAccess is restricted.'\n end as reason\n \nfrom\n aws_iam_user\nunion\nselect\n arn as resource,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'Role ' || title || ' has access to AWSCloudShellFullAccess.'\n else 'Role ' || title || ' access to AWSCloudShellFullAccess is restricted.'\n end as reason\n \nfrom\n aws_iam_role\nunion\nselect\n arn as resource,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when attached_policy_arns @> '[\"arn:aws:iam::aws:policy/AWSCloudShellFullAccess\"]' then 'Group ' || title || ' has access to AWSCloudShellFullAccess.'\n else 'Group ' || title || ' access to AWSCloudShellFullAccess is restricted.'\n end as reason\n \nfrom\n aws_iam_group;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' THEN 'User ' || title || ' has access to AWSCloudShellFullAccess.' + ELSE 'User ' || title || ' access to AWSCloudShellFullAccess is restricted.' + END AS reason + FROM + aws_iam_user + + UNION + + SELECT + arn AS resource, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' THEN 'Role ' || title || ' has access to AWSCloudShellFullAccess.' + ELSE 'Role ' || title || ' access to AWSCloudShellFullAccess is restricted.' + END AS reason + FROM + aws_iam_role + + UNION + + SELECT + arn AS resource, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN attached_policy_arns @> '["arn:aws:iam::aws:policy/AWSCloudShellFullAccess"]' THEN 'Group ' || title || ' has access to AWSCloudShellFullAccess.' + ELSE 'Group ' || title || ' access to AWSCloudShellFullAccess is restricted.' + END AS reason + FROM + aws_iam_group; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.22 Ensure access to AWSCloudShellFullAccess is restricted \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_1_9.yaml b/compliance/controls/pending/aws/aws_cis_v300_1_9.yaml old mode 100755 new mode 100644 index 74268a615..549541ac2 --- a/compliance/controls/pending/aws/aws_cis_v300_1_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_1_9.yaml @@ -1,13 +1,27 @@ +Description: IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords. ID: aws_cis_v300_1_9 -Title: "1.9 Ensure IAM password policy prevents password reuse" -Description: "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when password_reuse_prevention >= 24 then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n when password_reuse_prevention is null then 'Password reuse prevention not set.'\n else 'Password reuse prevention set to ' || password_reuse_prevention || '.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN password_reuse_prevention >= 24 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN password_reuse_prevention IS NULL THEN 'Password reuse prevention not set.' + ELSE 'Password reuse prevention set to ' || password_reuse_prevention || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1.9 Ensure IAM password policy prevents password reuse \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_2_1_4.yaml b/compliance/controls/pending/aws/aws_cis_v300_2_1_4.yaml old mode 100755 new mode 100644 index bae18a842..956c572a2 --- a/compliance/controls/pending/aws/aws_cis_v300_2_1_4.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_2_1_4.yaml @@ -1,13 +1,42 @@ +Description: Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principle with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, Block public access (bucket settings) prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, Block public access (account settings) prevents all buckets, and contained objects, from becoming publicly accessible across the entire account. ID: aws_cis_v300_2_1_4 -Title: "2.1.4 Ensure that S3 Buckets are configured with 'Block public access (bucket settings)'" -Description: "Amazon S3 provides Block public access (bucket settings) and Block public access (account settings) to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principle with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, Block public access (bucket settings) prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, Block public access (account settings) prevents all buckets, and contained objects, from becoming publicly accessible across the entire account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when (bucket.block_public_acls or s3account.block_public_acls)\n and (bucket.block_public_policy or s3account.block_public_policy)\n and (bucket.ignore_public_acls or s3account.ignore_public_acls)\n and (bucket.restrict_public_buckets or s3account.restrict_public_buckets)\n then 'ok'\n else 'alarm'\n end as status,\n case\n when (bucket.block_public_acls or s3account.block_public_acls)\n and (bucket.block_public_policy or s3account.block_public_policy)\n and (bucket.ignore_public_acls or s3account.ignore_public_acls)\n and (bucket.restrict_public_buckets or s3account.restrict_public_buckets)\n then name || ' all public access blocks enabled.'\n else name || ' not enabled for: ' ||\n concat_ws(', ',\n case when not (bucket.block_public_acls or s3account.block_public_acls) then 'block_public_acls' end,\n case when not (bucket.block_public_policy or s3account.block_public_policy) then 'block_public_policy' end,\n case when not (bucket.ignore_public_acls or s3account.ignore_public_acls) then 'ignore_public_acls' end,\n case when not (bucket.restrict_public_buckets or s3account.restrict_public_buckets) then 'restrict_public_buckets' end\n ) || '.'\n end as reason\n \n \nfrom\n aws_s3_bucket as bucket,\n aws_s3_account_settings as s3account\nwhere\n s3account.account_id = bucket.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (bucket.block_public_acls OR s3account.block_public_acls) + AND (bucket.block_public_policy OR s3account.block_public_policy) + AND (bucket.ignore_public_acls OR s3account.ignore_public_acls) + AND (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) + THEN name || ' all public access blocks enabled.' + ELSE name || ' not enabled for: ' || + CONCAT_WS(', ', + CASE WHEN NOT (bucket.block_public_acls OR s3account.block_public_acls) THEN 'block_public_acls' END, + CASE WHEN NOT (bucket.block_public_policy OR s3account.block_public_policy) THEN 'block_public_policy' END, + CASE WHEN NOT (bucket.ignore_public_acls OR s3account.ignore_public_acls) THEN 'ignore_public_acls' END, + CASE WHEN NOT (bucket.restrict_public_buckets OR s3account.restrict_public_buckets) THEN 'restrict_public_buckets' END + ) || '.' + END AS reason + FROM + aws_s3_bucket AS bucket, + aws_s3_account_settings AS s3account + WHERE + s3account.account_id = bucket.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2.1.4 Ensure that S3 Buckets are configured with 'Block public access (bucket settings)' \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_3_1.yaml b/compliance/controls/pending/aws/aws_cis_v300_3_1.yaml old mode 100755 new mode 100644 index ac10faef0..93fdd8e75 --- a/compliance/controls/pending/aws/aws_cis_v300_3_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_3_1.yaml @@ -1,13 +1,45 @@ +Description: AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation). ID: aws_cis_v300_3_1 -Title: "3.1 Ensure CloudTrail is enabled in all regions" -Description: "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) as e\n where\n (is_logging and is_multi_region_trail and e ->> 'ReadWriteType' = 'All')\n),\nadvanced_event_selectors_trail_details as (\n select\n distinct account_id\n from\n aws_cloudtrail_trail,\n jsonb_array_elements_text(advanced_event_selectors) as a\n where\n -- when readOnly = true, then it is readOnly, when readOnly = false then it is writeOnly, if advanced_event_selectors is not null then it is both ReadWriteType\n (is_logging and is_multi_region_trail and advanced_event_selectors is not null and (not a like '%readOnly%'))\n)\nselect\n a.title as resource,\n case\n when d.account_id is null and ad.account_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when d.account_id is null and ad.account_id is null then 'cloudtrail disabled.'\n else 'cloudtrail enabled.'\n end as reason\n\n \nfrom\n aws_account as a\n left join event_selectors_trail_details as d on d.account_id = a.account_id\n left join advanced_event_selectors_trail_details as ad on ad.account_id = a.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH event_selectors_trail_details AS ( + SELECT + DISTINCT account_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) AS e + WHERE + (is_logging AND is_multi_region_trail AND e ->> 'ReadWriteType' = 'All') + ), + advanced_event_selectors_trail_details AS ( + SELECT + DISTINCT account_id + FROM + aws_cloudtrail_trail, + jsonb_array_elements_text(advanced_event_selectors) AS a + WHERE + (is_logging AND is_multi_region_trail AND advanced_event_selectors IS NOT NULL AND (NOT a LIKE '%readOnly%')) + ) + SELECT + a.title AS resource, + CASE + WHEN d.account_id IS NULL AND ad.account_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN d.account_id IS NULL AND ad.account_id IS NULL THEN 'cloudtrail disabled.' + ELSE 'cloudtrail enabled.' + END AS reason + FROM + aws_account AS a + LEFT JOIN event_selectors_trail_details AS d ON d.account_id = a.account_id + LEFT JOIN advanced_event_selectors_trail_details AS ad ON ad.account_id = a.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.1 Ensure CloudTrail is enabled in all regions \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_3_7.yaml b/compliance/controls/pending/aws/aws_cis_v300_3_7.yaml old mode 100755 new mode 100644 index 5d5ff5478..f8abf42fb --- a/compliance/controls/pending/aws/aws_cis_v300_3_7.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_3_7.yaml @@ -1,13 +1,53 @@ +Description: VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet `Rejects` for VPCs. ID: aws_cis_v300_3_7 -Title: "3.7 Ensure VPC flow logging is enabled in all VPCs" -Description: "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet `Rejects` for VPCs." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vpcs as (\n select\n arn,\n account_id,\n region,\n owner_id,\n vpc_id,\n tags,\n _ctx\n from\n aws_vpc\n order by\n vpc_id\n),\nflowlogs as (\n select\n resource_id,\n account_id,\n region\n from\n aws_vpc_flow_log\n order by\n resource_id\n)\nselect\n v.arn as resource,\n case\n when v.account_id <> v.owner_id then 'skip'\n when f.resource_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when v.account_id <> v.owner_id then v.vpc_id || ' is a shared VPC.'\n when f.resource_id is not null then v.vpc_id || ' flow logging enabled.'\n else v.vpc_id || ' flow logging disabled.'\n end as reason\n \n \nfrom\n vpcs as v\n left join flowlogs as f on v.vpc_id = f.resource_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH vpcs AS ( + SELECT + arn, + account_id, + region, + owner_id, + vpc_id, + tags, + _ctx + FROM + aws_vpc + ORDER BY + vpc_id + ), + flowlogs AS ( + SELECT + resource_id, + account_id, + region + FROM + aws_vpc_flow_log + ORDER BY + resource_id + ) + SELECT + v.arn AS resource, + CASE + WHEN v.account_id <> v.owner_id THEN 'skip' + WHEN f.resource_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.account_id <> v.owner_id THEN v.vpc_id || ' is a shared VPC.' + WHEN f.resource_id IS NOT NULL THEN v.vpc_id || ' flow logging enabled.' + ELSE v.vpc_id || ' flow logging disabled.' + END AS reason + FROM + vpcs AS v + LEFT JOIN flowlogs AS f + ON v.vpc_id = f.resource_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3.7 Ensure VPC flow logging is enabled in all VPCs \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_1.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_1.yaml old mode 100755 new mode 100644 index 7e92e14fd..ffa52c045 --- a/compliance/controls/pending/aws/aws_cis_v300_4_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_1.yaml @@ -1,13 +1,90 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. ID: aws_cis_v300_4_1 -Title: "4.1 Ensure unauthorized API calls are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\$\\.errorCode\\s*=\\s*\"\\*UnauthorizedOperation\".+\\$\\.errorCode\\s*=\\s*\"AccessDenied\\*\".+\\$\\.sourceIPAddress\\s*!=\\s*\"delivery.logs.amazonaws.com\".+\\$\\.eventName\\s*!=\\s*\"HeadBucket\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for unauthorized API calls.'\n else filter_name || ' forwards events for unauthorized API calls.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '$.errorCode\\s*=\\s*"*UnauthorizedOperation".+$.errorCode\\s*=\\s*"AccessDenied*".+$.sourceIPAddress\\s*!=\\s*"delivery.logs.amazonaws.com".+$.eventName\\s*!=\\s*"HeadBucket"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for unauthorized API calls.' + ELSE filter_name || ' forwards events for unauthorized API calls.' + END AS reason + + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.1 Ensure unauthorized API calls are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_10.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_10.yaml old mode 100755 new mode 100644 index 96a396fb5..71f638de3 --- a/compliance/controls/pending/aws/aws_cis_v300_4_10.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_10.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. ID: aws_cis_v300_4_10 -Title: "4.10 Ensure security group changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*AuthorizeSecurityGroupIngress.+\\$\\.eventName\\s*=\\s*AuthorizeSecurityGroupEgress.+\\$\\.eventName\\s*=\\s*RevokeSecurityGroupIngress.+\\$\\.eventName\\s*=\\s*RevokeSecurityGroupEgress.+\\$\\.eventName\\s*=\\s*CreateSecurityGroup.+\\$\\.eventName\\s*=\\s*DeleteSecurityGroup'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for security group changes.'\n else filter_name || ' forwards events for security group changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$.eventName\s*=\s*RevokeSecurityGroupIngress.+\$.eventName\s*=\s*RevokeSecurityGroupEgress.+\$.eventName\s*=\s*CreateSecurityGroup.+\$.eventName\s*=\s*DeleteSecurityGroup' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for security group changes.' + ELSE filter_name || ' forwards events for security group changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.10 Ensure security group changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_13.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_13.yaml old mode 100755 new mode 100644 index 0fa7511ee..93e0ad1b3 --- a/compliance/controls/pending/aws/aws_cis_v300_4_13.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_13.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables. ID: aws_cis_v300_4_13 -Title: "4.13 Ensure route table changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateRoute.+\\$\\.eventName\\s*=\\s*CreateRouteTable.+\\$\\.eventName\\s*=\\s*ReplaceRoute.+\\$\\.eventName\\s*=\\s*ReplaceRouteTableAssociation.+\\$\\.eventName\\s*=\\s*DeleteRouteTable.+\\$\\.eventName\\s*=\\s*DeleteRoute.+\\$\\.eventName\\s*=\\s*DisassociateRouteTable'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for route table changes.'\n else filter_name || ' forwards events for route table changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateRoute.+\$.eventName\s*=\s*CreateRouteTable.+\$.eventName\s*=\s*ReplaceRoute.+\$.eventName\s*=\s*ReplaceRouteTableAssociation.+\$.eventName\s*=\s*DeleteRouteTable.+\$.eventName\s*=\s*DeleteRoute.+\$.eventName\s*=\s*DisassociateRouteTable' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for route table changes.' + ELSE filter_name || ' forwards events for route table changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.13 Ensure route table changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_15.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_15.yaml old mode 100755 new mode 100644 index 8386552ea..b43be5fb0 --- a/compliance/controls/pending/aws/aws_cis_v300_4_15.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_15.yaml @@ -1,13 +1,91 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account. ID: aws_cis_v300_4_15 -Title: "4.15 Ensure AWS Organizations changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*organizations.amazonaws.com.+\\$\\.eventName\\s*=\\s*\"?AcceptHandshake\"?.+\\$\\.eventName\\s*=\\s*\"?AttachPolicy\"?.+\\$\\.eventName\\s*=\\s*\"?CreateAccount\"?.+\\$\\.eventName\\s*=\\s*\"?CreateOrganizationalUnit\"?.+\\$\\.eventName\\s*=\\s*\"?CreatePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DeclineHandshake\"?.+\\$\\.eventName\\s*=\\s*\"?DeleteOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?DeleteOrganizationalUnit\"?.+\\$\\.eventName\\s*=\\s*\"?DeletePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DetachPolicy\"?.+\\$\\.eventName\\s*=\\s*\"?DisablePolicyType\"?.+\\$\\.eventName\\s*=\\s*\"?EnablePolicyType\"?.+\\$\\.eventName\\s*=\\s*\"?InviteAccountToOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?LeaveOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?MoveAccount\"?.+\\$\\.eventName\\s*=\\s*\"?RemoveAccountFromOrganization\"?.+\\$\\.eventName\\s*=\\s*\"?UpdatePolicy\"?.+\\$\\.eventName\\s*=\\s*\"?UpdateOrganizationalUnit\"?'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exists for AWS Organizations changes.'\n else filter_name || ' forwards relevant events for AWS Organizations changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*organizations.amazonaws.com.+\\$\\.eventName\\s*=\\s*"? + AcceptHandshake"?+.\\$\\.eventName\\s*=\\s*"AttachPolicy"?+.\\$\\.eventName\\s*=\\s*"CreateAccount"?+.\\$\\.eventName\\s*=\\s*"CreateOrganizationalUnit"?+.\\$\\.eventName\\s*=\\s*"CreatePolicy"?+.\\$\\.eventName\\s*=\\s*"DeclineHandshake"?+.\\$\\.eventName\\s*=\\s*"DeleteOrganization"?+.\\$\\.eventName\\s*=\\s*"DeleteOrganizationalUnit"?+.\\$\\.eventName\\s*=\\s*"DeletePolicy"?+.\\$\\.eventName\\s*=\\s*"DetachPolicy"?+.\\$\\.eventName\\s*=\\s*"DisablePolicyType"?+.\\$\\.eventName\\s*=\\s*"EnablePolicyType"?+.\\$\\.eventName\\s*=\\s*"InviteAccountToOrganization"?+.\\$\\.eventName\\s*=\\s*"LeaveOrganization"?+.\\$\\.eventName\\s*=\\s*"MoveAccount"?+.\\$\\.eventName\\s*=\\s*"RemoveAccountFromOrganization"?+.\\$\\.eventName\\s*=\\s*"UpdatePolicy"?+.\\$\\.eventName\\s*=\\s*"UpdateOrganizationalUnit"?' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exists for AWS Organizations changes.' + ELSE filter_name || ' forwards relevant events for AWS Organizations changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.15 Ensure AWS Organizations changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_16.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_16.yaml old mode 100755 new mode 100644 index d6525208b..d23c31cd2 --- a/compliance/controls/pending/aws/aws_cis_v300_4_16.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_16.yaml @@ -1,13 +1,30 @@ +Description: Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products. ID: aws_cis_v300_4_16 -Title: "4.16 Ensure AWS Security Hub is enabled" -Description: "Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource,\n case\n when r.region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) then 'skip'\n -- Skip any regions that are disabled in the account.\n when r.opt_in_status = 'not-opted-in' then 'skip'\n when h.hub_arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when r.region = any(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) then r.region || ' region not supported.'\n when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.'\n when h.hub_arn is not null then 'Security Hub enabled in ' || r.region || '.'\n else 'Security Hub disabled in ' || r.region || '.'\n end as reason\n \nfrom\n aws_region as r\n left join aws_securityhub_hub as h on r.account_id = h.account_id and r.name = h.region;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + CASE + WHEN r.region = ANY(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) THEN 'skip' + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN h.hub_arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.region = ANY(array['af-south-1', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'ap-northeast-3']) THEN r.region || ' region not supported.' + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN h.hub_arn IS NOT NULL THEN 'Security Hub enabled in ' || r.region || '.' + ELSE 'Security Hub disabled in ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN aws_securityhub_hub AS h ON r.account_id = h.account_id AND r.name = h.region Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.16 Ensure AWS Security Hub is enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_2.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_2.yaml old mode 100755 new mode 100644 index d2bed058b..a43c599d6 --- a/compliance/controls/pending/aws/aws_cis_v300_4_2.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_2.yaml @@ -1,13 +1,90 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. ID: aws_cis_v300_4_2 -Title: "4.2 Ensure management console sign-in without MFA is monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\(\\s*\\$\\.eventName\\s*=\\s*\"ConsoleLogin\"\\)\\s+&&\\s+\\(\\s*\\$.additionalEventData\\.MFAUsed\\s*!=\\s*\"Yes\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console sign-in without MFA.'\n else filter_name || ' forwards events for console sign-in without MFA.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\(\s*\$\.eventName\s*=\s*"ConsoleLogin"\)\s+&&\s+\(\s*\$.additionalEventData\.MFAUsed\s*!=\s*"Yes"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console sign-in without MFA.' + ELSE filter_name || ' forwards events for console sign-in without MFA.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.2 Ensure management console sign-in without MFA is monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_3.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_3.yaml old mode 100755 new mode 100644 index 4eedcd97c..9f6c3e692 --- a/compliance/controls/pending/aws/aws_cis_v300_4_3.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_3.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. ID: aws_cis_v300_4_3 -Title: "4.3 Ensure usage of 'root' account is monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.userIdentity\\.type\\s*=\\s*\"Root\".+\\$\\.userIdentity\\.invokedBy NOT EXISTS.+\\$\\.eventType\\s*!=\\s*\"AwsServiceEvent\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for usage of \"root\" account.'\n else filter_name || ' forwards events for usage of \"root\" account.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.userIdentity\.type\s*=\s*"Root".+\$\.userIdentity\.invokedBy NOT EXISTS.+\$\.eventType\s*!=\s*"AwsServiceEvent"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for usage of "root" account.' + ELSE filter_name || ' forwards events for usage of "root" account.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.3 Ensure usage of 'root' account is monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_4.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_4.yaml old mode 100755 new mode 100644 index 108be5912..96b1cc43b --- a/compliance/controls/pending/aws/aws_cis_v300_4_4.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_4.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies. ID: aws_cis_v300_4_4 -Title: "4.4 Ensure IAM policy changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*DeleteGroupPolicy.+\\$\\.eventName\\s*=\\s*DeleteRolePolicy.+\\$\\.eventName\\s*=\\s*DeleteUserPolicy.+\\$\\.eventName\\s*=\\s*PutGroupPolicy.+\\$\\.eventName\\s*=\\s*PutRolePolicy.+\\$\\.eventName\\s*=\\s*PutUserPolicy.+\\$\\.eventName\\s*=\\s*CreatePolicy.+\\$\\.eventName\\s*=\\s*DeletePolicy.+\\$\\.eventName\\s*=\\s*CreatePolicyVersion.+\\$\\.eventName\\s*=\\s*DeletePolicyVersion.+\\$\\.eventName\\s*=\\s*AttachRolePolicy.+\\$\\.eventName\\s*=\\s*DetachRolePolicy.+\\$\\.eventName\\s*=\\s*AttachUserPolicy.+\\$\\.eventName\\s*=\\s*DetachUserPolicy.+\\$\\.eventName\\s*=\\s*AttachGroupPolicy.+\\$\\.eventName\\s*=\\s*DetachGroupPolicy'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for IAM policy changes.'\n else filter_name || ' forwards events for IAM policy changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*DeleteGroupPolicy.+\$.eventName\s*=\s*DeleteRolePolicy.+\$.eventName\s*=\s*DeleteUserPolicy.+\$.eventName\s*=\s*PutGroupPolicy.+\$.eventName\s*=\s*PutRolePolicy.+\$.eventName\s*=\s*PutUserPolicy.+\$.eventName\s*=\s*CreatePolicy.+\$.eventName\s*=\s*DeletePolicy.+\$.eventName\s*=\s*CreatePolicyVersion.+\$.eventName\s*=\s*DeletePolicyVersion.+\$.eventName\s*=\s*AttachRolePolicy.+\$.eventName\s*=\s*DetachRolePolicy.+\$.eventName\s*=\s*AttachUserPolicy.+\$.eventName\s*=\s*DetachUserPolicy.+\$.eventName\s*=\s*AttachGroupPolicy.+\$.eventName\s*=\s*DetachGroupPolicy' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for IAM policy changes.' + ELSE filter_name || ' forwards events for IAM policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.4 Ensure IAM policy changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_5.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_5.yaml old mode 100755 new mode 100644 index defee02d1..31583f62e --- a/compliance/controls/pending/aws/aws_cis_v300_4_5.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_5.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, where metric filters and alarms can be established. It is recommended that a metric filter and alarm be utilized for detecting changes to CloudTrail's configurations. ID: aws_cis_v300_4_5 -Title: "4.5 Ensure CloudTrail configuration changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, where metric filters and alarms can be established. It is recommended that a metric filter and alarm be utilized for detecting changes to CloudTrail's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*CreateTrail.+\\$\\.eventName\\s*=\\s*UpdateTrail.+\\$\\.eventName\\s*=\\s*DeleteTrail.+\\$\\.eventName\\s*=\\s*StartLogging.+\\$\\.eventName\\s*=\\s*StopLogging'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for CloudTrail configuration changes.'\n else filter_name || ' forwards events for CloudTrail configuration changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*CreateTrail.+\$.eventName\s*=\s*UpdateTrail.+\$.eventName\s*=\s*DeleteTrail.+\$.eventName\s*=\s*StartLogging.+\$.eventName\s*=\s*StopLogging' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for CloudTrail configuration changes.' + ELSE filter_name || ' forwards events for CloudTrail configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.5 Ensure CloudTrail configuration changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_6.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_6.yaml old mode 100755 new mode 100644 index 28c2c479d..022b5a471 --- a/compliance/controls/pending/aws/aws_cis_v300_4_6.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_6.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts. ID: aws_cis_v300_4_6 -Title: "4.6 Ensure AWS Management Console authentication failures are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventName\\s*=\\s*ConsoleLogin.+\\$\\.errorMessage\\s*=\\s*\"Failed authentication\"'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for console authentication failures.'\n else f.filter_name || ' forwards events for console authentication failures.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventName\s*=\s*ConsoleLogin.+\$.errorMessage\s*=\s*"Failed authentication"' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for console authentication failures.' + ELSE f.filter_name || ' forwards events for console authentication failures.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.6 Ensure AWS Management Console authentication failures are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_7.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_7.yaml old mode 100755 new mode 100644 index 835cbfe95..59c77b360 --- a/compliance/controls/pending/aws/aws_cis_v300_4_7.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_7.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion. ID: aws_cis_v300_4_7 -Title: "4.7 Ensure disabling or scheduled deletion of customer created CMKs is monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*kms.amazonaws.com.+\\$\\.eventName\\s*=\\s*DisableKey.+\\$\\.eventName\\s*=\\s*ScheduleKeyDeletion'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for disabling/deletion of CMKs.'\n else filter_name || ' forwards events for disabling/deletion of CMKs.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$\.eventSource\s*=\s*kms.amazonaws.com.+\$.eventName\s*=\s*DisableKey.+\$.eventName\s*=\s*ScheduleKeyDeletion' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for disabling/deletion of CMKs.' + ELSE filter_name || ' forwards events for disabling/deletion of CMKs.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.7 Ensure disabling or scheduled deletion of customer created CMKs is monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_8.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_8.yaml old mode 100755 new mode 100644 index e735b7d70..d0e9e231f --- a/compliance/controls/pending/aws/aws_cis_v300_4_8.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_8.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies. ID: aws_cis_v300_4_8 -Title: "4.8 Ensure S3 bucket policy changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*s3.amazonaws.com.+\\$\\.eventName\\s*=\\s*PutBucketAcl.+\\$\\.eventName\\s*=\\s*PutBucketPolicy.+\\$\\.eventName\\s*=\\s*PutBucketCors.+\\$\\.eventName\\s*=\\s*PutBucketLifecycle.+\\$\\.eventName\\s*=\\s*PutBucketReplication.+\\$\\.eventName\\s*=\\s*DeleteBucketPolicy.+\\$\\.eventName\\s*=\\s*DeleteBucketCors.+\\$\\.eventName\\s*=\\s*DeleteBucketLifecycle.+\\$\\.eventName\\s*=\\s*DeleteBucketReplication'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for S3 bucket policy changes.'\n else filter_name || ' forwards events for S3 bucket policy changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + split_part(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + jsonb_array_elements(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*s3.amazonaws.com.+\$.eventName\s*=\s*PutBucketAcl.+\$.eventName\s*=\s*PutBucketPolicy.+\$.eventName\s*=\s*PutBucketCors.+\$.eventName\s*=\s*PutBucketLifecycle.+\$.eventName\s*=\s*PutBucketReplication.+\$.eventName\s*=\s*DeleteBucketPolicy.+\$.eventName\s*=\s*DeleteBucketCors.+\$.eventName\s*=\s*DeleteBucketLifecycle.+\$.eventName\s*=\s*DeleteBucketReplication' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for S3 bucket policy changes.' + ELSE filter_name || ' forwards events for S3 bucket policy changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.8 Ensure S3 bucket policy changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_4_9.yaml b/compliance/controls/pending/aws/aws_cis_v300_4_9.yaml old mode 100755 new mode 100644 index 8975ebcc6..709c17b77 --- a/compliance/controls/pending/aws/aws_cis_v300_4_9.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_4_9.yaml @@ -1,13 +1,89 @@ +Description: Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to AWS Config's configurations. ID: aws_cis_v300_4_9 -Title: "4.9 Ensure AWS Config configuration changes are monitored" -Description: "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs, or an external Security information and event management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to AWS Config's configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with trails as (\n select\n trail.account_id,\n trail.name as trail_name,\n trail.is_logging,\n split_part(trail.log_group_arn, ':', 7) as log_group_name\n from\n aws_cloudtrail_trail as trail,\n jsonb_array_elements(trail.event_selectors) as se\n where\n trail.is_multi_region_trail is true\n and trail.is_logging\n and se ->> 'ReadWriteType' = 'All'\n and trail.log_group_arn is not null\n order by\n trail_name\n),\nalarms as (\n select\n metric_name,\n action_arn as topic_arn\n from\n aws_cloudwatch_alarm,\n jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn\n order by\n metric_name\n),\ntopic_subscriptions as (\n select\n subscription_arn,\n topic_arn\n from\n aws_sns_topic_subscription\n order by\n subscription_arn\n),\nmetric_filters as (\n select\n filter.name as filter_name,\n filter_pattern,\n log_group_name,\n metric_transformation_name\n from\n aws_cloudwatch_log_metric_filter as filter\n where\n filter.filter_pattern ~ '\\s*\\$\\.eventSource\\s*=\\s*config.amazonaws.com.+\\$\\.eventName\\s*=\\s*StopConfigurationRecorder.+\\$\\.eventName\\s*=\\s*DeleteDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutDeliveryChannel.+\\$\\.eventName\\s*=\\s*PutConfigurationRecorder'\n order by\n filter_name\n),\nfilter_data as (\n select\n t.account_id,\n t.trail_name,\n f.filter_name\n from\n trails as t\n join\n metric_filters as f on f.log_group_name = t.log_group_name\n join\n alarms as alarm on alarm.metric_name = f.metric_transformation_name\n join\n topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn\n)\nselect\n distinct 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when f.trail_name is null then 'alarm'\n else 'ok'\n end as status,\n case\n when f.trail_name is null then 'No log metric filter and alarm exist for AWS Config configuration changes.'\n else filter_name || ' forwards events for AWS Config configuration changes.'\n end as reason\n \nfrom\n aws_account as a\n left join filter_data as f on a.account_id = f.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH trails AS ( + SELECT + trail.account_id, + trail.name AS trail_name, + trail.is_logging, + SPLIT_PART(trail.log_group_arn, ':', 7) AS log_group_name + FROM + aws_cloudtrail_trail AS trail, + JSONB_ARRAY_ELEMENTS(trail.event_selectors) AS se + WHERE + trail.is_multi_region_trail IS TRUE + AND trail.is_logging + AND se ->> 'ReadWriteType' = 'All' + AND trail.log_group_arn IS NOT NULL + ORDER BY + trail_name + ), + alarms AS ( + SELECT + metric_name, + action_arn AS topic_arn + FROM + aws_cloudwatch_alarm, + JSONB_ARRAY_ELEMENTS_TEXT(aws_cloudwatch_alarm.alarm_actions) AS action_arn + ORDER BY + metric_name + ), + topic_subscriptions AS ( + SELECT + subscription_arn, + topic_arn + FROM + aws_sns_topic_subscription + ORDER BY + subscription_arn + ), + metric_filters AS ( + SELECT + filter.name AS filter_name, + filter_pattern, + log_group_name, + metric_transformation_name + FROM + aws_cloudwatch_log_metric_filter AS filter + WHERE + filter.filter_pattern ~ '\s*\$.eventSource\s*=\s*config.amazonaws.com.+\$.eventName\s*=\s*StopConfigurationRecorder.+\$.eventName\s*=\s*DeleteDeliveryChannel.+\$.eventName\s*=\s*PutDeliveryChannel.+\$.eventName\s*=\s*PutConfigurationRecorder' + ORDER BY + filter_name + ), + filter_data AS ( + SELECT + t.account_id, + t.trail_name, + f.filter_name + FROM + trails AS t + JOIN + metric_filters AS f ON f.log_group_name = t.log_group_name + JOIN + alarms AS alarm ON alarm.metric_name = f.metric_transformation_name + JOIN + topic_subscriptions AS subscription ON subscription.topic_arn = alarm.topic_arn + ) + SELECT + DISTINCT 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN f.trail_name IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN f.trail_name IS NULL THEN 'No log metric filter and alarm exist for AWS Config configuration changes.' + ELSE filter_name || ' forwards events for AWS Config configuration changes.' + END AS reason + FROM + aws_account AS a + LEFT JOIN filter_data AS f ON a.account_id = f.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4.9 Ensure AWS Config configuration changes are monitored \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_5_1.yaml b/compliance/controls/pending/aws/aws_cis_v300_5_1.yaml old mode 100755 new mode 100644 index 7875a26cc..7691b6253 --- a/compliance/controls/pending/aws/aws_cis_v300_5_1.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_5_1.yaml @@ -1,13 +1,87 @@ +Description: The Network Access Control List (NACL) function provide stateless filtering of ingress and + egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted + ingress access to remote server administration ports, such as SSH to port 22 and RDP to + port 3389, using either the TCP (6), UDP (17) or ALL (-1) protocols. ID: aws_cis_v300_5_1 -Title: "5.1 Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports" -Description: "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port 22 and RDP to port 3389, using either the TCP (6), UDP (17) or ALL (-1) protocols." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bad_rules as (\n select\n network_acl_id,\n count(*) as num_bad_rules,\n tags,\n region,\n account_id\n from\n aws_vpc_network_acl,\n jsonb_array_elements(entries) as att\n where\n att ->> 'Egress' = 'false' -- as per aws egress = false indicates the ingress\n and (\n att ->> 'CidrBlock' = '0.0.0.0/0'\n or att ->> 'Ipv6CidrBlock' = '::/0'\n )\n and att ->> 'RuleAction' = 'allow'\n and (\n (\n att ->> 'Protocol' = '-1' -- all traffic\n and att ->> 'PortRange' is null\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 22\n and (att -> 'PortRange' ->> 'To') :: int >= 22\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 3389\n and (att -> 'PortRange' ->> 'To') :: int >= 3389\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n )\n group by\n network_acl_id,\n region,\n account_id,\n tags\n order by\n network_acl_id,\n region,\n account_id,\n tags\n),\naws_vpc_network_acls as (\n select\n network_acl_id,\n tags,\n partition,\n region,\n account_id\n from\n aws_vpc_network_acl\n order by\n network_acl_id,\n region,\n account_id\n)\nselect\n 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id as resource,\n case\n when bad_rules.network_acl_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when bad_rules.network_acl_id is null then acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n else acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n end as reason\n \n \nfrom\n aws_vpc_network_acls as acl\n left join bad_rules on bad_rules.network_acl_id = acl.network_acl_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH bad_rules AS ( + SELECT + network_acl_id, + COUNT(*) AS num_bad_rules, + tags, + region, + account_id + FROM + aws_vpc_network_acl, + jsonb_array_elements(entries) AS att + WHERE + att ->> 'Egress' = 'false' + AND ( + att ->> 'CidrBlock' = '0.0.0.0/0' + OR att ->> 'Ipv6CidrBlock' = '::/0' + ) + AND att ->> 'RuleAction' = 'allow' + AND ( + ( + att ->> 'Protocol' = '-1' + AND att ->> 'PortRange' IS NULL + ) + OR ( + (att -> 'PortRange' ->> 'From')::int <= 22 + AND (att -> 'PortRange' ->> 'To')::int >= 22 + AND att ->> 'Protocol' IN ('6', '17') + ) + OR ( + (att -> 'PortRange' ->> 'From')::int <= 3389 + AND (att -> 'PortRange' ->> 'To')::int >= 3389 + AND att ->> 'Protocol' IN ('6', '17') + ) + ) + GROUP BY + network_acl_id, + region, + account_id, + tags + ORDER BY + network_acl_id, + region, + account_id, + tags + ), + aws_vpc_network_acls AS ( + SELECT + network_acl_id, + tags, + partition, + region, + account_id + FROM + aws_vpc_network_acl + ORDER BY + network_acl_id, + region, + account_id + ) + SELECT + 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id AS resource, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + aws_vpc_network_acls AS acl + LEFT JOIN bad_rules ON bad_rules.network_acl_id = acl.network_acl_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.1 Ensure no Network ACLs allow ingress from 0.0.0.0/0 to remote server administration ports \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cis_v300_5_4.yaml b/compliance/controls/pending/aws/aws_cis_v300_5_4.yaml old mode 100755 new mode 100644 index fa76bc39d..8468a616b --- a/compliance/controls/pending/aws/aws_cis_v300_5_4.yaml +++ b/compliance/controls/pending/aws/aws_cis_v300_5_4.yaml @@ -1,13 +1,37 @@ +Description: A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. ID: aws_cis_v300_5_4 -Title: "5.4 Ensure the default security group of every VPC restricts all traffic" -Description: "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn resource,\n case\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) = 0 then 'ok'\n else 'alarm'\n end status,\n case\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has inbound and outbound rules.'\n when jsonb_array_length(ip_permissions) > 0 and jsonb_array_length(ip_permissions_egress) = 0\n then 'Default security group ' || group_id || ' has inbound rules.'\n when jsonb_array_length(ip_permissions) = 0 and jsonb_array_length(ip_permissions_egress) > 0\n then 'Default security group ' || group_id || ' has outbound rules.'\n else 'Default security group ' || group_id || ' has no inbound or outbound rules.'\n end reason\n \n \nfrom\n aws_vpc_security_group\nwhere\n group_name = 'default';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn resource, + CASE + WHEN jsonb_array_length(ip_permissions) = 0 + AND jsonb_array_length(ip_permissions_egress) = 0 + THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN jsonb_array_length(ip_permissions) > 0 + AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has inbound and outbound rules.' + WHEN jsonb_array_length(ip_permissions) > 0 + AND jsonb_array_length(ip_permissions_egress) = 0 + THEN 'Default security group ' || group_id || ' has inbound rules.' + WHEN jsonb_array_length(ip_permissions) = 0 + AND jsonb_array_length(ip_permissions_egress) > 0 + THEN 'Default security group ' || group_id || ' has outbound rules.' + ELSE 'Default security group ' || group_id || ' has no inbound or outbound rules.' + END reason + FROM + aws_vpc_security_group + WHERE + group_name = 'default'; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5.4 Ensure the default security group of every VPC restricts all traffic \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled.yaml b/compliance/controls/pending/aws/aws_cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled.yaml old mode 100755 new mode 100644 index e40e33ceb..84211ddf6 --- a/compliance/controls/pending/aws/aws_cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled.yaml +++ b/compliance/controls/pending/aws/aws_cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled.yaml @@ -1,13 +1,60 @@ +Description: This control ensures that connection between CloudFront and the origin server is encrypted. It is recommended to enforce HTTPS-only traffic between a CloudFront distribution and the origin. ID: aws_cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled -Title: "CloudFront distributions should encrypt traffic to non S3 origins" -Description: "This control ensures that conection between cloudfront and oriign server is encrypted. It is recommended to enforce HTTPS-only traffic between a CloudFront distribution and the origin." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with viewer_protocol_policy_value as (\n select\n distinct arn\n from\n aws_cloudfront_distribution,\n jsonb_array_elements(\n case jsonb_typeof(cache_behaviors -> 'Items')\n when 'array' then (cache_behaviors -> 'Items')\n else null end\n ) as cb\n where\n cb ->> 'ViewerProtocolPolicy' = 'allow-all'\n),\norigin_protocol_policy_value as (\n select\n distinct arn,\n o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' as origin_protocol_policy\n from\n aws_cloudfront_distribution,\n jsonb_array_elements(origins) as o\n where\n o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'http-only'\n or o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'match-viewer'\n and o -> 'S3OriginConfig' is null\n)\nselect\n b.arn as resource,\n case\n when o.arn is not null and o.origin_protocol_policy = 'http-only' then 'alarm'\n when o.arn is not null and o.origin_protocol_policy = 'match-viewer' and ( v.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') ) then 'alarm'\n else 'ok'\n end as status,\n case\n when o.arn is not null and o.origin_protocol_policy = 'http-only' then title || ' origins traffic not encrypted in transit.'\n when o.arn is not null and o.origin_protocol_policy = 'match-viewer' and ( v.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') ) then title || ' origins traffic not encrypted in transit.'\n else title || ' origins traffic encrypted in transit.'\n end as reason\n \n \nfrom\n aws_cloudfront_distribution as b\n left join origin_protocol_policy_value as o on b.arn = o.arn\n left join viewer_protocol_policy_value as v on b.arn = v.arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH viewer_protocol_policy_value AS ( + SELECT + DISTINCT arn + FROM + aws_cloudfront_distribution, + jsonb_array_elements( + CASE jsonb_typeof(cache_behaviors -> 'Items') + WHEN 'array' THEN (cache_behaviors -> 'Items') + ELSE NULL + END + ) AS cb + WHERE + cb ->> 'ViewerProtocolPolicy' = 'allow-all' + ), + origin_protocol_policy_value AS ( + SELECT + DISTINCT arn, + o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' AS origin_protocol_policy + FROM + aws_cloudfront_distribution, + jsonb_array_elements(origins) AS o + WHERE + o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'http-only' + OR o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'match-viewer' + AND o -> 'S3OriginConfig' IS NULL + ) + SELECT + b.arn AS resource, + CASE + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'http-only' THEN 'alarm' + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'match-viewer' AND + (v.arn IS NOT NULL OR (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all')) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'http-only' + THEN title || ' origins traffic not encrypted in transit.' + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'match-viewer' AND + (v.arn IS NOT NULL OR (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all')) + THEN title || ' origins traffic not encrypted in transit.' + ELSE title || ' origins traffic encrypted in transit.' + END AS reason + FROM + aws_cloudfront_distribution AS b + LEFT JOIN origin_protocol_policy_value AS o ON b.arn = o.arn + LEFT JOIN viewer_protocol_policy_value AS v ON b.arn = v.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: CloudFront distributions should encrypt traffic to non S3 origins \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_codedeploy_deployment_group_lambda_allatonce_traffic_shift_disabled.yaml b/compliance/controls/pending/aws/aws_codedeploy_deployment_group_lambda_allatonce_traffic_shift_disabled.yaml old mode 100755 new mode 100644 index 1590b2c71..b34cfbe34 --- a/compliance/controls/pending/aws/aws_codedeploy_deployment_group_lambda_allatonce_traffic_shift_disabled.yaml +++ b/compliance/controls/pending/aws/aws_codedeploy_deployment_group_lambda_allatonce_traffic_shift_disabled.yaml @@ -1,13 +1,67 @@ +Description: This control checks if the deployment group for Lambda Compute Platform is not using the default deployment configuration. The rule is non-compliant if the deployment group is using the deployment configuration 'CodeDeployDefault.LambdaAllAtOnce'. ID: aws_codedeploy_deployment_group_lambda_allatonce_traffic_shift_disabled -Title: "Codedeploy deployment groups lambda allatonce traffic shift should be disabled" -Description: "This control checks if the deployment group for Lambda Compute Platform is not using the default deployment configuration. The rule is non-compliant if the deployment group is using the deployment configuration 'CodeDeployDefault.LambdaAllAtOnce'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with codedeployment_groups as (\n select\n arn,\n application_name,\n deployment_config_name,\n tags,\n title,\n region,\n account_id,\n _ctx\n from\n aws_codedeploy_deployment_group\n group by\n arn,\n application_name,\n deployment_config_name,\n tags,\n title,\n region,\n account_id,\n _ctx\n),\ncodedeploy_apps as (\n select\n application_name,\n compute_platform,\n region,\n account_id,\n title\n from\n aws_codedeploy_app\n group by\n application_name,\n compute_platform,\n region,\n account_id,\n title\n)\nselect\n g.arn as resource,\n case\n when a.compute_platform <> 'Lambda' then 'skip'\n when deployment_config_name = 'CodeDeployDefault.LambdaAllAtOnce' then 'alarm'\n else 'ok'\n end as status,\n case\n when a.compute_platform <> 'Lambda' then g.title || ' using ' || a.compute_platform || ' compute platform.'\n else g.title || ' using '|| deployment_config_name || ' deployment config.'\n end as reason\n \n \nfrom\n codedeployment_groups as g,\n codedeploy_apps as a\nwhere\n g.application_name = a.application_name;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH codedeployment_groups AS ( + SELECT + arn, + application_name, + deployment_config_name, + tags, + title, + region, + account_id, + _ctx + FROM + aws_codedeploy_deployment_group + GROUP BY + arn, + application_name, + deployment_config_name, + tags, + title, + region, + account_id, + _ctx + ), + codedeploy_apps AS ( + SELECT + application_name, + compute_platform, + region, + account_id, + title + FROM + aws_codedeploy_app + GROUP BY + application_name, + compute_platform, + region, + account_id, + title + ) + SELECT + g.arn AS resource, + CASE + WHEN a.compute_platform <> 'Lambda' THEN 'skip' + WHEN deployment_config_name = 'CodeDeployDefault.LambdaAllAtOnce' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN a.compute_platform <> 'Lambda' THEN g.title || ' using ' || a.compute_platform || ' compute platform.' + ELSE g.title || ' using ' || deployment_config_name || ' deployment config.' + END AS reason + FROM + codedeployment_groups AS g, + codedeploy_apps AS a + WHERE + g.application_name = a.application_name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Codedeploy deployment groups lambda allatonce traffic shift should be disabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_dms_replication_task_target_database_logging_enabled.yaml b/compliance/controls/pending/aws/aws_dms_replication_task_target_database_logging_enabled.yaml old mode 100755 new mode 100644 index 8a7564618..2003e3f83 --- a/compliance/controls/pending/aws/aws_dms_replication_task_target_database_logging_enabled.yaml +++ b/compliance/controls/pending/aws/aws_dms_replication_task_target_database_logging_enabled.yaml @@ -1,13 +1,51 @@ +Description: This control checks whether logging is enabled with the minimum severity level of LOGGER_SEVERITY_DEFAULT for DMS replication tasks TARGET_APPLY and TARGET_LOAD. The control fails if logging isn't enabled for these tasks or if the minimum severity level is less than LOGGER_SEVERITY_DEFAULT. ID: aws_dms_replication_task_target_database_logging_enabled -Title: "DMS replication tasks for the target database should have logging enabled" -Description: "This control checks whether logging is enabled with the minimum severity level of LOGGER_SEVERITY_DEFAULT for DMS replication tasks TARGET_APPLY and TARGET_LOAD. The control fails if logging isn't enabled for these tasks or if the minimum severity level is less than LOGGER_SEVERITY_DEFAULT." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with replication_task_target_apply as (\n select\n arn\n from\n aws_dms_replication_task,\n jsonb_array_elements(replication_task_settings -> 'Logging' -> 'LogComponents') as o\n where\n o ->> 'Id' = 'TARGET_APPLY'\n and o ->> 'Severity' in ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')\n), replication_task_target_load as (\n select\n arn\n from\n aws_dms_replication_task,\n jsonb_array_elements(replication_task_settings -> 'Logging' -> 'LogComponents') as o\n where\n o ->> 'Id' = 'TARGET_LOAD'\n and o ->> 'Severity' in ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')\n)\nselect\n t.arn as resource,\n (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool,\n case\n when (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool\n and a.arn is not null\n and l.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool\n and a.arn is not null\n and l.arn is not null then title || ' target database logging enabled.'\n else title || 'target database logging disabled.'\n end as reason\n \n \nfrom\n aws_dms_replication_task as t\n left join replication_task_target_apply as a on a.arn = t.arn\n left join replication_task_target_load as l on l.arn = t.arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH replication_task_target_apply AS ( + SELECT + arn + FROM + aws_dms_replication_task, + jsonb_array_elements(replication_task_settings -> 'Logging' -> 'LogComponents') AS o + WHERE + o ->> 'Id' = 'TARGET_APPLY' + AND o ->> 'Severity' IN ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG') + ), replication_task_target_load AS ( + SELECT + arn + FROM + aws_dms_replication_task, + jsonb_array_elements(replication_task_settings -> 'Logging' -> 'LogComponents') AS o + WHERE + o ->> 'Id' = 'TARGET_LOAD' + AND o ->> 'Severity' IN ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG') + ) + SELECT + t.arn AS resource, + (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool, + CASE + WHEN (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool + AND a.arn IS NOT NULL + AND l.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool + AND a.arn IS NOT NULL + AND l.arn IS NOT NULL THEN title || ' target database logging enabled.' + ELSE title || 'target database logging disabled.' + END AS reason + FROM + aws_dms_replication_task AS t + LEFT JOIN replication_task_target_apply AS a ON a.arn = t.arn + LEFT JOIN replication_task_target_load AS l ON l.arn = t.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: DMS replication tasks for the target database should have logging enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_docdb_cluster_snapshot_restrict_public_access.yaml b/compliance/controls/pending/aws/aws_docdb_cluster_snapshot_restrict_public_access.yaml old mode 100755 new mode 100644 index 21700cbff..cb5340481 --- a/compliance/controls/pending/aws/aws_docdb_cluster_snapshot_restrict_public_access.yaml +++ b/compliance/controls/pending/aws/aws_docdb_cluster_snapshot_restrict_public_access.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether an Amazon DocumentDB manual cluster snapshot is public. The control fails if the manual cluster snapshot is public. ID: aws_docdb_cluster_snapshot_restrict_public_access -Title: "Amazon DocumentDB manual cluster snapshots should not be public" -Description: "This control checks whether an Amazon DocumentDB manual cluster snapshot is public. The control fails if the manual cluster snapshot is public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when (cluster_snapshot ->> 'AttributeName' = 'restore') and cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when (cluster_snapshot ->> 'AttributeName' = 'restore') and cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then title || ' does not restrict public access.'\n else title || ' restrict public access.'\n end reason\n \n \nfrom\n aws_docdb_cluster_snapshot,\n jsonb_array_elements(db_cluster_snapshot_attributes) as cluster_snapshot;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN (cluster_snapshot ->> 'AttributeName' = 'restore') + AND cluster_snapshot -> 'AttributeValues' = '["all"]' + THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN (cluster_snapshot ->> 'AttributeName' = 'restore') + AND cluster_snapshot -> 'AttributeValues' = '["all"]' + THEN title || ' does not restrict public access.' + ELSE title || ' restrict public access.' + END reason + FROM + aws_docdb_cluster_snapshot, + jsonb_array_elements(db_cluster_snapshot_attributes) AS cluster_snapshot; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Amazon DocumentDB manual cluster snapshots should not be public \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_ec2_instance_no_high_level_finding_in_inspector_scan.yaml b/compliance/controls/pending/aws/aws_ec2_instance_no_high_level_finding_in_inspector_scan.yaml old mode 100755 new mode 100644 index 49903a752..c0f05cd21 --- a/compliance/controls/pending/aws/aws_ec2_instance_no_high_level_finding_in_inspector_scan.yaml +++ b/compliance/controls/pending/aws/aws_ec2_instance_no_high_level_finding_in_inspector_scan.yaml @@ -1,13 +1,49 @@ +Description: AWS Inspector scans operating system packages installed on your AWS EC2 instances for vulnerabilities and network reachability issues. Each finding has the name of the detected vulnerability and provides a severity rating, information about the affected resource, and details such as how to remediate the reported vulnerability. ID: aws_ec2_instance_no_high_level_finding_in_inspector_scan -Title: "EC2 instances high level findings should not be there in inspector scans" -Description: "AWS Inspector scans operating system packages installed on your AWS EC2 instances for vulnerabilities and network reachability issues. Each finding has the name of the detected vulnerability and provides a severity rating, information about the affected resource, and details such as how to remediate the reported vulnerability." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with severity_list as (\n select\n distinct title ,\n a ->> 'Value' as instance_id\n from\n aws_inspector_finding,\n jsonb_array_elements(attributes) as a\n where\n severity = 'High'\n and asset_type = 'ec2-instance'\n and a ->> 'Key' = 'INSTANCE_ID'\n group by\n a ->> 'Value',\n title\n), ec2_istance_list as (\n select\n distinct instance_id\n from\n severity_list\n)\nselect\n arn as resource,\n case\n when l.instance_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when l.instance_id is null then i.title || ' has no high level finding in inspector scans.'\n else i.title || ' has ' || (select count(*) from severity_list where instance_id = i.instance_id) || ' high level findings in inspector scans.'\n end as reason\n \n \nfrom\n aws_ec2_instance as i\n left join ec2_istance_list as l on i.instance_id = l.instance_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH severity_list AS ( + SELECT + DISTINCT title, + a ->> 'Value' AS instance_id + FROM + aws_inspector_finding, + jsonb_array_elements(attributes) AS a + WHERE + severity = 'High' + AND asset_type = 'ec2-instance' + AND a ->> 'Key' = 'INSTANCE_ID' + GROUP BY + a ->> 'Value', + title + ), + + ec2_instance_list AS ( + SELECT + DISTINCT instance_id + FROM + severity_list + ) + + SELECT + arn AS resource, + CASE + WHEN l.instance_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN l.instance_id IS NULL THEN i.title || ' has no high level finding in inspector scans.' + ELSE i.title || ' has ' || (SELECT COUNT(*) FROM severity_list WHERE instance_id = i.instance_id) || ' high level findings in inspector scans.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN ec2_instance_list AS l ON i.instance_id = l.instance_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instances high level findings should not be there in inspector scans \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_database_management_write_access.yaml b/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_database_management_write_access.yaml old mode 100755 new mode 100644 index 96ebf221a..e7a8b1cbb --- a/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_database_management_write_access.yaml +++ b/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_database_management_write_access.yaml @@ -1,13 +1,80 @@ +Description: This control ensures that EC2 instance IAM role does not allow database management write access. ID: aws_ec2_instance_no_iam_role_with_database_management_write_access -Title: "EC2 instance IAM role should not allow database management write access" -Description: "This control ensures that EC2 instance IAM role does not allow database management write access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with iam_roles as (\n select\n r.arn as role_arn,\n i.arn as intance_arn\n from\n aws_iam_role as r,\n jsonb_array_elements_text(instance_profile_arns) as p\n left join aws_ec2_instance as i on p = i.iam_instance_profile_arn\n where\n i.arn is not null\n), iam_role_with_permission as (\n select\n arn\n from\n aws_iam_role,\n jsonb_array_elements(assume_role_policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n arn in (select role_arn from iam_roles)\n and s ->> 'Effect' = 'Allow'\n and service = 'ec2.amazonaws.com'\n and (\n (action in ('rds:modifydbcluster','rds:modifydbclusterendpoint','rds:modifydbinstance','rds:modifydbsnapshot','rds:modifyglobalcluster','dynamodb:updateitem','dynamodb:updatetable','memorydb:updatecluster','neptune-db:resetdatabase','neptune-db:writedataviaquery','docdb-elastic:updatecluster','elasticache:modifycachecluster','cassandra:alter','cassandra:modify','qldb:executestatement','qldb:partiqlupdate','qldb:sendcommand','qldb:updateledger','redshift:modifycluster','redshift:modifyclustersnapshot','redshift:modifyendpointaccess','timestream:updatedatabase','timestream:updatetable','timestream:writerecords','*:*')\n )\n )\n)\nselect\n i.arn as resource,\n case\n when p.arn is null then 'ok'\n else 'alarm'\n end status,\n case\n when p.arn is null then title || ' has no database management write level access.'\n else title || ' has database management write level access.'\n end as reason\n \n \nfrom\n aws_ec2_instance as i\n left join iam_roles as r on r.intance_arn = i.arn\n left join iam_role_with_permission as p on p.arn = r.role_arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), + iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND ( + action IN ( + 'rds:modifydbcluster', + 'rds:modifydbclusterendpoint', + 'rds:modifydbinstance', + 'rds:modifydbsnapshot', + 'rds:modifyglobalcluster', + 'dynamodb:updateitem', + 'dynamodb:updatetable', + 'memorydb:updatecluster', + 'neptune-db:resetdatabase', + 'neptune-db:writedataviaquery', + 'docdb-elastic:updatecluster', + 'elasticache:modifycachecluster', + 'cassandra:alter', + 'cassandra:modify', + 'qldb:executestatement', + 'qldb:partiqlupdate', + 'qldb:sendcommand', + 'qldb:updateledger', + 'redshift:modifycluster', + 'redshift:modifyclustersnapshot', + 'redshift:modifyendpointaccess', + 'timestream:updatedatabase', + 'timestream:updatetable', + 'timestream:writerecords', + '*:*' + ) + ) + ) + SELECT + i.arn AS resource, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN p.arn IS NULL THEN title || ' has no database management write level access.' + ELSE title || ' has database management write level access.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow database management write access \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_defense_evasion_impact_of_aws_security_services_access.yaml b/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_defense_evasion_impact_of_aws_security_services_access.yaml old mode 100755 new mode 100644 index 38ed30f5e..842415b51 --- a/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_defense_evasion_impact_of_aws_security_services_access.yaml +++ b/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_defense_evasion_impact_of_aws_security_services_access.yaml @@ -1,13 +1,70 @@ +Description: This control ensures that EC2 instance IAM role does not allow defense evasion impact of AWS security services access. ID: aws_ec2_instance_no_iam_role_with_defense_evasion_impact_of_aws_security_services_access -Title: "EC2 instance IAM role should not allow defense evasion impact of AWS security services access" -Description: "This control ensures that EC2 instance IAM role does not allow defense evasion impact of AWS security services access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with iam_roles as (\n select\n r.arn as role_arn,\n i.arn as intance_arn\n from\n aws_iam_role as r,\n jsonb_array_elements_text(instance_profile_arns) as p\n left join aws_ec2_instance as i on p = i.iam_instance_profile_arn\n where\n i.arn is not null\n), iam_role_with_permission as (\n select\n arn\n from\n aws_iam_role,\n jsonb_array_elements(assume_role_policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n arn in (select role_arn from iam_roles)\n and s ->> 'Effect' = 'Allow'\n and service = 'ec2.amazonaws.com'\n and action in ( 'guardduty:updatedetector','guardduty:deletedetector','guardduty:deletemembers','guardduty:updatefilter','guardduty:deletefilter','shield:disableapplicationlayerautomaticresponse','shield:updateprotectiongroup','shield:deletesubscription','detective:disassociatemembership','detective:deletemembers','inspector:disable','config:stopconfigurationrecorder','config:deleteconfigurationrecorder','config:deleteconfigrule','config:deleteorganizationconfigrule','cloudwatch:disablealarmactions','cloudwatch:disableinsightrules','*:*')\n)\nselect\n i.arn as resource,\n case\n when p.arn is null then 'ok'\n else 'alarm'\n end status,\n case\n when p.arn is null then title || ' has no IAM role with defense evasion impact of AWS security services access.'\n else title || ' has IAM role with defense evasion impact of AWS security services access.'\n end as reason\n \n \nfrom\n aws_ec2_instance as i\n left join iam_roles as r on r.intance_arn = i.arn\n left join iam_role_with_permission as p on p.arn = r.role_arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + JSONB_ARRAY_ELEMENTS_TEXT(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + JSONB_ARRAY_ELEMENTS(assume_role_policy_std -> 'Statement') AS s, + JSONB_ARRAY_ELEMENTS_TEXT(s -> 'Principal' -> 'Service') AS service, + JSONB_ARRAY_ELEMENTS_TEXT(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ( + 'guardduty:updatedetector', + 'guardduty:deletedetector', + 'guardduty:deletemembers', + 'guardduty:updatefilter', + 'guardduty:deletefilter', + 'shield:disableapplicationlayerautomaticresponse', + 'shield:updateprotectiongroup', + 'shield:deletesubscription', + 'detective:disassociatemembership', + 'detective:deletemembers', + 'inspector:disable', + 'config:stopconfigurationrecorder', + 'config:deleteconfigurationrecorder', + 'config:deleteconfigrule', + 'config:deleteorganizationconfigrule', + 'cloudwatch:disablealarmactions', + 'cloudwatch:disableinsightrules', + '*:*' + ) + ) + SELECT + i.arn AS resource, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' has no IAM role with defense evasion impact of AWS security services access.' + ELSE title || ' has IAM role with defense evasion impact of AWS security services access.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow defense evasion impact of AWS security services access \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_new_user_creation_with_attached_policy_access.yaml b/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_new_user_creation_with_attached_policy_access.yaml old mode 100755 new mode 100644 index dd909b455..20e312d47 --- a/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_new_user_creation_with_attached_policy_access.yaml +++ b/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_new_user_creation_with_attached_policy_access.yaml @@ -1,13 +1,52 @@ +Description: This control ensures that EC2 instance IAM role does not allow new user creation with attached policy access. ID: aws_ec2_instance_no_iam_role_with_new_user_creation_with_attached_policy_access -Title: "EC2 instance IAM role should not allow new user creation with attached policy access" -Description: "This control ensures that EC2 instance IAM role does not allow new user creation with attached policy access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with iam_roles as (\n select\n r.arn as role_arn,\n i.arn as intance_arn\n from\n aws_iam_role as r,\n jsonb_array_elements_text(instance_profile_arns) as p\n left join aws_ec2_instance as i on p = i.iam_instance_profile_arn\n where\n i.arn is not null\n), iam_role_with_permission as (\n select\n arn\n from\n aws_iam_role,\n jsonb_array_elements(assume_role_policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n arn in (select role_arn from iam_roles)\n and s ->> 'Effect' = 'Allow'\n and service = 'ec2.amazonaws.com'\n and action = 'iam:createuser'\n and action = 'iam:attachuserpolicy'\n)\nselect\n i.arn as resource,\n case\n when p.arn is null then 'ok'\n else 'alarm'\n end status,\n case\n when p.arn is null then title || ' has no new user creation access with attached policy.'\n else title || ' has new user creation access with attached policy.'\n end as reason\n \n \nfrom\n aws_ec2_instance as i\n left join iam_roles as r on r.intance_arn = i.arn\n left join iam_role_with_permission as p on p.arn = r.role_arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action = 'iam:createuser' + AND action = 'iam:attachuserpolicy' + ) + SELECT + i.arn AS resource, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.arn IS NULL THEN title || ' has no new user creation access with attached policy.' + ELSE title || ' has new user creation access with attached policy.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.instance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow new user creation with attached policy access \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_write_access_to_resource_based_policies.yaml b/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_write_access_to_resource_based_policies.yaml old mode 100755 new mode 100644 index 1bda4b94d..381a1ea07 --- a/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_write_access_to_resource_based_policies.yaml +++ b/compliance/controls/pending/aws/aws_ec2_instance_no_iam_role_with_write_access_to_resource_based_policies.yaml @@ -1,13 +1,75 @@ +Description: This control ensures that EC2 instance IAM role does not allow write access to resource based policies. ID: aws_ec2_instance_no_iam_role_with_write_access_to_resource_based_policies -Title: "EC2 instance IAM role should not allow write access to resource based policies" -Description: "This control ensures that EC2 instance IAM role does not allow write access to resource based policies." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with iam_roles as (\n select\n r.arn as role_arn,\n i.arn as intance_arn\n from\n aws_iam_role as r,\n jsonb_array_elements_text(instance_profile_arns) as p\n left join aws_ec2_instance as i on p = i.iam_instance_profile_arn\n where\n i.arn is not null\n), iam_role_with_permission as (\n select\n arn\n from\n aws_iam_role,\n jsonb_array_elements(assume_role_policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Principal' -> 'Service') as service,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n arn in (select role_arn from iam_roles)\n and s ->> 'Effect' = 'Allow'\n and service = 'ec2.amazonaws.com'\n and action in (\n'ecr:setrepositorypolicy','serverlessrepo:putapplicationpolicy','backup:putbackupvaultaccesspolicy','efs:putfilesystempolicy','glacier:setvaultaccesspolicy','secretsmanager:putresourcepolicy','events:putpermission','mediastore:putcontainerpolicy','glue:putresourcepolicy','ses:putidentitypolicy','lambda:addpermission','lambda:addlayerversionpermission','s3:putbucketpolicy','s3:putbucketacl','s3:putObject','s3:putobjectacl','kms:creategrant','kms:putkeypolicy','es:Updateelasticsearchdomainconfig','sns:addpermission','sqs:addpermission','*:*'\n )\n)\nselect\n i.arn as resource,\n case\n when p.arn is null then 'ok'\n else 'alarm'\n end status,\n case\n when p.arn is null then title || ' has no write access permission to resource based policies.'\n else title || ' has write access permission to resource based policies.'\n end as reason\n \n \nfrom\n aws_ec2_instance as i\n left join iam_roles as r on r.intance_arn = i.arn\n left join iam_role_with_permission as p on p.arn = r.role_arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH iam_roles AS ( + SELECT + r.arn AS role_arn, + i.arn AS instance_arn + FROM + aws_iam_role AS r, + jsonb_array_elements_text(instance_profile_arns) AS p + LEFT JOIN aws_ec2_instance AS i ON p = i.iam_instance_profile_arn + WHERE + i.arn IS NOT NULL + ), + iam_role_with_permission AS ( + SELECT + arn + FROM + aws_iam_role, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Principal' -> 'Service') AS service, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + arn IN (SELECT role_arn FROM iam_roles) + AND s ->> 'Effect' = 'Allow' + AND service = 'ec2.amazonaws.com' + AND action IN ( + 'ecr:setrepositorypolicy', + 'serverlessrepo:putapplicationpolicy', + 'backup:putbackupvaultaccesspolicy', + 'efs:putfilesystempolicy', + 'glacier:setvaultaccesspolicy', + 'secretsmanager:putresourcepolicy', + 'events:putpermission', + 'mediastore:putcontainerpolicy', + 'glue:putresourcepolicy', + 'ses:putidentitypolicy', + 'lambda:addpermission', + 'lambda:addlayerversionpermission', + 's3:putbucketpolicy', + 's3:putbucketacl', + 's3:putObject', + 's3:putobjectacl', + 'kms:creategrant', + 'kms:putkeypolicy', + 'es:Updateelasticsearchdomainconfig', + 'sns:addpermission', + 'sqs:addpermission', + '*:*' + ) + ) + SELECT + i.arn AS resource, + CASE + WHEN p.arn IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN p.arn IS NULL THEN title || ' has no write access permission to resource based policies.' + ELSE title || ' has write access permission to resource based policies.' + END AS reason + FROM + aws_ec2_instance AS i + LEFT JOIN iam_roles AS r ON r.intance_arn = i.arn + LEFT JOIN iam_role_with_permission AS p ON p.arn = r.role_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EC2 instance IAM role should not allow write access to resource based policies \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_ecs_cluster_instance_in_vpc.yaml b/compliance/controls/pending/aws/aws_ecs_cluster_instance_in_vpc.yaml old mode 100755 new mode 100644 index 155322672..b1e0963de --- a/compliance/controls/pending/aws/aws_ecs_cluster_instance_in_vpc.yaml +++ b/compliance/controls/pending/aws/aws_ecs_cluster_instance_in_vpc.yaml @@ -1,13 +1,27 @@ +Description: Deploy AWS ECS cluster instance within an AWS Virtual Private Cloud (AWS VPC) for a secure communication between a instance and other services within the AWS VPC. ID: aws_ecs_cluster_instance_in_vpc -Title: "ECS cluster instances should be in a VPC" -Description: "Deploy AWS ECS cluster instance within an AWS Virtual Private Cloud (AWS VPC) for a secure communication between a instance and other services within the AWS VPC." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n c.arn as resource,\n case\n when i.vpc_id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when i.vpc_id is null then c.title || ' not in VPC.'\n else c.title || ' in VPC.'\n end as reason\n \n \nfrom\n aws_ecs_container_instance as c\n left join aws_ec2_instance as i on c.ec2_instance_id = i.instance_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + c.arn AS resource, + CASE + WHEN i.vpc_id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.vpc_id IS NULL THEN c.title || ' not in VPC.' + ELSE c.title || ' in VPC.' + END AS reason + FROM + aws_ecs_container_instance AS c + LEFT JOIN aws_ec2_instance AS i + ON c.ec2_instance_id = i.instance_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ECS cluster instances should be in a VPC \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_elb_application_lb_listener_certificate_expire_30_days.yaml b/compliance/controls/pending/aws/aws_elb_application_lb_listener_certificate_expire_30_days.yaml old mode 100755 new mode 100644 index fee306702..98a91d3db --- a/compliance/controls/pending/aws/aws_elb_application_lb_listener_certificate_expire_30_days.yaml +++ b/compliance/controls/pending/aws/aws_elb_application_lb_listener_certificate_expire_30_days.yaml @@ -1,13 +1,25 @@ +Description: This control ensures that SSL/TLS certificates used in application load balancers are renewed 30 days before their expiration date. ID: aws_elb_application_lb_listener_certificate_expire_30_days -Title: "ELB application load balancers secured listener certificate should not expire within next 30 days" -Description: "This control ensures that SSL/TLS certificates used in application load balancers are renewed 30 days before their expiration date." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n load_balancer_arn as resource,\n case\n when date(not_after) - date(current_date) >= 30 then 'ok'\n else 'alarm'\n end as status,\n l.title || ' certificate set to expire in ' || extract(day from not_after - current_date) || ' days.' as reason\n \nfrom\n aws_ec2_load_balancer_listener as l,\n jsonb_array_elements(certificates) as c\n left join aws_acm_certificate as a on c ->> 'CertificateArn' = a.certificate_arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + load_balancer_arn AS resource, + CASE + WHEN DATE(not_after) - DATE(current_date) >= 30 THEN 'ok' + ELSE 'alarm' + END AS status, + l.title || ' certificate set to expire in ' || EXTRACT(DAY FROM not_after - current_date) || ' days.' AS reason + FROM + aws_ec2_load_balancer_listener AS l, + jsonb_array_elements(certificates) AS c + LEFT JOIN aws_acm_certificate AS a + ON c ->> 'CertificateArn' = a.certificate_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB application load balancers secured listener certificate should not expire within next 30 days \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_elb_application_lb_listener_certificate_expire_7_days.yaml b/compliance/controls/pending/aws/aws_elb_application_lb_listener_certificate_expire_7_days.yaml old mode 100755 new mode 100644 index 3ad4c242d..2f966285b --- a/compliance/controls/pending/aws/aws_elb_application_lb_listener_certificate_expire_7_days.yaml +++ b/compliance/controls/pending/aws/aws_elb_application_lb_listener_certificate_expire_7_days.yaml @@ -1,13 +1,24 @@ +Description: This control ensures that SSL/TLS certificates used in application load balancers are renewed 7 days before their expiration date. ID: aws_elb_application_lb_listener_certificate_expire_7_days -Title: "ELB application load balancers secured listener certificate should not expire within next 7 days" -Description: "This control ensures that SSL/TLS certificates used in application load balancers are renewed 7 days before their expiration date." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n load_balancer_arn as resource,\n case\n when date(not_after) - date(current_date) >= 7 then 'ok'\n else 'alarm'\n end as status,\n l.title || ' certificate set to expire in ' || extract(day from not_after - current_date) || ' days.' as reason\n \nfrom\n aws_ec2_load_balancer_listener as l,\n jsonb_array_elements(certificates) as c\n left join aws_acm_certificate as a on c ->> 'CertificateArn' = a.certificate_arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + load_balancer_arn AS resource, + CASE + WHEN DATE(not_after) - DATE(current_date) >= 7 THEN 'ok' + ELSE 'alarm' + END AS status, + l.title || ' certificate set to expire in ' || EXTRACT(day FROM not_after - current_date) || ' days.' AS reason + FROM + aws_ec2_load_balancer_listener AS l, + jsonb_array_elements(certificates) AS c + LEFT JOIN aws_acm_certificate AS a ON c ->> 'CertificateArn' = a.certificate_arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: ELB application load balancers secured listener certificate should not expire within next 7 days \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_emr_cluster_encryption_at_rest_enabled.yaml b/compliance/controls/pending/aws/aws_emr_cluster_encryption_at_rest_enabled.yaml old mode 100755 new mode 100644 index e1478564e..409ccc2b5 --- a/compliance/controls/pending/aws/aws_emr_cluster_encryption_at_rest_enabled.yaml +++ b/compliance/controls/pending/aws/aws_emr_cluster_encryption_at_rest_enabled.yaml @@ -1,13 +1,31 @@ +Description: This control checks whether EMR clusters have encryption at rest enabled. The check fails if encryption at rest is not enabled as sensitive data should be protected. ID: aws_emr_cluster_encryption_at_rest_enabled -Title: "EMR clusters encryption at rest should be enabled" -Description: "This control checks whether EMR clusters have encryption at rest enabled. The check fails if encryption at rest is not enabled as sensitive data should be protected." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n cluster_arn as resource,\n case\n when s.name is null then 'alarm'\n when s.name is not null and (encryption_configuration -> 'EnableAtRestEncryption')::bool then 'ok'\n else 'alarm'\n end as status,\n case\n when s.name is null then c.title || ' security configuration disabled.'\n when s.name is not null and (encryption_configuration -> 'EnableAtRestEncryption')::bool then c.title || ' encryption at rest enabled.'\n else c.title || ' encryption at rest disabled.'\n end as reason\n \n \nfrom\n aws_emr_cluster as c\n left join aws_emr_security_configuration as s on c.security_configuration = s.name and s.region = s.region and s.account_id = c.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + cluster_arn AS resource, + CASE + WHEN s.name IS NULL THEN 'alarm' + WHEN s.name IS NOT NULL AND (encryption_configuration -> 'EnableAtRestEncryption')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.name IS NULL THEN c.title || ' security configuration disabled.' + WHEN s.name IS NOT NULL AND (encryption_configuration -> 'EnableAtRestEncryption')::bool THEN c.title || ' encryption at rest enabled.' + ELSE c.title || ' encryption at rest disabled.' + END AS reason + FROM + aws_emr_cluster AS c + LEFT JOIN aws_emr_security_configuration AS s + ON c.security_configuration = s.name + AND s.region = s.region + AND s.account_id = c.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EMR clusters encryption at rest should be enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_emr_cluster_encryption_at_rest_with_cse_cmk.yaml b/compliance/controls/pending/aws/aws_emr_cluster_encryption_at_rest_with_cse_cmk.yaml old mode 100755 new mode 100644 index 854260172..2bfdc87ed --- a/compliance/controls/pending/aws/aws_emr_cluster_encryption_at_rest_with_cse_cmk.yaml +++ b/compliance/controls/pending/aws/aws_emr_cluster_encryption_at_rest_with_cse_cmk.yaml @@ -1,13 +1,35 @@ +Description: This control checks whether EMR client side encryption (CSE CMK) is enabled with CMK. The check fails if encryption at rest is not enabled with CSE-CMK. ID: aws_emr_cluster_encryption_at_rest_with_cse_cmk -Title: "EMR clusters client side encryption (CSE CMK) enabled with CMK" -Description: "This control checks whether EMR client side encryption (CSE CMK) is enabled with CMK. The check fails if encryption at rest is not enabled with CSE-CMK." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n cluster_arn as resource,\n case\n when s.name is null then 'alarm'\n when not (encryption_configuration -> 'EnableAtRestEncryption')::bool then 'alarm'\n when (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'S3EncryptionConfiguration' ->> 'EncryptionMode') = 'CSE-Custom' then 'ok'\n else 'alarm'\n end as status,\n case\n when s.name is null then c.title || ' security configuration disabled.'\n when not (encryption_configuration -> 'EnableAtRestEncryption')::bool then c.title || ' encryption at rest disabled.'\n when (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'S3EncryptionConfiguration' ->> 'EncryptionMode') = 'CSE-Custom' then c.title || ' encryption at rest enabled with CSE-CMK.'\n else c.title || ' encryption at rest not enabled with CSE-CMK.'\n end as reason\n \n \nfrom\n aws_emr_cluster as c\n left join aws_emr_security_configuration as s on c.security_configuration = s.name and s.region = s.region and s.account_id = c.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + cluster_arn AS resource, + CASE + WHEN s.name IS NULL THEN 'alarm' + WHEN NOT (encryption_configuration -> 'EnableAtRestEncryption')::bool THEN 'alarm' + WHEN (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'S3EncryptionConfiguration' ->> 'EncryptionMode') = 'CSE-Custom' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.name IS NULL THEN c.title || ' security configuration disabled.' + WHEN NOT (encryption_configuration -> 'EnableAtRestEncryption')::bool THEN c.title || ' encryption at rest disabled.' + WHEN (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'S3EncryptionConfiguration' ->> 'EncryptionMode') = 'CSE-Custom' THEN c.title || ' encryption at rest enabled with CSE-CMK.' + ELSE c.title || ' encryption at rest not enabled with CSE-CMK.' + END AS reason + FROM + aws_emr_cluster AS c + LEFT JOIN + aws_emr_security_configuration AS s + ON + c.security_configuration = s.name + AND s.region = s.region + AND s.account_id = c.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EMR clusters client side encryption (CSE CMK) enabled with CMK \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_emr_cluster_encryption_in_transit_enabled.yaml b/compliance/controls/pending/aws/aws_emr_cluster_encryption_in_transit_enabled.yaml old mode 100755 new mode 100644 index b11aa7efc..8dae81b9f --- a/compliance/controls/pending/aws/aws_emr_cluster_encryption_in_transit_enabled.yaml +++ b/compliance/controls/pending/aws/aws_emr_cluster_encryption_in_transit_enabled.yaml @@ -1,13 +1,32 @@ +Description: This control checks whether EMR clusters have encryption in transit enabled. This control fails if an EMR cluster isn't encrypted in transit. ID: aws_emr_cluster_encryption_in_transit_enabled -Title: "EMR clusters encryption in transit should be enabled" -Description: "This control checks whether EMR clusters have encryption in transit enabled. This control fails if an EMR cluster isn't encrypted in transit." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n cluster_arn as resource,\n case\n when s.name is null then 'alarm'\n when s.name is not null and (encryption_configuration -> 'EnableInTransitEncryption')::bool then 'ok'\n else 'alarm'\n end as status,\n case\n when s.name is null then c.title || ' security configuration disabled.'\n when s.name is not null and (encryption_configuration -> 'EnableInTransitEncryption')::bool then c.title || ' encryption in transit enabled.'\n else c.title || ' encryption in transit disabled.'\n end as reason\n \n \nfrom\n aws_emr_cluster as c\n left join aws_emr_security_configuration as s on c.security_configuration = s.name and s.region = s.region and s.account_id = c.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + cluster_arn AS resource, + CASE + WHEN s.name IS NULL THEN 'alarm' + WHEN s.name IS NOT NULL AND (encryption_configuration -> 'EnableInTransitEncryption')::bool THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.name IS NULL THEN c.title || ' security configuration disabled.' + WHEN s.name IS NOT NULL AND (encryption_configuration -> 'EnableInTransitEncryption')::bool THEN c.title || ' encryption in transit enabled.' + ELSE c.title || ' encryption in transit disabled.' + END AS reason + FROM + aws_emr_cluster AS c + LEFT JOIN + aws_emr_security_configuration AS s + ON c.security_configuration = s.name + AND s.region = s.region + AND s.account_id = c.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: EMR clusters encryption in transit should be enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_emr_cluster_local_disk_encryption_enabled.yaml b/compliance/controls/pending/aws/aws_emr_cluster_local_disk_encryption_enabled.yaml old mode 100755 new mode 100644 index 4d9071fa1..955d46aa3 --- a/compliance/controls/pending/aws/aws_emr_cluster_local_disk_encryption_enabled.yaml +++ b/compliance/controls/pending/aws/aws_emr_cluster_local_disk_encryption_enabled.yaml @@ -1,13 +1,32 @@ ID: aws_emr_cluster_local_disk_encryption_enabled Title: "EMR clusters local disk encryption should be enabled" -Description: "This control checks whether EMR cluster have local disk encryption enabled. This control fails if an EMR cluster local disk isn't encrypted." +Description: "This control checks whether EMR clusters have local disk encryption enabled. This control fails if an EMR cluster's local disk isn't encrypted." Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n cluster_arn as resource,\n case\n when s.name is null then 'alarm'\n when s.name is not null\n and (encryption_configuration -> 'EnableAtRestEncryption')::bool\n and (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when s.name is null then c.title || ' security configuration disabled.'\n when s.name is not null\n and (encryption_configuration -> 'EnableAtRestEncryption')::bool\n and (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') is not null then c.title || ' local disk encryption enabled.'\n else c.title || ' local disk encryption disabled.'\n end as reason\n \n \nfrom\n aws_emr_cluster as c\n left join aws_emr_security_configuration as s on c.security_configuration = s.name and s.region = s.region and s.account_id = c.account_id;\n" + QueryToExecute: | + SELECT + cluster_arn AS resource, + CASE + WHEN s.name IS NULL THEN 'alarm' + WHEN s.name IS NOT NULL + AND (encryption_configuration -> 'EnableAtRestEncryption')::bool + AND (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.name IS NULL THEN c.title || ' security configuration disabled.' + WHEN s.name IS NOT NULL + AND (encryption_configuration -> 'EnableAtRestEncryption')::bool + AND (encryption_configuration -> 'AtRestEncryptionConfiguration' -> 'LocalDiskEncryptionConfiguration') IS NOT NULL THEN c.title || ' local disk encryption enabled.' + ELSE c.title || ' local disk encryption disabled.' + END AS reason + FROM + aws_emr_cluster AS c + LEFT JOIN aws_emr_security_configuration AS s ON c.security_configuration = s.name AND s.region = s.region AND s.account_id = c.account_id; PrimaryTable: "" ListOfTables: [] Parameters: [] Severity: low Tags: {} IntegrationType: - - aws_cloud_account + - aws_cloud_account \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_cloudfront_13.yaml b/compliance/controls/pending/aws/aws_foundational_security_cloudfront_13.yaml old mode 100755 new mode 100644 index e1431e6e2..fd310e4fb --- a/compliance/controls/pending/aws/aws_foundational_security_cloudfront_13.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_cloudfront_13.yaml @@ -1,13 +1,30 @@ +Description: This control checks whether an Amazon CloudFront distribution with an Amazon S3 origin has origin access control (OAC) configured. The control fails if OAC isn't configured for the CloudFront distribution. ID: aws_foundational_security_cloudfront_13 -Title: "13 CloudFront distributions should use origin access control" -Description: "This control checks whether an Amazon CloudFront distribution with an Amazon S3 origin has origin access control (OAC) configured. The control fails if OAC isn't configured for the CloudFront distribution." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when o ->> 'DomainName' not like '%s3.amazonaws.com' then 'skip'\n when o ->> 'DomainName' like '%s3.amazonaws.com'\n and o -> 'S3OriginConfig' ->> 'OriginAccessIdentity' = '' then 'alarm'\n else 'ok'\n end as status,\n case\n when o ->> 'DomainName' not like '%s3.amazonaws.com' then title || ' origin type is not s3.'\n when o ->> 'DomainName' like '%s3.amazonaws.com'\n and o -> 'S3OriginConfig' ->> 'OriginAccessIdentity' = '' then title || ' origin access identity not configured.'\n else title || ' origin access identity configured.'\n end as reason\n \n \nfrom\n aws_cloudfront_distribution,\n jsonb_array_elements(origins) as o;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN o ->> 'DomainName' NOT LIKE '%s3.amazonaws.com' THEN 'skip' + WHEN o ->> 'DomainName' LIKE '%s3.amazonaws.com' + AND o -> 'S3OriginConfig' ->> 'OriginAccessIdentity' = '' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN o ->> 'DomainName' NOT LIKE '%s3.amazonaws.com' THEN title || ' origin type is not s3.' + WHEN o ->> 'DomainName' LIKE '%s3.amazonaws.com' + AND o -> 'S3OriginConfig' ->> 'OriginAccessIdentity' = '' THEN title || ' origin access identity not configured.' + ELSE title || ' origin access identity configured.' + END AS reason + FROM + aws_cloudfront_distribution, + jsonb_array_elements(origins) AS o; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 13 CloudFront distributions should use origin access control \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_cloudfront_9.yaml b/compliance/controls/pending/aws/aws_foundational_security_cloudfront_9.yaml old mode 100755 new mode 100644 index c0372b536..1e847f2c1 --- a/compliance/controls/pending/aws/aws_foundational_security_cloudfront_9.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_cloudfront_9.yaml @@ -1,13 +1,56 @@ +Description: This control checks if Amazon CloudFront distributions are encrypting traffic to custom origins. This control fails for a CloudFront distribution whose origin protocol policy allows 'http-only'. This control also fails if the distribution's origin protocol policy is 'match-viewer' while the viewer protocol policy is 'allow-all'. ID: aws_foundational_security_cloudfront_9 -Title: "9 CloudFront distributions should encrypt traffic to custom origins" -Description: "This control checks if Amazon CloudFront distributions are encrypting traffic to custom origins. This control fails for a CloudFront distribution whose origin protocol policy allows 'http-only'. This control also fails if the distribution's origin protocol policy is 'match-viewer' while the viewer protocol policy is 'allow-all'." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with viewer_protocol_policy_value as (\n select\n distinct arn\n from\n aws_cloudfront_distribution,\n jsonb_array_elements(\n case jsonb_typeof(cache_behaviors -> 'Items')\n when 'array' then (cache_behaviors -> 'Items')\n else null end\n ) as cb\n where\n cb ->> 'ViewerProtocolPolicy' = 'allow-all'\n),\norigin_protocol_policy_value as (\n select\n distinct arn,\n o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' as origin_protocol_policy\n from\n aws_cloudfront_distribution,\n jsonb_array_elements(origins) as o\n where\n o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'http-only'\n or o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'match-viewer'\n)\nselect\n b.arn as resource,\n case\n when o.arn is not null and o.origin_protocol_policy = 'http-only' then 'alarm'\n when o.arn is not null and o.origin_protocol_policy = 'match-viewer' and ( v.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') ) then 'alarm'\n else 'ok'\n end as status,\n case\n when o.arn is not null and o.origin_protocol_policy = 'http-only' then title || ' custom origins traffic not encrypted in transit.'\n when o.arn is not null and o.origin_protocol_policy = 'match-viewer' and ( v.arn is not null or (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all') ) then title || ' custom origins traffic not encrypted in transit.'\n else title || ' custom origins traffic encrypted in transit.'\n end as reason\n \n \nfrom\n aws_cloudfront_distribution as b\n left join origin_protocol_policy_value as o on b.arn = o.arn\n left join viewer_protocol_policy_value as v on b.arn = v.arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH viewer_protocol_policy_value AS ( + SELECT + DISTINCT arn + FROM + aws_cloudfront_distribution, + jsonb_array_elements( + CASE jsonb_typeof(cache_behaviors -> 'Items') + WHEN 'array' THEN (cache_behaviors -> 'Items') + ELSE NULL + END + ) AS cb + WHERE + cb ->> 'ViewerProtocolPolicy' = 'allow-all' + ), + origin_protocol_policy_value AS ( + SELECT + DISTINCT arn, + o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' AS origin_protocol_policy + FROM + aws_cloudfront_distribution, + jsonb_array_elements(origins) AS o + WHERE + o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'http-only' + OR o -> 'CustomOriginConfig' ->> 'OriginProtocolPolicy' = 'match-viewer' + ) + SELECT + b.arn AS resource, + CASE + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'http-only' THEN 'alarm' + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'match-viewer' AND + (v.arn IS NOT NULL OR (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all')) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'http-only' THEN title || ' custom origins traffic not encrypted in transit.' + WHEN o.arn IS NOT NULL AND o.origin_protocol_policy = 'match-viewer' AND + (v.arn IS NOT NULL OR (default_cache_behavior ->> 'ViewerProtocolPolicy' = 'allow-all')) THEN title || ' custom origins traffic not encrypted in transit.' + ELSE title || ' custom origins traffic encrypted in transit.' + END AS reason + FROM + aws_cloudfront_distribution AS b + LEFT JOIN origin_protocol_policy_value AS o ON b.arn = o.arn + LEFT JOIN viewer_protocol_policy_value AS v ON b.arn = v.arn Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 9 CloudFront distributions should encrypt traffic to custom origins \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_dms_7.yaml b/compliance/controls/pending/aws/aws_foundational_security_dms_7.yaml old mode 100755 new mode 100644 index 8b16409e7..979c25694 --- a/compliance/controls/pending/aws/aws_foundational_security_dms_7.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_dms_7.yaml @@ -1,13 +1,52 @@ +Description: This control checks whether logging is enabled with the minimum severity level of LOGGER_SEVERITY_DEFAULT for DMS replication tasks TARGET_APPLY and TARGET_LOAD. The control fails if logging isn't enabled for these tasks or if the minimum severity level is less than LOGGER_SEVERITY_DEFAULT. ID: aws_foundational_security_dms_7 -Title: "7 DMS replication tasks for the target database should have logging enabled" -Description: "This control checks whether logging is enabled with the minimum severity level of LOGGER_SEVERITY_DEFAULT for DMS replication tasks TARGET_APPLY and TARGET_LOAD. The control fails if logging isn't enabled for these tasks or if the minimum severity level is less than LOGGER_SEVERITY_DEFAULT." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with replication_task_target_apply as (\n select\n arn\n from\n aws_dms_replication_task,\n jsonb_array_elements(replication_task_settings -> 'Logging' -> 'LogComponents') as o\n where\n o ->> 'Id' = 'TARGET_APPLY'\n and o ->> 'Severity' in ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')\n), replication_task_target_load as (\n select\n arn\n from\n aws_dms_replication_task,\n jsonb_array_elements(replication_task_settings -> 'Logging' -> 'LogComponents') as o\n where\n o ->> 'Id' = 'TARGET_LOAD'\n and o ->> 'Severity' in ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG')\n)\nselect\n t.arn as resource,\n (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool,\n case\n when (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool\n and a.arn is not null\n and l.arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool\n and a.arn is not null\n and l.arn is not null then title || ' target database logging enabled.'\n else title || 'target database logging disabled.'\n end as reason\n \n \nfrom\n aws_dms_replication_task as t\n left join replication_task_target_apply as a on a.arn = t.arn\n left join replication_task_target_load as l on l.arn = t.arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH replication_task_target_apply AS ( + SELECT + arn + FROM + aws_dms_replication_task, + jsonb_array_elements(replication_task_settings -> 'Logging' -> 'LogComponents') AS o + WHERE + o ->> 'Id' = 'TARGET_APPLY' + AND o ->> 'Severity' IN ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG') + ), + replication_task_target_load AS ( + SELECT + arn + FROM + aws_dms_replication_task, + jsonb_array_elements(replication_task_settings -> 'Logging' -> 'LogComponents') AS o + WHERE + o ->> 'Id' = 'TARGET_LOAD' + AND o ->> 'Severity' IN ('LOGGER_SEVERITY_DEFAULT', 'LOGGER_SEVERITY_DEBUG', 'LOGGER_SEVERITY_DETAILED_DEBUG') + ) + SELECT + t.arn AS resource, + (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool, + CASE + WHEN (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool + AND a.arn IS NOT NULL + AND l.arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (replication_task_settings -> 'Logging' ->> 'EnableLogging')::bool + AND a.arn IS NOT NULL + AND l.arn IS NOT NULL THEN title || ' target database logging enabled.' + ELSE title || 'target database logging disabled.' + END AS reason + FROM + aws_dms_replication_task AS t + LEFT JOIN replication_task_target_apply AS a ON a.arn = t.arn + LEFT JOIN replication_task_target_load AS l ON l.arn = t.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 DMS replication tasks for the target database should have logging enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_docdb_3.yaml b/compliance/controls/pending/aws/aws_foundational_security_docdb_3.yaml old mode 100755 new mode 100644 index e4d3b74e1..66833343f --- a/compliance/controls/pending/aws/aws_foundational_security_docdb_3.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_docdb_3.yaml @@ -1,13 +1,28 @@ +Description: This control checks whether an Amazon DocumentDB manual cluster snapshot is public. The control fails if the manual cluster snapshot is public. ID: aws_foundational_security_docdb_3 -Title: "3 Amazon DocumentDB manual cluster snapshots should not be public" -Description: "This control checks whether an Amazon DocumentDB manual cluster snapshot is public. The control fails if the manual cluster snapshot is public." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when (cluster_snapshot ->> 'AttributeName' = 'restore') and cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when (cluster_snapshot ->> 'AttributeName' = 'restore') and cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then title || ' does not restrict public access.'\n else title || ' restrict public access.'\n end reason\n \n \nfrom\n aws_docdb_cluster_snapshot,\n jsonb_array_elements(db_cluster_snapshot_attributes) as cluster_snapshot;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN (cluster_snapshot->>'AttributeName' = 'restore') + AND cluster_snapshot->'AttributeValues' = '["all"]' THEN 'alarm' + ELSE 'ok' + END status, + CASE + WHEN (cluster_snapshot->>'AttributeName' = 'restore') + AND cluster_snapshot->'AttributeValues' = '["all"]' THEN title || ' does not restrict public access.' + ELSE title || ' restrict public access.' + END reason + FROM + aws_docdb_cluster_snapshot, + jsonb_array_elements(db_cluster_snapshot_attributes) AS cluster_snapshot; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Amazon DocumentDB manual cluster snapshots should not be public \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_ec2_10.yaml b/compliance/controls/pending/aws/aws_foundational_security_ec2_10.yaml old mode 100755 new mode 100644 index 9a23ac3b4..98c75bcf4 --- a/compliance/controls/pending/aws/aws_foundational_security_ec2_10.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_ec2_10.yaml @@ -1,13 +1,39 @@ +Description: This control checks whether a service endpoint for Amazon EC2 is created for each VPC. The control fails if a VPC does not have a VPC endpoint created for the Amazon EC2 service. ID: aws_foundational_security_ec2_10 -Title: "10 Amazon EC2 should be configured to use VPC endpoints" -Description: "This control checks whether a service endpoint for Amazon EC2 is created for each VPC. The control fails if a VPC does not have a VPC endpoint created for the Amazon EC2 service." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when vpc_id not in (\n select\n vpc_id\n from\n aws_vpc_endpoint\n where\n service_name like 'com.amazonaws.' || region || '.ec2'\n ) then 'alarm'\n else 'ok'\n end as status,\n case\n when vpc_id not in (\n select\n vpc_id\n from\n aws_vpc_endpoint\n where\n service_name like 'com.amazonaws.' || region || '.ec2'\n ) then title || ' not configured to use VPC endpoints.'\n else title || ' configured to use VPC endpoints.'\n end as reason\n \n \nfrom\n aws_vpc;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN vpc_id NOT IN ( + SELECT + vpc_id + FROM + aws_vpc_endpoint + WHERE + service_name LIKE 'com.amazonaws.' || region || '.ec2' + ) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN vpc_id NOT IN ( + SELECT + vpc_id + FROM + aws_vpc_endpoint + WHERE + service_name LIKE 'com.amazonaws.' || region || '.ec2' + ) THEN title || ' not configured to use VPC endpoints.' + ELSE title || ' configured to use VPC endpoints.' + END AS reason + FROM + aws_vpc; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 10 Amazon EC2 should be configured to use VPC endpoints \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_ec2_21.yaml b/compliance/controls/pending/aws/aws_foundational_security_ec2_21.yaml old mode 100755 new mode 100644 index 5a4c76618..ef4f47421 --- a/compliance/controls/pending/aws/aws_foundational_security_ec2_21.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_ec2_21.yaml @@ -1,13 +1,84 @@ +Description: This control checks if default ports for SSH/RDP ingress traffic for network access control lists (NACLs) is unrestricted. The rule fails if a NACL inbound entry allows a source CIDR block of '0.0.0.0/0' or '::/0' for ports 22 or 3389. ID: aws_foundational_security_ec2_21 -Title: "21 Network ACLs should not allow ingress from 0.0.0.0/0 to port 22 or port 3389" -Description: "This control checks if default ports for SSH/RDP ingress traffic for network access control lists (NACLs) is unrestricted. The rule fails if a NACL inbound entry allows a source CIDR block of '0.0.0.0/0' or '::/0' for ports 22 or 3389." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with bad_rules as (\n select\n network_acl_id,\n count(*) as num_bad_rules,\n tags,\n region,\n account_id\n from\n aws_vpc_network_acl,\n jsonb_array_elements(entries) as att\n where\n att ->> 'Egress' = 'false' -- as per aws egress = false indicates the ingress\n and (\n att ->> 'CidrBlock' = '0.0.0.0/0'\n or att ->> 'Ipv6CidrBlock' = '::/0'\n )\n and att ->> 'RuleAction' = 'allow'\n and (\n (\n att ->> 'Protocol' = '-1' -- all traffic\n and att ->> 'PortRange' is null\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 22\n and (att -> 'PortRange' ->> 'To') :: int >= 22\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n or (\n (att -> 'PortRange' ->> 'From') :: int <= 3389\n and (att -> 'PortRange' ->> 'To') :: int >= 3389\n and att ->> 'Protocol' in('6', '17') -- TCP or UDP\n )\n )\n group by\n network_acl_id,\n region,\n account_id,\n tags\n order by\n network_acl_id,\n region,\n account_id,\n tags\n),\naws_vpc_network_acls as (\n select\n network_acl_id,\n tags,\n partition,\n region,\n account_id\n from\n aws_vpc_network_acl\n order by\n network_acl_id,\n region,\n account_id\n)\nselect\n 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id as resource,\n case\n when bad_rules.network_acl_id is null then 'ok'\n else 'alarm'\n end as status,\n case\n when bad_rules.network_acl_id is null then acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n else acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.'\n end as reason\n \n \nfrom\n aws_vpc_network_acls as acl\n left join bad_rules on bad_rules.network_acl_id = acl.network_acl_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH bad_rules AS ( + SELECT + network_acl_id, + COUNT(*) AS num_bad_rules, + tags, + region, + account_id + FROM + aws_vpc_network_acl, + jsonb_array_elements(entries) AS att + WHERE + att ->> 'Egress' = 'false' + AND ( + att ->> 'CidrBlock' = '0.0.0.0/0' + OR att ->> 'Ipv6CidrBlock' = '::/0' + ) + AND att ->> 'RuleAction' = 'allow' + AND ( + ( + att ->> 'Protocol' = '-1' + AND att ->> 'PortRange' IS NULL + ) + OR ( + (att -> 'PortRange' ->> 'From')::int <= 22 + AND (att -> 'PortRange' ->> 'To')::int >= 22 + AND att ->> 'Protocol' IN ('6', '17') + ) + OR ( + (att -> 'PortRange' ->> 'From')::int <= 3389 + AND (att -> 'PortRange' ->> 'To')::int >= 3389 + AND att ->> 'Protocol' IN ('6', '17') + ) + ) + GROUP BY + network_acl_id, + region, + account_id, + tags + ORDER BY + network_acl_id, + region, + account_id, + tags + ), + aws_vpc_network_acls AS ( + SELECT + network_acl_id, + tags, + partition, + region, + account_id + FROM + aws_vpc_network_acl + ORDER BY + network_acl_id, + region, + account_id + ) + SELECT + 'arn:' || acl.partition || ':ec2:' || acl.region || ':' || acl.account_id || ':network-acl/' || acl.network_acl_id AS resource, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN bad_rules.network_acl_id IS NULL THEN acl.network_acl_id || ' does not allow ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + ELSE acl.network_acl_id || ' contains ' || bad_rules.num_bad_rules || ' rule(s) allowing ingress to port 22 or 3389 from 0.0.0.0/0 or ::/0.' + END AS reason + FROM + aws_vpc_network_acls AS acl + LEFT JOIN bad_rules ON bad_rules.network_acl_id = acl.network_acl_id Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 21 Network ACLs should not allow ingress from 0.0.0.0/0 to port 22 or port 3389 \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_ec2_25.yaml b/compliance/controls/pending/aws/aws_foundational_security_ec2_25.yaml old mode 100755 new mode 100644 index b5fc7124f..0d14699a5 --- a/compliance/controls/pending/aws/aws_foundational_security_ec2_25.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_ec2_25.yaml @@ -1,13 +1,43 @@ +Description: This control checks if Amazon EC2 launch templates are configured to assign public IP addresses to network interfaces upon launch. The control fails if an EC2 launch template is configured to assign a public IP address to network interfaces or if there is at least one network interface that has a public IP address. ID: aws_foundational_security_ec2_25 -Title: "25 Amazon EC2 launch templates should not assign public IPs to network interfaces" -Description: "This control checks if Amazon EC2 launch templates are configured to assign public IP addresses to network interfaces upon launch. The control fails if an EC2 launch template is configured to assign a public IP address to network interfaces or if there is at least one network interface that has a public IP address." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with public_launch_templates as (\n select\n i.tags ->> 'aws:ec2launchtemplate:id' as public_launch_template_id\n from\n aws_ec2_instance as i,\n jsonb_array_elements(launch_template_data -> 'NetworkInterfaces') as nic\n where\n (nic -> 'AssociatePublicIpAddress')::bool\n),\nlaunch_templates_associated_instance as (\n select\n distinct tags ->> 'aws:ec2launchtemplate:id' as launch_template_id\n from\n aws_ec2_instance\n)\nselect\n t.launch_template_id as resource,\n case\n when i.launch_template_id is null then 'skip'\n when t.launch_template_id in ( select public_launch_template_id from public_launch_templates ) then 'alarm'\n else 'ok'\n end as status,\n case\n when i.launch_template_id is null then t.title || ' does not launch any instance.'\n when t.launch_template_id in ( select public_launch_template_id from public_launch_templates ) then t.title || ' publicly accessible.'\n else t.title || ' not publicly accessible.'\n end as reason\n \n \nfrom\n aws_ec2_launch_template as t\n left join launch_templates_associated_instance as i on i.launch_template_id = t.launch_template_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH public_launch_templates AS ( + SELECT + i.tags ->> 'aws:ec2launchtemplate:id' AS public_launch_template_id + FROM + aws_ec2_instance AS i, + jsonb_array_elements(launch_template_data -> 'NetworkInterfaces') AS nic + WHERE + (nic -> 'AssociatePublicIpAddress')::bool + ), + launch_templates_associated_instance AS ( + SELECT + DISTINCT tags ->> 'aws:ec2launchtemplate:id' AS launch_template_id + FROM + aws_ec2_instance + ) + SELECT + t.launch_template_id AS resource, + CASE + WHEN i.launch_template_id IS NULL THEN 'skip' + WHEN t.launch_template_id IN (SELECT public_launch_template_id FROM public_launch_templates) THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN i.launch_template_id IS NULL THEN t.title || ' does not launch any instance.' + WHEN t.launch_template_id IN (SELECT public_launch_template_id FROM public_launch_templates) THEN t.title || ' publicly accessible.' + ELSE t.title || ' not publicly accessible.' + END AS reason + FROM + aws_ec2_launch_template AS t + LEFT JOIN launch_templates_associated_instance AS i ON i.launch_template_id = t.launch_template_id Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 25 Amazon EC2 launch templates should not assign public IPs to network interfaces \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_ec2_6.yaml b/compliance/controls/pending/aws/aws_foundational_security_ec2_6.yaml old mode 100755 new mode 100644 index 1a77ea301..f1d63f5ae --- a/compliance/controls/pending/aws/aws_foundational_security_ec2_6.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_ec2_6.yaml @@ -1,13 +1,53 @@ +Description: This control checks whether Amazon VPC Flow Logs are found and enabled for VPCs. The traffic type is set to Reject. With the VPC Flow Logs feature, you can capture information about the IP address traffic going to and from network interfaces in your VPC. After you create a flow log, you can view and retrieve its data in CloudWatch Logs. To reduce cost, you can also send your flow logs to Amazon S3. ID: aws_foundational_security_ec2_6 -Title: "6 VPC flow logging should be enabled in all VPCs" -Description: "This control checks whether Amazon VPC Flow Logs are found and enabled for VPCs. The traffic type is set to Reject. With the VPC Flow Logs feature, you can capture information about the IP address traffic going to and from network interfaces in your VPC. After you create a flow log, you can view and retrieve its data in CloudWatch Logs. To reduce cost, you can also send your flow logs to Amazon S3." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with vpcs as (\n select\n arn,\n account_id,\n region,\n owner_id,\n vpc_id,\n tags,\n _ctx\n from\n aws_vpc\n order by\n vpc_id\n),\nflowlogs as (\n select\n resource_id,\n account_id,\n region\n from\n aws_vpc_flow_log\n order by\n resource_id\n)\nselect\n v.arn as resource,\n case\n when v.account_id <> v.owner_id then 'skip'\n when f.resource_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when v.account_id <> v.owner_id then v.vpc_id || ' is a shared VPC.'\n when f.resource_id is not null then v.vpc_id || ' flow logging enabled.'\n else v.vpc_id || ' flow logging disabled.'\n end as reason\n \n \nfrom\n vpcs as v\n left join flowlogs as f on v.vpc_id = f.resource_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH vpcs AS ( + SELECT + arn, + account_id, + region, + owner_id, + vpc_id, + tags, + _ctx + FROM + aws_vpc + ORDER BY + vpc_id + ), + flowlogs AS ( + SELECT + resource_id, + account_id, + region + FROM + aws_vpc_flow_log + ORDER BY + resource_id + ) + SELECT + v.arn AS resource, + CASE + WHEN v.account_id <> v.owner_id THEN 'skip' + WHEN f.resource_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN v.account_id <> v.owner_id THEN v.vpc_id || ' is a shared VPC.' + WHEN f.resource_id IS NOT NULL THEN v.vpc_id || ' flow logging enabled.' + ELSE v.vpc_id || ' flow logging disabled.' + END AS reason + FROM + vpcs AS v + LEFT JOIN flowlogs AS f + ON v.vpc_id = f.resource_id; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 VPC flow logging should be enabled in all VPCs \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_elb_13.yaml b/compliance/controls/pending/aws/aws_foundational_security_elb_13.yaml old mode 100755 new mode 100644 index 075350a10..ce9a02d04 --- a/compliance/controls/pending/aws/aws_foundational_security_elb_13.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_elb_13.yaml @@ -1,13 +1,42 @@ +Description: This control checks whether an Elastic Load Balancer V2 (Application, Network, or Gateway Load Balancer) has registered instances from multiple Availability Zones. The control fails if an Elastic Load Balancer V2 has instances registered in fewer than two Availability Zones. ID: aws_foundational_security_elb_13 -Title: "13 Application, Network, and Gateway Load Balancers should span multiple Availability Zones" -Description: "This control checks whether an Elastic Load Balancer V2 (Application, Network, or Gateway Load Balancer) has registered instances from multiple Availability Zones. The control fails if an Elastic Load Balancer V2 has instances registered in fewer than two Availability Zones." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when jsonb_array_length(availability_zones) < 2 then 'alarm'\n else 'ok'\n end as status,\n title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason\n \n \nfrom\n aws_ec2_application_load_balancer\nunion\nselect\n arn as resource,\n case\n when jsonb_array_length(availability_zones) < 2 then 'alarm'\n else 'ok'\n end as status,\n title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason\n \n \nfrom\n aws_ec2_network_load_balancer\nunion\nselect\n arn as resource,\n case\n when jsonb_array_length(availability_zones) < 2 then 'alarm'\n else 'ok'\n end as status,\n title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' as reason\n \n \nfrom\n aws_ec2_gateway_load_balancer;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason + FROM + aws_ec2_application_load_balancer + UNION + SELECT + arn AS resource, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason + FROM + aws_ec2_network_load_balancer + UNION + SELECT + arn AS resource, + CASE + WHEN jsonb_array_length(availability_zones) < 2 THEN 'alarm' + ELSE 'ok' + END AS status, + title || ' has ' || jsonb_array_length(availability_zones) || ' availability zone(s).' AS reason + FROM + aws_ec2_gateway_load_balancer Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 13 Application, Network, and Gateway Load Balancers should span multiple Availability Zones \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_elb_3.yaml b/compliance/controls/pending/aws/aws_foundational_security_elb_3.yaml old mode 100755 new mode 100644 index 4032b0b33..149830f18 --- a/compliance/controls/pending/aws/aws_foundational_security_elb_3.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_elb_3.yaml @@ -1,13 +1,27 @@ +Description: This control checks whether your Classic Load Balancer listeners are configured with HTTPS or TLS protocol for front-end (client to load balancer) connections. The control is applicable if a Classic Load Balancer has listeners. If your Classic Load Balancer does not have a listener configured, then the control does not report any findings. The control passes if the Classic Load Balancer listeners are configured with TLS or HTTPS for front-end connections. The control fails if the listener is not configured with TLS or HTTPS for front-end connections. ID: aws_foundational_security_elb_3 -Title: "3 Classic Load Balancer listeners should be configured with HTTPS or TLS termination" -Description: "This control checks whether your Classic Load Balancer listeners are configured with HTTPS or TLS protocol for front-end (client to load balancer) connections. The control is applicable if a Classic Load Balancer has listeners. If your Classic Load Balancer does not have a listener configured, then the control does not report any findings. The control passes if the Classic Load Balancer listeners are configured with TLS or HTTPS for front-end connections. The control fails if the listener is not configured with TLS or HTTPS for front-end connections." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || partition || ':elasticloadbalancing:' || region || ':' || account_id || ':loadbalancer/' || title as resource,\n case\n when listener_description -> 'Listener' ->> 'Protocol' in ('HTTPS', 'SSL', 'TLS') then 'ok'\n else 'alarm'\n end as status,\n case\n when listener_description -> 'Listener' ->> 'Protocol' = 'HTTPS' then title || ' configured with HTTPS protocol.'\n when listener_description -> 'Listener' ->> 'Protocol' = 'SSL' then title || ' configured with TLS protocol.'\n else title || ' configured with ' || (listener_description -> 'Listener' ->> 'Protocol') || ' protocol.'\n end as reason\n \n \nfrom\n aws_ec2_classic_load_balancer,\n jsonb_array_elements(listener_descriptions) as listener_description;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || partition || ':elasticloadbalancing:' || region || ':' || account_id || ':loadbalancer/' || title AS resource, + CASE + WHEN listener_description -> 'Listener' ->> 'Protocol' IN ('HTTPS', 'SSL', 'TLS') THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN listener_description -> 'Listener' ->> 'Protocol' = 'HTTPS' THEN title || ' configured with HTTPS protocol.' + WHEN listener_description -> 'Listener' ->> 'Protocol' = 'SSL' THEN title || ' configured with TLS protocol.' + ELSE title || ' configured with ' || (listener_description -> 'Listener' ->> 'Protocol') || ' protocol.' + END AS reason + FROM + aws_ec2_classic_load_balancer, + jsonb_array_elements(listener_descriptions) AS listener_description; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 Classic Load Balancer listeners should be configured with HTTPS or TLS termination \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_elb_5.yaml b/compliance/controls/pending/aws/aws_foundational_security_elb_5.yaml old mode 100755 new mode 100644 index 3c9554bfd..132c46327 --- a/compliance/controls/pending/aws/aws_foundational_security_elb_5.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_elb_5.yaml @@ -1,13 +1,42 @@ +Description: This control checks whether the Application Load Balancer and the Classic Load Balancer have logging enabled. The control fails if access_logs.s3.enabled is false. ID: aws_foundational_security_elb_5 -Title: "5 Application and Classic Load Balancers logging should be enabled" -Description: "This control checks whether the Application Load Balancer and the Classic Load Balancer have logging enabled. The control fails if access_logs.s3.enabled is false." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\n select\n arn as resource,\n case\n when load_balancer_attributes @> '[{\"Key\": \"access_logs.s3.enabled\", \"Value\": \"true\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when load_balancer_attributes @> '[{\"Key\": \"access_logs.s3.enabled\", \"Value\": \"true\"}]' then title || ' logging enabled.'\n else title || ' logging disabled.'\n end as reason\n \n \n from\n aws_ec2_application_load_balancer\n)\nunion\n(\n select\n 'arn:' || partition || ':elasticloadbalancing:' || region || ':' || account_id || ':loadbalancer/' || title as resource,\n case\n when access_log_enabled = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when access_log_enabled = 'true' then title || ' logging enabled.'\n else title || ' logging disabled.'\n end as reason\n \n \n from\n aws_ec2_classic_load_balancer\n);\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + arn AS resource, + CASE + WHEN load_balancer_attributes @> '[{"Key": "access_logs.s3.enabled", "Value": "true"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN load_balancer_attributes @> '[{"Key": "access_logs.s3.enabled", "Value": "true"}]' THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason + FROM + aws_ec2_application_load_balancer + ) + UNION + ( + SELECT + 'arn:' || partition || ':elasticloadbalancing:' || region || ':' || account_id || ':loadbalancer/' || title AS resource, + CASE + WHEN access_log_enabled = 'true' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN access_log_enabled = 'true' THEN title || ' logging enabled.' + ELSE title || ' logging disabled.' + END AS reason + FROM + aws_ec2_classic_load_balancer + ); Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 Application and Classic Load Balancers logging should be enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_guardduty_1.yaml b/compliance/controls/pending/aws/aws_foundational_security_guardduty_1.yaml old mode 100755 new mode 100644 index c67b877e8..dd20e15a4 --- a/compliance/controls/pending/aws/aws_foundational_security_guardduty_1.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_guardduty_1.yaml @@ -1,13 +1,33 @@ +Description: This control checks whether Amazon GuardDuty is enabled in your GuardDuty account and Region. It is highly recommended that you enable GuardDuty in all supported AWS Regions. Doing so allows GuardDuty to generate findings about unauthorized or unusual activity, even in Regions that you do not actively use. This also allows GuardDuty to monitor CloudTrail events for global AWS services such as IAM. ID: aws_foundational_security_guardduty_1 -Title: "1 GuardDuty should be enabled" -Description: "This control checks whether Amazon GuardDuty is enabled in your GuardDuty account and Region. It is highly recommended that you enable GuardDuty in all supported AWS Regions. Doing so allows GuardDuty to generate findings about unauthorized or unusual activity, even in Regions that you do not actively use. This also allows GuardDuty to monitor CloudTrail events for global AWS services such as IAM." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource,\n case\n when r.region = any(array['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) then 'skip'\n -- Skip any regions that are disabled in the account.\n when r.opt_in_status = 'not-opted-in' then 'skip'\n when status = 'ENABLED' and master_account ->> 'AccountId' is null then 'ok'\n when status = 'ENABLED' and master_account ->> 'AccountId' is not null then 'info'\n else 'alarm'\n end as status,\n case\n when r.region = any(array['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) then r.region || ' region not supported.'\n when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.'\n when status is null then 'No GuardDuty detector found in ' || r.region || '.'\n when status = 'ENABLED' and master_account ->> 'AccountId' is null then r.region || ' detector ' || d.title || ' enabled.'\n when status = 'ENABLED' and master_account ->> 'AccountId' is not null then r.region || ' detector ' || d.title || ' is managed by account ' || (master_account ->> 'AccountId') || ' via delegated admin.'\n else r.region || ' detector ' || d.title || ' disabled.'\n end as reason\n \nfrom\n aws_region as r\n left join aws_guardduty_detector d on r.account_id = d.account_id and r.name = d.region;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + CASE + WHEN r.region = ANY(array['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) THEN 'skip' + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN status = 'ENABLED' AND master_account ->> 'AccountId' IS NULL THEN 'ok' + WHEN status = 'ENABLED' AND master_account ->> 'AccountId' IS NOT NULL THEN 'info' + ELSE 'alarm' + END AS status, + CASE + WHEN r.region = ANY(array['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) THEN r.region || ' region not supported.' + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN status IS NULL THEN 'No GuardDuty detector found in ' || r.region || '.' + WHEN status = 'ENABLED' AND master_account ->> 'AccountId' IS NULL THEN r.region || ' detector ' || d.title || ' enabled.' + WHEN status = 'ENABLED' AND master_account ->> 'AccountId' IS NOT NULL THEN r.region || ' detector ' || d.title || ' is managed by account ' || (master_account ->> 'AccountId') || ' via delegated admin.' + ELSE r.region || ' detector ' || d.title || ' disabled.' + END AS reason + FROM + aws_region AS r + LEFT JOIN aws_guardduty_detector d ON r.account_id = d.account_id AND r.name = d.region; Severity: high Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 GuardDuty should be enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_iam_6.yaml b/compliance/controls/pending/aws/aws_foundational_security_iam_6.yaml old mode 100755 new mode 100644 index 5cefa573b..b705b3add --- a/compliance/controls/pending/aws/aws_foundational_security_iam_6.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_iam_6.yaml @@ -1,13 +1,29 @@ +Description: This control checks whether your AWS account is enabled to use a hardware multi-factor authentication (MFA) device to sign in with root user credentials. ID: aws_foundational_security_iam_6 -Title: "6 Hardware MFA should be enabled for the root user" -Description: "This control checks whether your AWS account is enabled to use a hardware multi-factor authentication (MFA) device to sign in with root user credentials." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || s.partition || ':::' || s.account_id as resource,\n case\n when s.account_mfa_enabled and d.serial_number is null then 'ok'\n else 'alarm'\n end status,\n case\n when s.account_mfa_enabled = false then 'MFA not enabled for root account.'\n when d.serial_number is not null then 'MFA enabled for root account, but the MFA associated is a virtual device.'\n else 'Hardware MFA device enabled for root account.'\n end reason\n \nfrom\n aws_iam_account_summary as s\n left join aws_iam_virtual_mfa_device as d on (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || s.partition || ':::' || s.account_id AS resource, + CASE + WHEN s.account_mfa_enabled AND d.serial_number IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN s.account_mfa_enabled = FALSE THEN 'MFA not enabled for root account.' + WHEN d.serial_number IS NOT NULL THEN 'MFA enabled for root account, but the MFA associated is a virtual device.' + ELSE 'Hardware MFA device enabled for root account.' + END AS reason + FROM + aws_iam_account_summary AS s + LEFT JOIN + aws_iam_virtual_mfa_device AS d + ON (d.user ->> 'Arn') = 'arn:' || s.partition || ':iam::' || s.account_id || ':root'; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 Hardware MFA should be enabled for the root user \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_iam_7.yaml b/compliance/controls/pending/aws/aws_foundational_security_iam_7.yaml old mode 100755 new mode 100644 index 6aedd7d4f..09e86c220 --- a/compliance/controls/pending/aws/aws_foundational_security_iam_7.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_iam_7.yaml @@ -1,13 +1,46 @@ +Description: This control checks whether the account password policy for IAM users uses the recommended configurations. ID: aws_foundational_security_iam_7 -Title: "7 Password policies for IAM users should have strong configurations" -Description: "This control checks whether the account password policy for IAM users uses the recommended configurations." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when\n minimum_password_length >= 8\n and require_lowercase_characters = 'true'\n and require_uppercase_characters = 'true'\n and require_numbers = 'true'\n and require_symbols = 'true'\n then 'ok'\n else 'alarm'\n end as status,\n case\n when minimum_password_length is null then 'No password policy set.'\n when\n minimum_password_length >= 8\n and require_lowercase_characters = 'true'\n and require_uppercase_characters = 'true'\n and require_numbers = 'true'\n and require_symbols = 'true'\n then 'Strong password policies configured.'\n else 'Password policy ' ||\n concat_ws(', ',\n case when minimum_password_length < 8 then ('minimum password length set to ' || minimum_password_length) end,\n case when not (require_lowercase_characters = 'true') then 'lowercase characters not required' end,\n case when not (require_uppercase_characters = 'true') then 'uppercase characters not required' end,\n case when not (require_numbers) then 'numbers not required' end,\n case when not (require_symbols) then 'symbols not required' end\n ) || '.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN + minimum_password_length >= 8 + AND require_lowercase_characters = 'true' + AND require_uppercase_characters = 'true' + AND require_numbers = 'true' + AND require_symbols = 'true' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN minimum_password_length IS NULL THEN 'No password policy set.' + WHEN + minimum_password_length >= 8 + AND require_lowercase_characters = 'true' + AND require_uppercase_characters = 'true' + AND require_numbers = 'true' + AND require_symbols = 'true' + THEN 'Strong password policies configured.' + ELSE 'Password policy ' || + CONCAT_WS(', ', + CASE WHEN minimum_password_length < 8 THEN ('minimum password length set to ' || minimum_password_length) END, + CASE WHEN NOT (require_lowercase_characters = 'true') THEN 'lowercase characters not required' END, + CASE WHEN NOT (require_uppercase_characters = 'true') THEN 'uppercase characters not required' END, + CASE WHEN NOT (require_numbers) THEN 'numbers not required' END, + CASE WHEN NOT (require_symbols) THEN 'symbols not required' END + ) || '.' + END AS reason + FROM + aws_account AS a + LEFT JOIN aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 7 Password policies for IAM users should have strong configurations \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_kms_2.yaml b/compliance/controls/pending/aws/aws_foundational_security_kms_2.yaml old mode 100755 new mode 100644 index 86a72e95d..b023b8391 --- a/compliance/controls/pending/aws/aws_foundational_security_kms_2.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_kms_2.yaml @@ -1,13 +1,95 @@ +Description: Checks whether the inline policies that are embedded in your IAM identities (role, user, or group) + allow the AWS KMS decryption actions on all KMS keys. This control uses Zelkova, an automated reasoning engine, + to validate and warn you about policies that may grant broad access to your secrets across AWS accounts. + This control fails if kms:Decrypt or kms:ReEncryptFrom actions are allowed on all KMS keys in an inline policy. ID: aws_foundational_security_kms_2 -Title: "2 IAM principals should not have IAM inline policies that allow decryption actions on all KMS keys" -Description: "Checks whether the inline policies that are embedded in your IAM identities (role, user, or group) allow the AWS KMS decryption actions on all KMS keys. This control uses Zelkova, an automated reasoning engine, to validate and warn you about policies that may grant broad access to your secrets across AWS accounts. This control fails if kms:Decrypt or kms:ReEncryptFrom actions are allowed on all KMS keys in an inline policy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with user_with_decrypt_grant as (\n select\n distinct arn\n from\n aws_iam_user,\n jsonb_array_elements(inline_policies_std) as inline_policy,\n jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') as statement\n where\n statement ->> 'Effect' = 'Allow'\n and statement -> 'Resource' ?| array['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*']\n and statement -> 'Action' ?| array['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom']\n),\nrole_with_decrypt_grant as (\n select\n distinct arn\n from\n aws_iam_role,\n jsonb_array_elements(inline_policies_std) as inline_policy,\n jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') as statement\n where\n statement ->> 'Effect' = 'Allow'\n and statement -> 'Resource' ?| array['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*']\n and statement -> 'Action' ?| array['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom']\n),\ngroup_with_decrypt_grant as (\n select\n distinct arn\n from\n aws_iam_group,\n jsonb_array_elements(inline_policies_std) as inline_policy,\n jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') as statement\n where\n statement ->> 'Effect' = 'Allow'\n and statement -> 'Resource' ?| array['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*']\n and statement -> 'Action' ?| array['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom']\n)\nselect\n i.arn as resource,\n case\n when d.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when d.arn is null then 'User ' || i.title || ' not allowed to perform decryption actions on all keys.'\n else 'User ' || i.title || ' allowed to perform decryption actions on all keys.'\n end as reason\n\n \nfrom\n aws_iam_user i\n left join user_with_decrypt_grant d on i.arn = d.arn\nunion\nselect\n r.arn as resource,\n case\n when d.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when d.arn is null then 'Role ' || r.title || ' not allowed to perform decryption actions on all keys.'\n else 'Role ' || r.title || ' allowed to perform decryption actions on all keys.'\n end as reason\n\n \nfrom\n aws_iam_role r\n left join role_with_decrypt_grant d on r.arn = d.arn\nwhere\n r.arn not like '%service-role/%'\nunion\nselect\n g.arn as resource,\n case\n when d.arn is null then 'ok'\n else 'alarm'\n end as status,\n case\n when d.arn is null then 'Role ' || g.title || ' not allowed to perform decryption actions on all keys.'\n else 'Group ' || g.title || ' allowed to perform decryption actions on all keys.'\n end as reason\n \nfrom\n aws_iam_group g\n left join group_with_decrypt_grant d on g.arn = d.arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH user_with_decrypt_grant AS ( + SELECT + DISTINCT arn + FROM + aws_iam_user, + jsonb_array_elements(inline_policies_std) AS inline_policy, + jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') AS statement + WHERE + statement ->> 'Effect' = 'Allow' + AND statement -> 'Resource' ?| ARRAY['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] + AND statement -> 'Action' ?| ARRAY['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom'] + ), + role_with_decrypt_grant AS ( + SELECT + DISTINCT arn + FROM + aws_iam_role, + jsonb_array_elements(inline_policies_std) AS inline_policy, + jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') AS statement + WHERE + statement ->> 'Effect' = 'Allow' + AND statement -> 'Resource' ?| ARRAY['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] + AND statement -> 'Action' ?| ARRAY['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom'] + ), + group_with_decrypt_grant AS ( + SELECT + DISTINCT arn + FROM + aws_iam_group, + jsonb_array_elements(inline_policies_std) AS inline_policy, + jsonb_array_elements(inline_policy -> 'PolicyDocument' -> 'Statement') AS statement + WHERE + statement ->> 'Effect' = 'Allow' + AND statement -> 'Resource' ?| ARRAY['*', 'arn:aws:kms:*:' || account_id || ':key/*', 'arn:aws:kms:*:' || account_id || ':alias/*'] + AND statement -> 'Action' ?| ARRAY['*', 'kms:*', 'kms:decrypt', 'kms:deencrypt*', 'kms:reencryptfrom'] + ) + SELECT + i.arn AS resource, + CASE + WHEN d.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.arn IS NULL THEN 'User ' || i.title || ' not allowed to perform decryption actions on all keys.' + ELSE 'User ' || i.title || ' allowed to perform decryption actions on all keys.' + END AS reason + FROM + aws_iam_user i + LEFT JOIN user_with_decrypt_grant d ON i.arn = d.arn + UNION + SELECT + r.arn AS resource, + CASE + WHEN d.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.arn IS NULL THEN 'Role ' || r.title || ' not allowed to perform decryption actions on all keys.' + ELSE 'Role ' || r.title || ' allowed to perform decryption actions on all keys.' + END AS reason + FROM + aws_iam_role r + LEFT JOIN role_with_decrypt_grant d ON r.arn = d.arn + WHERE + r.arn NOT LIKE '%service-role/%' + UNION + SELECT + g.arn AS resource, + CASE + WHEN d.arn IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN d.arn IS NULL THEN 'Group ' || g.title || ' not allowed to perform decryption actions on all keys.' + ELSE 'Group ' || g.title || ' allowed to perform decryption actions on all keys.' + END AS reason + FROM + aws_iam_group g + LEFT JOIN group_with_decrypt_grant d ON g.arn = d.arn; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 IAM principals should not have IAM inline policies that allow decryption actions on all KMS keys \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_lambda_5.yaml b/compliance/controls/pending/aws/aws_foundational_security_lambda_5.yaml old mode 100755 new mode 100644 index 4ef2e1f50..6884bc573 --- a/compliance/controls/pending/aws/aws_foundational_security_lambda_5.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_lambda_5.yaml @@ -1,13 +1,36 @@ +Description: This control checks if Lambda has more than one availability zone associated. The rule fails if only one availability zone is associated with Lambda. ID: aws_foundational_security_lambda_5 -Title: "5 VPC Lambda functions should operate in multiple Availability Zones" -Description: "This control checks if Lambda has more than one availability zone associated. The rule fails if only one availability zone is associated with Lambda." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n arn as resource,\n case\n when vpc_id is null or vpc_id = '' then 'skip'\n else case\n when\n (\n select\n count(distinct availability_zone_id)\n from\n aws_vpc_subnet\n where\n subnet_id in (select jsonb_array_elements_text(vpc_subnet_ids) )\n ) >= 2\n then 'ok'\n else 'alarm'\n end\n end as status,\n case\n when vpc_id is null or vpc_id = '' then title || ' is not in VPC.'\n else title || ' has ' || jsonb_array_length(vpc_subnet_ids) || ' availability zone(s).'\n end as reason\n \n \nfrom\n aws_lambda_function;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + arn AS resource, + CASE + WHEN vpc_id IS NULL OR vpc_id = '' THEN 'skip' + ELSE CASE + WHEN ( + SELECT + COUNT(DISTINCT availability_zone_id) + FROM + aws_vpc_subnet + WHERE + subnet_id IN (SELECT jsonb_array_elements_text(vpc_subnet_ids)) + ) >= 2 + THEN 'ok' + ELSE 'alarm' + END + END AS status, + CASE + WHEN vpc_id IS NULL OR vpc_id = '' THEN title || ' is not in VPC.' + ELSE title || ' has ' || jsonb_array_length(vpc_subnet_ids) || ' availability zone(s).' + END AS reason + FROM + aws_lambda_function; Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 5 VPC Lambda functions should operate in multiple Availability Zones \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_rds_1.yaml b/compliance/controls/pending/aws/aws_foundational_security_rds_1.yaml old mode 100755 new mode 100644 index b9a1a07b6..77cbc620f --- a/compliance/controls/pending/aws/aws_foundational_security_rds_1.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_rds_1.yaml @@ -1,13 +1,44 @@ +Description: This control checks whether Amazon RDS snapshots are public. This control is intended for RDS instances. It can also return findings for snapshots of Aurora DB instances, Neptune DB instances, and Amazon DocumentDB clusters, even though they are not evaluated for public accessibility. If these findings are not useful, you can suppress them. ID: aws_foundational_security_rds_1 -Title: "1 RDS snapshots should be private" -Description: "This control checks whether Amazon RDS snapshots are public. This control is intended for RDS instances. It can also return findings for snapshots of Aurora DB instances, Neptune DB instances, and Amazon DocumentDB clusters, even though they are not evaluated for public accessibility. If these findings are not useful, you can suppress them." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\nselect\n arn as resource,\n case\n when cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when cluster_snapshot -> 'AttributeValues' = '[\"all\"]' then title || ' publicly restorable.'\n else title || ' not publicly restorable.'\n end reason\n \n \nfrom\n aws_rds_db_cluster_snapshot,\n jsonb_array_elements(db_cluster_snapshot_attributes) as cluster_snapshot\n)\nunion\n(\nselect\n arn as resource,\n case\n when database_snapshot -> 'AttributeValues' = '[\"all\"]' then 'alarm'\n else 'ok'\n end status,\n case\n when database_snapshot -> 'AttributeValues' = '[\"all\"]' then title || ' publicly restorable.'\n else title || ' not publicly restorable.'\n end reason\n \n \nfrom\n aws_rds_db_snapshot,\n jsonb_array_elements(db_snapshot_attributes) as database_snapshot\n);\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + arn AS resource, + CASE + WHEN cluster_snapshot -> 'AttributeValues' = '["all"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN cluster_snapshot -> 'AttributeValues' = '["all"]' THEN title || ' publicly restorable.' + ELSE title || ' not publicly restorable.' + END AS reason + FROM + aws_rds_db_cluster_snapshot, + jsonb_array_elements(db_cluster_snapshot_attributes) AS cluster_snapshot + ) + UNION + ( + SELECT + arn AS resource, + CASE + WHEN database_snapshot -> 'AttributeValues' = '["all"]' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN database_snapshot -> 'AttributeValues' = '["all"]' THEN title || ' publicly restorable.' + ELSE title || ' not publicly restorable.' + END AS reason + FROM + aws_rds_db_snapshot, + jsonb_array_elements(db_snapshot_attributes) AS database_snapshot + ); Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 1 RDS snapshots should be private \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_rds_23.yaml b/compliance/controls/pending/aws/aws_foundational_security_rds_23.yaml old mode 100755 new mode 100644 index b9a7d53be..0ea2e7e9a --- a/compliance/controls/pending/aws/aws_foundational_security_rds_23.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_rds_23.yaml @@ -1,13 +1,54 @@ +Description: This control checks whether the RDS cluster or instance uses a port other than the default port of the database engine. ID: aws_foundational_security_rds_23 -Title: "23 RDS databases and clusters should not use a database engine default port" -Description: "This control checks whether the RDS cluster or instance uses a port other than the default port of the database engine." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\nselect\n arn as resource,\n case\n when engine similar to '%(aurora|mysql|mariadb)%' and port = '3306' then 'alarm'\n when engine like '%postgres%' and port = '5432' then 'alarm'\n when engine like 'oracle%' and port = '1521' then 'alarm'\n when engine like 'sqlserver%' and port = '1433' then 'alarm'\n else 'ok'\n end as status,\n case\n when engine similar to '%(aurora|mysql|mariadb)%' and port = '3306' then title || ' ' || engine || ' uses a default port.'\n when engine like '%postgres%' and port = '5432' then title || ' ' || engine || ' uses a default port.'\n when engine like 'oracle%' and port = '1521' then title || ' ' || engine || ' uses a default port.'\n when engine like 'sqlserver%' and port = '1433' then title || ' ' || engine || ' uses a default port.'\n else title || ' doesnt use a default port.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster\n)\nunion\n(\nselect\n arn as resource,\n case\n when engine similar to '%(aurora|mysql|mariadb)%' and port = '3306' then 'alarm'\n when engine like '%postgres%' and port = '5432' then 'alarm'\n when engine like 'oracle%' and port = '1521' then 'alarm'\n when engine like 'sqlserver%' and port = '1433' then 'alarm'\n else 'ok'\n end as status,\n case\n when engine similar to '%(aurora|mysql|mariadb)%' and port = '3306' then title || ' ' || engine || ' uses a default port.'\n when engine like '%postgres%' and port = '5432' then title || ' ' || engine || ' uses a default port.'\n when engine like 'oracle%' and port = '1521' then title || ' ' || engine || ' uses a default port.'\n when engine like 'sqlserver%' and port = '1433' then title || ' ' || engine || ' uses a default port.'\n else title || ' doesnt use a default port.'\n end as reason\n \n \nfrom\n aws_rds_db_instance\n);\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + arn AS resource, + CASE + WHEN engine SIMILAR TO '%(aurora|mysql|mariadb)%' AND port = '3306' THEN 'alarm' + WHEN engine LIKE '%postgres%' AND port = '5432' THEN 'alarm' + WHEN engine LIKE 'oracle%' AND port = '1521' THEN 'alarm' + WHEN engine LIKE 'sqlserver%' AND port = '1433' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN engine SIMILAR TO '%(aurora|mysql|mariadb)%' AND port = '3306' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE '%postgres%' AND port = '5432' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE 'oracle%' AND port = '1521' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE 'sqlserver%' AND port = '1433' THEN title || ' ' || engine || ' uses a default port.' + ELSE title || ' doesn\'t use a default port.' + END AS reason + FROM + aws_rds_db_cluster + ) + UNION + ( + SELECT + arn AS resource, + CASE + WHEN engine SIMILAR TO '%(aurora|mysql|mariadb)%' AND port = '3306' THEN 'alarm' + WHEN engine LIKE '%postgres%' AND port = '5432' THEN 'alarm' + WHEN engine LIKE 'oracle%' AND port = '1521' THEN 'alarm' + WHEN engine LIKE 'sqlserver%' AND port = '1433' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN engine SIMILAR TO '%(aurora|mysql|mariadb)%' AND port = '3306' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE '%postgres%' AND port = '5432' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE 'oracle%' AND port = '1521' THEN title || ' ' || engine || ' uses a default port.' + WHEN engine LIKE 'sqlserver%' AND port = '1433' THEN title || ' ' || engine || ' uses a default port.' + ELSE title || ' doesn\'t use a default port.' + END AS reason + FROM + aws_rds_db_instance + ); Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 23 RDS databases and clusters should not use a database engine default port \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_rds_4.yaml b/compliance/controls/pending/aws/aws_foundational_security_rds_4.yaml old mode 100755 new mode 100644 index 10afe250b..5c3ab6767 --- a/compliance/controls/pending/aws/aws_foundational_security_rds_4.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_rds_4.yaml @@ -1,13 +1,42 @@ +Description: This control checks whether RDS DB snapshots are encrypted. This control is intended for RDS DB instances. However, it can also generate findings for snapshots of Aurora DB instances, Neptune DB instances, and Amazon DocumentDB clusters. If these findings are not useful, then you can suppress them. ID: aws_foundational_security_rds_4 -Title: "4 RDS cluster snapshots and database snapshots should be encrypted at rest" -Description: "This control checks whether RDS DB snapshots are encrypted. This control is intended for RDS DB instances. However, it can also generate findings for snapshots of Aurora DB instances, Neptune DB instances, and Amazon DocumentDB clusters. If these findings are not useful, then you can suppress them." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\nselect\n arn as resource,\n case\n when storage_encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when storage_encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster_snapshot\n)\nunion\n(\nselect\n arn as resource,\n case\n when encrypted then 'ok'\n else 'alarm'\n end as status,\n case\n when encrypted then title || ' encrypted at rest.'\n else title || ' not encrypted at rest.'\n end as reason\n \n \nfrom\n aws_rds_db_snapshot\n);\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + arn AS resource, + CASE + WHEN storage_encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN storage_encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_rds_db_cluster_snapshot + ) + UNION + ( + SELECT + arn AS resource, + CASE + WHEN encrypted THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN encrypted THEN title || ' encrypted at rest.' + ELSE title || ' not encrypted at rest.' + END AS reason + FROM + aws_rds_db_snapshot + ); Severity: medium Tags: {} -IntegrationType: - - aws_cloud_account +Title: 4 RDS cluster snapshots and database snapshots should be encrypted at rest \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_rds_6.yaml b/compliance/controls/pending/aws/aws_foundational_security_rds_6.yaml old mode 100755 new mode 100644 index d4896b2ef..3b0fbd01c --- a/compliance/controls/pending/aws/aws_foundational_security_rds_6.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_rds_6.yaml @@ -1,13 +1,44 @@ +Description: This control checks whether enhanced monitoring is enabled for your RDS DB instances. In Amazon RDS, Enhanced Monitoring enables a more rapid response to performance changes in underlying infrastructure. These performance changes could result in a lack of availability of the data. Enhanced Monitoring provides real-time metrics of the operating system that your RDS DB instance runs on. An agent is installed on the instance. The agent can obtain metrics more accurately than is possible from the hypervisor layer. ID: aws_foundational_security_rds_6 -Title: "6 Enhanced monitoring should be configured for RDS DB instances and clusters" -Description: "This control checks whether enhanced monitoring is enabled for your RDS DB instances. In Amazon RDS, Enhanced Monitoring enables a more rapid response to performance changes in underlying infrastructure. These performance changes could result in a lack of availability of the data. Enhanced Monitoring provides real-time metrics of the operating system that your RDS DB instance runs on. An agent is installed on the instance. The agent can obtain metrics more accurately than is possible from the hypervisor layer." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "(\nselect\n arn as resource,\n case\n when enabled_cloudwatch_logs_exports is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when enabled_cloudwatch_logs_exports is not null then title || ' enhanced monitoring enabled.'\n else title || ' enhanced monitoring not enabled.'\n end as reason\n \n \nfrom\n aws_rds_db_cluster\n)\nunion\n(\nselect\n arn as resource,\n case\n when class = 'db.m1.small' then 'skip'\n when enhanced_monitoring_resource_arn is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when class = 'db.m1.small' then title || ' enhanced monitoring not supported.'\n when enhanced_monitoring_resource_arn is not null then title || ' enhanced monitoring enabled.'\n else title || ' enhanced monitoring not enabled.'\n end as reason\n \n \nfrom\n aws_rds_db_instance\n);\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + ( + SELECT + arn AS resource, + CASE + WHEN enabled_cloudwatch_logs_exports IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN enabled_cloudwatch_logs_exports IS NOT NULL THEN title || ' enhanced monitoring enabled.' + ELSE title || ' enhanced monitoring not enabled.' + END AS reason + FROM + aws_rds_db_cluster + ) + UNION + ( + SELECT + arn AS resource, + CASE + WHEN class = 'db.m1.small' THEN 'skip' + WHEN enhanced_monitoring_resource_arn IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN class = 'db.m1.small' THEN title || ' enhanced monitoring not supported.' + WHEN enhanced_monitoring_resource_arn IS NOT NULL THEN title || ' enhanced monitoring enabled.' + ELSE title || ' enhanced monitoring not enabled.' + END AS reason + FROM + aws_rds_db_instance + ); Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: 6 Enhanced monitoring should be configured for RDS DB instances and clusters \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_s3_2.yaml b/compliance/controls/pending/aws/aws_foundational_security_s3_2.yaml old mode 100755 new mode 100644 index ac166f0b8..ba99cc604 --- a/compliance/controls/pending/aws/aws_foundational_security_s3_2.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_s3_2.yaml @@ -1,13 +1,67 @@ +Description: This control checks whether your S3 buckets allow public read access. It evaluates the Block Public Access settings, the bucket policy, and the bucket access control list (ACL). ID: aws_foundational_security_s3_2 -Title: "2 S3 buckets should prohibit public read access" -Description: "This control checks whether your S3 buckets allow public read access. It evaluates the Block Public Access settings, the bucket policy, and the bucket access control list (ACL)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with public_acl as (\n select\n distinct name\n from\n aws_s3_bucket,\n jsonb_array_elements(acl -> 'Grants') as grants\n where\n (grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers'\n or grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers')\n and (\n grants ->> 'Permission' = 'FULL_CONTROL'\n or grants ->> 'Permission' = 'READ_ACP'\n or grants ->> 'Permission' = 'READ'\n )\n ),read_access_policy as (\n select\n distinct name\n from\n aws_s3_bucket,\n jsonb_array_elements(policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n s ->> 'Effect' = 'Allow'\n and (\n s -> 'Principal' -> 'AWS' = '[\"*\"]'\n or s ->> 'Principal' = '*'\n )\n and (\n action = '*'\n or action = '*:*'\n or action = 's3:*'\n or action ilike 's3:get%'\n or action ilike 's3:list%'\n )\n)\nselect\n b.arn as resource,\n case\n when (block_public_acls or a.name is null) and not bucket_policy_is_public then 'ok'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then 'ok'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and p.name is null) then 'ok'\n else 'alarm'\n end as status,\n case\n when (block_public_acls or a.name is null) and not bucket_policy_is_public then b.title || ' not publicly readable.'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then b.title || ' not publicly readable.'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and p.name is null) then b.title || ' not publicly readable.'\n else b.title || ' publicly readable.'\n end as reason\n \n \nfrom\n aws_s3_bucket as b\n left join public_acl as a on b.name = a.name\n left join read_access_policy as p on b.name = p.name;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH public_acl AS ( + SELECT + DISTINCT name + FROM + aws_s3_bucket, + jsonb_array_elements(acl -> 'Grants') AS grants + WHERE + (grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers' + OR grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers') + AND ( + grants ->> 'Permission' = 'FULL_CONTROL' + OR grants ->> 'Permission' = 'READ_ACP' + OR grants ->> 'Permission' = 'READ' + ) + ), + read_access_policy AS ( + SELECT + DISTINCT name + FROM + aws_s3_bucket, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + s ->> 'Effect' = 'Allow' + AND ( + s -> 'Principal' -> 'AWS' = '[\"*\"]' + OR s ->> 'Principal' = '*' + ) + AND ( + action = '*' + OR action = '*:*' + OR action = 's3:*' + OR action ILIKE 's3:get%' + OR action ILIKE 's3:list%' + ) + ) + SELECT + b.arn AS resource, + CASE + WHEN (block_public_acls OR a.name IS NULL) AND NOT bucket_policy_is_public THEN 'ok' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND block_public_policy) THEN 'ok' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND p.name IS NULL) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (block_public_acls OR a.name IS NULL) AND NOT bucket_policy_is_public THEN b.title || ' not publicly readable.' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND block_public_policy) THEN b.title || ' not publicly readable.' + WHEN (block_public_acls OR a.name IS NULL) AND (bucket_policy_is_public AND p.name IS NULL) THEN b.title || ' not publicly readable.' + ELSE b.title || ' publicly readable.' + END AS reason + FROM + aws_s3_bucket AS b + LEFT JOIN public_acl AS a ON b.name = a.name + LEFT JOIN read_access_policy AS p ON b.name = p.name; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 2 S3 buckets should prohibit public read access \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_foundational_security_s3_3.yaml b/compliance/controls/pending/aws/aws_foundational_security_s3_3.yaml old mode 100755 new mode 100644 index 196fc27e8..99803dd19 --- a/compliance/controls/pending/aws/aws_foundational_security_s3_3.yaml +++ b/compliance/controls/pending/aws/aws_foundational_security_s3_3.yaml @@ -1,13 +1,59 @@ +Description: This control checks whether your S3 buckets allow public write access. It evaluates the block public access settings, the bucket policy, and the bucket access control list (ACL). ID: aws_foundational_security_s3_3 -Title: "3 S3 buckets should prohibit public write access" -Description: "This control checks whether your S3 buckets allow public write access. It evaluates the block public access settings, the bucket policy, and the bucket access control list (ACL)." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with public_acl as (\n select\n distinct name\n from\n aws_s3_bucket,\n jsonb_array_elements(acl -> 'Grants') as grants\n where\n (grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers'\n or grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers')\n and (\n grants ->> 'Permission' = 'FULL_CONTROL'\n or grants ->> 'Permission' = 'WRITE_ACP'\n or grants ->> 'Permission' = 'WRITE'\n )\n), write_access_policy as (\n select\n distinct name\n from\n aws_s3_bucket,\n jsonb_array_elements(policy_std -> 'Statement') as s,\n jsonb_array_elements_text(s -> 'Action') as action\n where\n s ->> 'Effect' = 'Allow'\n and (\n s -> 'Principal' -> 'AWS' = '[\"*\"]'\n or s ->> 'Principal' = '*'\n )\n and (\n action = '*'\n or action = '*:*'\n or action = 's3:*'\n or action ilike 's3:put%'\n or action ilike 's3:delete%'\n or action ilike 's3:create%'\n or action ilike 's3:update%'\n or action ilike 's3:replicate%'\n or action ilike 's3:restore%'\n )\n)\nselect\n b.arn as resource,\n case\n when (block_public_acls or a.name is null) and not bucket_policy_is_public then 'ok'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then 'ok'\n when bucket_policy_is_public and p.name is null then 'ok'\n else 'alarm'\n end status,\n case\n when (block_public_acls or a.name is null ) and not bucket_policy_is_public then b.title || ' not publicly writable.'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and block_public_policy) then b.title || ' not publicly writable.'\n when (block_public_acls or a.name is null) and (bucket_policy_is_public and p.name is null) then b.title || ' not publicly writable.'\n else b.title || ' publicly writable.'\n end reason\n \n \nfrom\n aws_s3_bucket as b\n left join public_acl as a on b.name = a.name\n left join write_access_policy as p on b.name = p.name;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH public_acl AS ( + SELECT DISTINCT name + FROM aws_s3_bucket, + jsonb_array_elements(acl -> 'Grants') AS grants + WHERE + (grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AllUsers' + OR grants -> 'Grantee' ->> 'URI' = 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers') + AND (grants ->> 'Permission' = 'FULL_CONTROL' + OR grants ->> 'Permission' = 'WRITE_ACP' + OR grants ->> 'Permission' = 'WRITE') + ), write_access_policy AS ( + SELECT DISTINCT name + FROM aws_s3_bucket, + jsonb_array_elements(policy_std -> 'Statement') AS s, + jsonb_array_elements_text(s -> 'Action') AS action + WHERE + s ->> 'Effect' = 'Allow' + AND (s -> 'Principal' -> 'AWS' = '[\"*\"]' + OR s ->> 'Principal' = '*') + AND (action = '*' + OR action = '*:*' + OR action = 's3:*' + OR action ILIKE 's3:put%' + OR action ILIKE 's3:delete%' + OR action ILIKE 's3:create%' + OR action ILIKE 's3:update%' + OR action ILIKE 's3:replicate%' + OR action ILIKE 's3:restore%') + ) + SELECT + b.arn AS resource, + CASE + WHEN (block_public_acls OR a.name IS NULL) AND NOT bucket_policy_is_public THEN 'ok' + WHEN (block_public_acls OR a.name IS NULL) AND bucket_policy_is_public AND block_public_policy THEN 'ok' + WHEN bucket_policy_is_public AND p.name IS NULL THEN 'ok' + ELSE 'alarm' + END status, + CASE + WHEN (block_public_acls OR a.name IS NULL) AND NOT bucket_policy_is_public THEN b.title || ' not publicly writable.' + WHEN (block_public_acls OR a.name IS NULL) AND bucket_policy_is_public AND block_public_policy THEN b.title || ' not publicly writable.' + WHEN (block_public_acls OR a.name IS NULL) AND bucket_policy_is_public AND p.name IS NULL THEN b.title || ' not publicly writable.' + ELSE b.title || ' publicly writable.' + END reason + FROM aws_s3_bucket AS b + LEFT JOIN public_acl AS a ON b.name = a.name + LEFT JOIN write_access_policy AS p ON b.name = p.name; Severity: critical Tags: {} -IntegrationType: - - aws_cloud_account +Title: 3 S3 buckets should prohibit public write access \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_glue_dev_endpoint_cloudwatch_logs_encryption_enabled.yaml b/compliance/controls/pending/aws/aws_glue_dev_endpoint_cloudwatch_logs_encryption_enabled.yaml old mode 100755 new mode 100644 index f19e82b51..29d3ec2c7 --- a/compliance/controls/pending/aws/aws_glue_dev_endpoint_cloudwatch_logs_encryption_enabled.yaml +++ b/compliance/controls/pending/aws/aws_glue_dev_endpoint_cloudwatch_logs_encryption_enabled.yaml @@ -1,13 +1,29 @@ +Description: Ensure Glue dev endpoints have CloudWatch logs encryption enabled to protect sensitive information at rest. ID: aws_glue_dev_endpoint_cloudwatch_logs_encryption_enabled -Title: "Glue dev endpoints CloudWatch logs encryption should be enabled" -Description: "Ensure Glue dev endpoints have CloudWatch logs encryption enabled to protect sensitive information at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n e.arn as resource,\n case\n when cloud_watch_encryption is not null and cloud_watch_encryption ->> 'CloudWatchEncryptionMode' != 'DISABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when cloud_watch_encryption is not null and cloud_watch_encryption ->> 'CloudWatchEncryptionMode' != 'DISABLED' then e.title || ' CloudWatch logs encryption enabled.'\n else e.title || ' CloudWatch logs encryption disabled.'\n end as reason\n \nfrom\n aws_glue_dev_endpoint as e\n left join aws_glue_security_configuration as c on e.security_configuration = c.name;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + e.arn AS resource, + CASE + WHEN cloud_watch_encryption IS NOT NULL AND cloud_watch_encryption ->> 'CloudWatchEncryptionMode' != 'DISABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cloud_watch_encryption IS NOT NULL AND cloud_watch_encryption ->> 'CloudWatchEncryptionMode' != 'DISABLED' THEN e.title || ' CloudWatch logs encryption enabled.' + ELSE e.title || ' CloudWatch logs encryption disabled.' + END AS reason + FROM + aws_glue_dev_endpoint AS e + LEFT JOIN + aws_glue_security_configuration AS c + ON + e.security_configuration = c.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Glue dev endpoints CloudWatch logs encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_glue_dev_endpoint_job_bookmarks_encryption_enabled.yaml b/compliance/controls/pending/aws/aws_glue_dev_endpoint_job_bookmarks_encryption_enabled.yaml old mode 100755 new mode 100644 index 704e52a56..0c38f6e09 --- a/compliance/controls/pending/aws/aws_glue_dev_endpoint_job_bookmarks_encryption_enabled.yaml +++ b/compliance/controls/pending/aws/aws_glue_dev_endpoint_job_bookmarks_encryption_enabled.yaml @@ -1,13 +1,31 @@ +Description: Ensure Glue dev endpoints have job bookmark encryption enabled to protect sensitive information at rest. ID: aws_glue_dev_endpoint_job_bookmarks_encryption_enabled -Title: "Glue dev endpoints job bookmark encryption should be enabled" -Description: "Ensure Glue dev endpoints have job bookmark encryption enabled to protect sensitive information at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n e.arn as resource,\n case\n when job_bookmarks_encryption is not null and job_bookmarks_encryption ->> 'JobBookmarksEncryptionMode' != 'DISABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when job_bookmarks_encryption is not null and job_bookmarks_encryption ->> 'JobBookmarksEncryptionMode' != 'DISABLED' then e.title || ' job bookmark encryption enabled.'\n else e.title || ' job bookmark encryption disabled.'\n end as reason\n \nfrom\n aws_glue_dev_endpoint as e\n left join aws_glue_security_configuration as c on e.security_configuration = c.name;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + e.arn AS resource, + CASE + WHEN job_bookmarks_encryption IS NOT NULL + AND job_bookmarks_encryption ->> 'JobBookmarksEncryptionMode' != 'DISABLED' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN job_bookmarks_encryption IS NOT NULL + AND job_bookmarks_encryption ->> 'JobBookmarksEncryptionMode' != 'DISABLED' + THEN e.title || ' job bookmark encryption enabled.' + ELSE e.title || ' job bookmark encryption disabled.' + END AS reason + FROM + aws_glue_dev_endpoint AS e + LEFT JOIN aws_glue_security_configuration AS c + ON e.security_configuration = c.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Glue dev endpoints job bookmark encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_glue_dev_endpoint_s3_encryption_enabled.yaml b/compliance/controls/pending/aws/aws_glue_dev_endpoint_s3_encryption_enabled.yaml old mode 100755 new mode 100644 index 66996ca5c..5632c9257 --- a/compliance/controls/pending/aws/aws_glue_dev_endpoint_s3_encryption_enabled.yaml +++ b/compliance/controls/pending/aws/aws_glue_dev_endpoint_s3_encryption_enabled.yaml @@ -1,13 +1,29 @@ +Description: Ensure Glue dev endpoints have S3 encryption enabled to protect sensitive information at rest. ID: aws_glue_dev_endpoint_s3_encryption_enabled -Title: "Glue dev endpoints S3 encryption should be enabled" -Description: "Ensure Glue dev endpoints have S3 encryption enabled to protect sensitive information at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n d.arn as resource,\n case\n when e is not null and e ->> 'S3EncryptionMode' != 'DISABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when e is not null and e ->> 'S3EncryptionMode' != 'DISABLED' then d.title || ' S3 encryption enabled.'\n else d.title || ' S3 encryption disabled.'\n end as reason\n \nfrom\n aws_glue_dev_endpoint as d\n left join aws_glue_security_configuration s on d.security_configuration = s.name,\n jsonb_array_elements(s.s3_encryption) e;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + d.arn AS resource, + CASE + WHEN e IS NOT NULL AND e ->> 'S3EncryptionMode' != 'DISABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN e IS NOT NULL AND e ->> 'S3EncryptionMode' != 'DISABLED' THEN d.title || ' S3 encryption enabled.' + ELSE d.title || ' S3 encryption disabled.' + END AS reason + FROM + aws_glue_dev_endpoint AS d + LEFT JOIN + aws_glue_security_configuration s + ON d.security_configuration = s.name, + jsonb_array_elements(s.s3_encryption) e; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Glue dev endpoints S3 encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_glue_job_cloudwatch_logs_encryption_enabled.yaml b/compliance/controls/pending/aws/aws_glue_job_cloudwatch_logs_encryption_enabled.yaml old mode 100755 new mode 100644 index 4cd0e4908..46cb4042b --- a/compliance/controls/pending/aws/aws_glue_job_cloudwatch_logs_encryption_enabled.yaml +++ b/compliance/controls/pending/aws/aws_glue_job_cloudwatch_logs_encryption_enabled.yaml @@ -1,13 +1,27 @@ +Description: Ensure Glue jobs have CloudWatch logs encryption enabled to protect sensitive information at rest. ID: aws_glue_job_cloudwatch_logs_encryption_enabled -Title: "Glue jobs CloudWatch logs encryption should be enabled" -Description: "Ensure Glue jobs have CloudWatch logs encryption enabled to protect sensitive information at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n j.arn as resource,\n case\n when cloud_watch_encryption is not null and cloud_watch_encryption ->> 'CloudWatchEncryptionMode' != 'DISABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when cloud_watch_encryption is not null and cloud_watch_encryption ->> 'CloudWatchEncryptionMode' != 'DISABLED' then j.title || ' CloudWatch logs encryption enabled.'\n else j.title || ' CloudWatch logs encryption disabled.'\n end as reason\n \nfrom\n aws_glue_job as j\n left join aws_glue_security_configuration as c on j.security_configuration = c.name;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + j.arn AS resource, + CASE + WHEN cloud_watch_encryption IS NOT NULL AND cloud_watch_encryption ->> 'CloudWatchEncryptionMode' != 'DISABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN cloud_watch_encryption IS NOT NULL AND cloud_watch_encryption ->> 'CloudWatchEncryptionMode' != 'DISABLED' THEN j.title || ' CloudWatch logs encryption enabled.' + ELSE j.title || ' CloudWatch logs encryption disabled.' + END AS reason + FROM + aws_glue_job AS j + LEFT JOIN + aws_glue_security_configuration AS c ON j.security_configuration = c.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Glue jobs CloudWatch logs encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_glue_job_s3_encryption_enabled.yaml b/compliance/controls/pending/aws/aws_glue_job_s3_encryption_enabled.yaml old mode 100755 new mode 100644 index bead4eec4..405e6ed1c --- a/compliance/controls/pending/aws/aws_glue_job_s3_encryption_enabled.yaml +++ b/compliance/controls/pending/aws/aws_glue_job_s3_encryption_enabled.yaml @@ -1,13 +1,30 @@ +Description: Ensure Glue jobs have S3 encryption enabled to protect sensitive information at rest. ID: aws_glue_job_s3_encryption_enabled -Title: "Glue jobs S3 encryption should be enabled" -Description: "Ensure Glue jobs have S3 encryption enabled to protect sensitive information at rest." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n j.arn as resource,\n case\n when e is not null and e ->> 'S3EncryptionMode' != 'DISABLED' then 'ok'\n else 'alarm'\n end as status,\n case\n when e is not null and e ->> 'S3EncryptionMode' != 'DISABLED' then j.title || ' S3 encryption enabled.'\n else j.title || ' S3 encryption disabled.'\n end as reason\n \nfrom\n aws_glue_job as j\n left join aws_glue_security_configuration as s on j.security_configuration = s.name,\n jsonb_array_elements(s.s3_encryption) e;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + j.arn AS resource, + CASE + WHEN e IS NOT NULL AND e ->> 'S3EncryptionMode' != 'DISABLED' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN e IS NOT NULL AND e ->> 'S3EncryptionMode' != 'DISABLED' THEN j.title || ' S3 encryption enabled.' + ELSE j.title || ' S3 encryption disabled.' + END AS reason + FROM + aws_glue_job AS j + LEFT JOIN + aws_glue_security_configuration AS s + ON + j.security_configuration = s.name, + jsonb_array_elements(s.s3_encryption) e; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Glue jobs S3 encryption should be enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_guardduty_centrally_configured.yaml b/compliance/controls/pending/aws/aws_guardduty_centrally_configured.yaml old mode 100755 new mode 100644 index d968b5a78..58d372a36 --- a/compliance/controls/pending/aws/aws_guardduty_centrally_configured.yaml +++ b/compliance/controls/pending/aws/aws_guardduty_centrally_configured.yaml @@ -1,36 +1,34 @@ +Description: Ensure that GuardDuty is centrally configured, if GuardDuty is not under central management, it becomes impossible to centrally manage GuardDuty findings, settings, and member accounts. ID: aws_guardduty_centrally_configured -Title: "GuardDuty Detector should be centrally configured" -Description: "Ensure that GuardDuty is centrally configured, if GuardDuty is not under central management, it becomes impossible to centrally manage GuardDuty findings, settings, and member accounts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource, - case - when r.region = any(array['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) then 'skip' - -- Skip any regions that are disabled in the account. - when r.opt_in_status = 'not-opted-in' then 'skip' - when status is null then 'info' - when status = 'DISABLED' then 'alarm' - when status = 'ENABLED' and master_account ->> 'AccountId' is not null then 'ok' - else 'alarm' - end as status, - case - when r.region = any(array['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) then r.region || ' region not supported.' - when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.' - when status is null then 'No GuardDuty detector found in ' || r.region || '.' - when status = 'DISABLED' then r.region || ' detector ' || d.title || ' disabled.' - when status = 'ENABLED' and master_account ->> 'AccountId' is not null then r.region || ' detector ' || d.title || ' centrally configured.' - else r.region || ' detector ' || d.title || ' not centrally configured..' - end as reason - - from - aws_region as r - left join aws_guardduty_detector d on r.account_id = d.account_id and r.name = d.region; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + CASE + WHEN r.region = ANY(array['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) THEN 'skip' + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN status IS NULL THEN 'info' + WHEN status = 'DISABLED' THEN 'alarm' + WHEN status = 'ENABLED' AND master_account ->> 'AccountId' IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN r.region = ANY(array['af-south-1', 'ap-northeast-3', 'ap-southeast-3', 'eu-south-1', 'cn-north-1', 'cn-northwest-1', 'me-south-1', 'us-gov-east-1']) THEN r.region || ' region not supported.' + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN status IS NULL THEN 'No GuardDuty detector found in ' || r.region || '.' + WHEN status = 'DISABLED' THEN r.region || ' detector ' || d.title || ' disabled.' + WHEN status = 'ENABLED' AND master_account ->> 'AccountId' IS NOT NULL THEN r.region || ' detector ' || d.title || ' centrally configured.' + ELSE r.region || ' detector ' || d.title || ' not centrally configured.' + END AS reason + FROM + aws_region AS r + LEFT JOIN aws_guardduty_detector d ON r.account_id = d.account_id AND r.name = d.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: GuardDuty Detector should be centrally configured \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_iam_access_analyzer_enabled_without_findings.yaml b/compliance/controls/pending/aws/aws_iam_access_analyzer_enabled_without_findings.yaml old mode 100755 new mode 100644 index 5941d4270..1fda2a72a --- a/compliance/controls/pending/aws/aws_iam_access_analyzer_enabled_without_findings.yaml +++ b/compliance/controls/pending/aws/aws_iam_access_analyzer_enabled_without_findings.yaml @@ -1,13 +1,32 @@ +Description: This control checks whether the IAM Access analyzer is enabled without findings. If you grant permissions to an S3 bucket in one of your organization member accounts to a principal in another organization member account, IAM Access Analyzer does not generate a finding. But if you grant permission to a principal in an account that is not a member of the organization, IAM Access Analyzer generates a finding. ID: aws_iam_access_analyzer_enabled_without_findings -Title: "IAM Access analyzer should be enabled without findings" -Description: "This control checks whether the IAM Access analyzer is enabled without findings. If you grant permissions to an S3 bucket in one of your organization member accounts to a principal in another organization member account, IAM Access Analyzer does not generate a finding. But if you grant permission to a principal in an account that is not a member of the organization, IAM Access Analyzer generates a finding." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || r.partition || '::' || r.region || ':' || r.account_id as resource,\n case\n -- Skip any regions that are disabled in the account.\n when r.opt_in_status = 'not-opted-in' then 'skip'\n when aa.status = 'ACTIVE' and aa.findings is null then 'ok'\n when aa.status = 'ACTIVE' and jsonb_array_length(aa.findings) > 0 then 'alarm'\n when aa.status = 'NOT_AVAILABLE' then 'alarm'\n else 'alarm'\n end as status,\n case\n when r.opt_in_status = 'not-opted-in' then r.region || ' region is disabled.'\n when aa.status = 'ACTIVE' and aa.findings is null then aa.name || ' does not have active findings in region ' || r.region || '.'\n when aa.status = 'ACTIVE' and jsonb_array_length(aa.findings) > 0 then aa.name || ' has active findings in region ' || r.region || '.'\n when aa.status = 'NOT_AVAILABLE' then aa.name || ' is not enabled in region ' || r.region || '.'\n else 'IAM Access Analyzer is not active in region ' || r.region || '.'\n end as reason\n \n \nfrom\n aws_region as r\n left join aws_accessanalyzer_analyzer as aa on r.account_id = aa.account_id and r.region = aa.region;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || r.partition || '::' || r.region || ':' || r.account_id AS resource, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN 'skip' + WHEN aa.status = 'ACTIVE' AND aa.findings IS NULL THEN 'ok' + WHEN aa.status = 'ACTIVE' AND jsonb_array_length(aa.findings) > 0 THEN 'alarm' + WHEN aa.status = 'NOT_AVAILABLE' THEN 'alarm' + ELSE 'alarm' + END AS status, + CASE + WHEN r.opt_in_status = 'not-opted-in' THEN r.region || ' region is disabled.' + WHEN aa.status = 'ACTIVE' AND aa.findings IS NULL THEN aa.name || ' does not have active findings in region ' || r.region || '.' + WHEN aa.status = 'ACTIVE' AND jsonb_array_length(aa.findings) > 0 THEN aa.name || ' has active findings in region ' || r.region || '.' + WHEN aa.status = 'NOT_AVAILABLE' THEN aa.name || ' is not enabled in region ' || r.region || '.' + ELSE 'IAM Access Analyzer is not active in region ' || r.region || '.' + END AS reason + FROM + aws_region AS r + LEFT JOIN aws_accessanalyzer_analyzer AS aa ON r.account_id = aa.account_id AND r.region = aa.region; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM Access analyzer should be enabled without findings \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_iam_password_policy_expire_90.yaml b/compliance/controls/pending/aws/aws_iam_password_policy_expire_90.yaml old mode 100755 new mode 100644 index fed0b6215..d73f9daeb --- a/compliance/controls/pending/aws/aws_iam_password_policy_expire_90.yaml +++ b/compliance/controls/pending/aws/aws_iam_password_policy_expire_90.yaml @@ -1,13 +1,27 @@ +Description: IAM password policies can require passwords to be rotated or expired after a given number of days. Security Hub recommends that the password policy expire passwords after 90 days or less. Reducing the password lifetime increases account resiliency against brute force login attempts. ID: aws_iam_password_policy_expire_90 -Title: "Ensure IAM password policy expires passwords within 90 days or less" -Description: "IAM password policies can require passwords to be rotated or expired after a given number of days. Security Hub recommends that the password policy expire passwords after 90 days or less. Reducing the password lifetime increases account resiliency against brute force login attempts." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n 'arn:' || a.partition || ':::' || a.account_id as resource,\n case\n when max_password_age <= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when max_password_age is null then 'Password expiration not set.'\n else 'Password expiration set to ' || max_password_age || ' days.'\n end as reason\n \nfrom\n aws_account as a\n left join aws_iam_account_password_policy as pol on a.account_id = pol.account_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'arn:' || a.partition || ':::' || a.account_id AS resource, + CASE + WHEN max_password_age <= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN max_password_age IS NULL THEN 'Password expiration not set.' + ELSE 'Password expiration set to ' || max_password_age || ' days.' + END AS reason + FROM + aws_account AS a + LEFT JOIN + aws_iam_account_password_policy AS pol ON a.account_id = pol.account_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure IAM password policy expires passwords within 90 days or less \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_iam_role_cross_account_read_only_access_policy.yaml b/compliance/controls/pending/aws/aws_iam_role_cross_account_read_only_access_policy.yaml old mode 100755 new mode 100644 index fd92313bb..76f4f4c7c --- a/compliance/controls/pending/aws/aws_iam_role_cross_account_read_only_access_policy.yaml +++ b/compliance/controls/pending/aws/aws_iam_role_cross_account_read_only_access_policy.yaml @@ -1,13 +1,53 @@ +Description: Ensure IAM Roles do not have ReadOnlyAccess access for external AWS account. The AWS-managed ReadOnlyAccess policy carries a high risk of potential data leakage, posing a significant threat to customer security and privacy. ID: aws_iam_role_cross_account_read_only_access_policy -Title: "IAM roles should not have read only access for external AWS accounts" -Description: "Ensure IAM Roles do not have ReadOnlyAccess access for external AWS account. The AWS-managed ReadOnlyAccess policy carries a high risk of potential data leakage, posing a significant threat to customer security and privacy." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with read_only_access_roles as (\n select\n *\n from\n aws_iam_role,\n jsonb_array_elements_text(attached_policy_arns) as a\n where\n a = 'arn:aws:iam::aws:policy/ReadOnlyAccess'\n), read_only_access_roles_with_cross_account_access as (\n select\n arn\n from\n read_only_access_roles,\n jsonb_array_elements(assume_role_policy_std -> 'Statement') as stmt,\n jsonb_array_elements_text( stmt -> 'Principal' -> 'AWS' ) as p\n where\n stmt ->> 'Effect' = 'Allow'\n and (\n p = '*'\n or not (p like '%' || account_id || '%')\n )\n)\nselect\n r.arn as resource,\n case\n when ar.arn is null then 'skip'\n when c.arn is not null then 'alarm'\n else 'ok'\n end as status,\n case\n when ar.arn is null then r.title || ' not associated with ReadOnlyAccess policy.'\n when c.arn is not null then r.title || ' associated with ReadOnlyAccess cross account access.'\n else r.title || ' associated ReadOnlyAccess without cross account access.'\n end as reason\n \nfrom\n aws_iam_role as r\n left join read_only_access_roles as ar on r.arn = ar.arn\n left join read_only_access_roles_with_cross_account_access as c on c.arn = r.arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH read_only_access_roles AS ( + SELECT + * + FROM + aws_iam_role, + jsonb_array_elements_text(attached_policy_arns) AS a + WHERE + a = 'arn:aws:iam::aws:policy/ReadOnlyAccess' + ), read_only_access_roles_with_cross_account_access AS ( + SELECT + arn + FROM + read_only_access_roles, + jsonb_array_elements(assume_role_policy_std -> 'Statement') AS stmt, + jsonb_array_elements_text(stmt -> 'Principal' -> 'AWS') AS p + WHERE + stmt ->> 'Effect' = 'Allow' + AND ( + p = '*' + OR NOT (p LIKE '%' || account_id || '%') + ) + ) + SELECT + r.arn AS resource, + CASE + WHEN ar.arn IS NULL THEN 'skip' + WHEN c.arn IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN ar.arn IS NULL THEN r.title || ' not associated with ReadOnlyAccess policy.' + WHEN c.arn IS NOT NULL THEN r.title || ' associated with ReadOnlyAccess cross account access.' + ELSE r.title || ' associated ReadOnlyAccess without cross account access.' + END AS reason + FROM + aws_iam_role AS r + LEFT JOIN + read_only_access_roles AS ar ON r.arn = ar.arn + LEFT JOIN + read_only_access_roles_with_cross_account_access AS c ON c.arn = r.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM roles should not have read only access for external AWS accounts \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_iam_user_hardware_mfa_enabled.yaml b/compliance/controls/pending/aws/aws_iam_user_hardware_mfa_enabled.yaml old mode 100755 new mode 100644 index 4f57f609c..2dd4f8e6a --- a/compliance/controls/pending/aws/aws_iam_user_hardware_mfa_enabled.yaml +++ b/compliance/controls/pending/aws/aws_iam_user_hardware_mfa_enabled.yaml @@ -1,13 +1,31 @@ +Description: Manage access to resources in the AWS Cloud by ensuring hardware MFA is enabled for the user. ID: aws_iam_user_hardware_mfa_enabled -Title: "IAM users should have hardware MFA enabled" -Description: "Manage access to resources in the AWS Cloud by ensuring hardware MFA is enabled for the user." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n u.arn as resource,\n case\n when serial_number is null then 'alarm'\n when serial_number like any(array['%mfa%','%sms-mfa%']) then 'info'\n else 'ok'\n end as status,\n case\n when serial_number is null then u.name || ' MFA device not configured.'\n when serial_number like any(array['%mfa%','%sms-mfa%']) then u.name || ' MFA enabled, but the MFA associated is a virtual device.'\n else u.name || ' hardware MFA device enabled.'\n end as reason\n \n \nfrom\n aws_iam_virtual_mfa_device as m\n right join aws_iam_user as u on m.user_id = u.user_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + u.arn AS resource, + CASE + WHEN serial_number IS NULL THEN 'alarm' + WHEN serial_number LIKE ANY(ARRAY['%mfa%', '%sms-mfa%']) THEN 'info' + ELSE 'ok' + END AS status, + CASE + WHEN serial_number IS NULL THEN u.name || ' MFA device not configured.' + WHEN serial_number LIKE ANY(ARRAY['%mfa%', '%sms-mfa%']) THEN u.name || ' MFA enabled, but the MFA associated is a virtual device.' + ELSE u.name || ' hardware MFA device enabled.' + END AS reason + FROM + aws_iam_virtual_mfa_device AS m + RIGHT JOIN + aws_iam_user AS u + ON + m.user_id = u.user_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: IAM users should have hardware MFA enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_lightsail_instance_rdp_restricted_ip.yaml b/compliance/controls/pending/aws/aws_lightsail_instance_rdp_restricted_ip.yaml old mode 100755 new mode 100644 index 7ef666866..7966b56d3 --- a/compliance/controls/pending/aws/aws_lightsail_instance_rdp_restricted_ip.yaml +++ b/compliance/controls/pending/aws/aws_lightsail_instance_rdp_restricted_ip.yaml @@ -1,55 +1,55 @@ +Description: Any ports enabled within Lightsail by default are open and exposed to the world. For SSH and RDP access you should identify which IP address need access. ID: aws_lightsail_instance_rdp_restricted_ip -Title: "Ensure RDP is restricted to only IP address that should have this access" -Description: "Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should identify which IP address need access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: [] + Parameters: [] + PrimaryTable: "" QueryToExecute: | - with open_ports as ( - select + WITH open_ports AS ( + SELECT name, - jsonb_array_elements(networking -> 'Ports') as port - from + jsonb_array_elements(networking -> 'Ports') AS port + FROM aws_lightsail_instance ), - port_cidrs as ( - select + port_cidrs AS ( + SELECT op.name, - (op.port ->> 'FromPort')::int as from_port, - (op.port ->> 'ToPort')::int as to_port, - op.port ->> 'Protocol' as protocol, - jsonb_array_elements_text(op.port -> 'Cidrs') as cidr - from + (op.port ->> 'FromPort')::INT AS from_port, + (op.port ->> 'ToPort')::INT AS to_port, + op.port ->> 'Protocol' AS protocol, + jsonb_array_elements_text(op.port -> 'Cidrs') AS cidr + FROM open_ports op ), - unrestricted_rdp_ports as ( - select + unrestricted_rdp_ports AS ( + SELECT name - from + FROM port_cidrs - where + WHERE from_port = 3389 - and to_port = 3389 - and protocol = 'tcp' - and cidr = '0.0.0.0/0' + AND to_port = 3389 + AND protocol = 'tcp' + AND cidr = '0.0.0.0/0' ) - select - i.name as resource, - case - when urp.name is null then 'ok' - else 'alarm' - end as status, - case - when urp.name is null then i.name || ' has RDP (3389) restricted to specific IP addresses.' - else i.name || ' has RDP (3389) open to the world (0.0.0.0/0).' - end as reason, + SELECT + i.name AS resource, + CASE + WHEN urp.name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN urp.name IS NULL THEN i.name || ' has RDP (3389) restricted to specific IP addresses.' + ELSE i.name || ' has RDP (3389) open to the world (0.0.0.0/0).' + END AS reason, i.tags - from + FROM aws_lightsail_instance i - left join unrestricted_rdp_ports urp on i.name = urp.name; - PrimaryTable: "" - ListOfTables: [] - Parameters: [] + LEFT JOIN unrestricted_rdp_ports urp ON i.name = urp.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure RDP is restricted to only IP address that should have this access \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_lightsail_instance_ssh_rdp_http_ports_disabled.yaml b/compliance/controls/pending/aws/aws_lightsail_instance_ssh_rdp_http_ports_disabled.yaml old mode 100755 new mode 100644 index e2ef8133c..41a1831bd --- a/compliance/controls/pending/aws/aws_lightsail_instance_ssh_rdp_http_ports_disabled.yaml +++ b/compliance/controls/pending/aws/aws_lightsail_instance_ssh_rdp_http_ports_disabled.yaml @@ -1,56 +1,56 @@ +Description: Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should remove and disable these ports when not is use. ID: aws_lightsail_instance_ssh_rdp_http_ports_disabled -Title: "Disable SSH and RDP ports for Lightsail instances when not needed" -Description: "Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should remove and disable these ports when not is use." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: [] + Parameters: [] + PrimaryTable: "" QueryToExecute: | - with open_ports as ( - select + WITH open_ports AS ( + SELECT i.name, - jsonb_array_elements(i.networking -> 'Ports') as port - from + jsonb_array_elements(i.networking -> 'Ports') AS port + FROM aws_lightsail_instance i ), - port_cidrs as ( - select + port_cidrs AS ( + SELECT op.name, - (op.port ->> 'FromPort')::int as from_port, - (op.port ->> 'ToPort')::int as to_port, - op.port ->> 'Protocol' as protocol, - jsonb_array_elements_text(op.port -> 'Cidrs') as cidr, - jsonb_array_elements_text(op.port -> 'Ipv6Cidrs') as ipv6_cidr - from + (op.port ->> 'FromPort')::int AS from_port, + (op.port ->> 'ToPort')::int AS to_port, + op.port ->> 'Protocol' AS protocol, + jsonb_array_elements_text(op.port -> 'Cidrs') AS cidr, + jsonb_array_elements_text(op.port -> 'Ipv6Cidrs') AS ipv6_cidr + FROM open_ports op ), - insecure_ports as ( - select + insecure_ports AS ( + SELECT name - from + FROM port_cidrs - where - from_port in (22, 3389, 80) - and to_port in (22, 338, 80) - and protocol = 'tcp' - and (cidr = '0.0.0.0/0' or ipv6_cidr = '::/0') + WHERE + from_port IN (22, 3389, 80) + AND to_port IN (22, 3389, 80) + AND protocol = 'tcp' + AND (cidr = '0.0.0.0/0' OR ipv6_cidr = '::/0') ) - select - i.name as resource, - case - when p.name is null then 'ok' - else 'alarm' - end as status, - case - when p.name is null then i.name || ' does not have SSH (22) or RDP (3389) or HTTP (80) ports open to 0.0.0.0/0 or ::/0.' - else i.name || ' has SSH (22) or RDP (3389) or HTTP (80) ports open to 0.0.0.0/0 or ::/0.' - end as reason, + SELECT + i.name AS resource, + CASE + WHEN p.name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN p.name IS NULL THEN i.name || ' does not have SSH (22) or RDP (3389) or HTTP (80) ports open to 0.0.0.0/0 or ::/0.' + ELSE i.name || ' has SSH (22) or RDP (3389) or HTTP (80) ports open to 0.0.0.0/0 or ::/0.' + END AS reason, i.tags - from + FROM aws_lightsail_instance i - left join insecure_ports p on i.name = p.name; - PrimaryTable: "" - ListOfTables: [] - Parameters: [] + LEFT JOIN insecure_ports p ON i.name = p.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Disable SSH and RDP ports for Lightsail instances when not needed \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_lightsail_instance_ssh_restricted_ip.yaml b/compliance/controls/pending/aws/aws_lightsail_instance_ssh_restricted_ip.yaml old mode 100755 new mode 100644 index d10b3ca3b..18448e385 --- a/compliance/controls/pending/aws/aws_lightsail_instance_ssh_restricted_ip.yaml +++ b/compliance/controls/pending/aws/aws_lightsail_instance_ssh_restricted_ip.yaml @@ -1,55 +1,55 @@ +Description: Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should identify which IP address need access. ID: aws_lightsail_instance_ssh_restricted_ip -Title: "Ensure SSH is restricted to only IP address that should have this access" -Description: "Any ports enable within Lightsail by default are open and exposed to the world. For SSH and RDP access you should identify which IP address need access." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 + ListOfTables: [] + Parameters: [] + PrimaryTable: "" QueryToExecute: | - with open_ports as ( - select + WITH open_ports AS ( + SELECT name, - jsonb_array_elements(networking -> 'Ports') as port - from + jsonb_array_elements(networking -> 'Ports') AS port + FROM aws_lightsail_instance ), - port_cidrs as ( - select + port_cidrs AS ( + SELECT op.name, - (op.port ->> 'FromPort')::int as from_port, - (op.port ->> 'ToPort')::int as to_port, - op.port ->> 'Protocol' as protocol, - jsonb_array_elements_text(op.port -> 'Cidrs') as cidr - from + (op.port ->> 'FromPort')::int AS from_port, + (op.port ->> 'ToPort')::int AS to_port, + op.port ->> 'Protocol' AS protocol, + jsonb_array_elements_text(op.port -> 'Cidrs') AS cidr + FROM open_ports op ), - unrestricted_ssh_ports as ( - select + unrestricted_ssh_ports AS ( + SELECT name - from + FROM port_cidrs - where + WHERE from_port = 22 - and to_port = 22 - and protocol = 'tcp' - and cidr = '0.0.0.0/0' + AND to_port = 22 + AND protocol = 'tcp' + AND cidr = '0.0.0.0/0' ) - select - i.name as resource, - case - when usp.name is null then 'ok' - else 'alarm' - end as status, - case - when usp.name is null then i.name || ' has SSH (22) restricted to specific IP addresses.' - else i.name || ' has SSH (22) open to the world (0.0.0.0/0).' - end as reason, + SELECT + i.name AS resource, + CASE + WHEN usp.name IS NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN usp.name IS NULL THEN i.name || ' has SSH (22) restricted to specific IP addresses.' + ELSE i.name || ' has SSH (22) open to the world (0.0.0.0/0).' + END AS reason, i.tags - from + FROM aws_lightsail_instance i - left join unrestricted_ssh_ports usp on i.name = usp.name; - PrimaryTable: "" - ListOfTables: [] - Parameters: [] + LEFT JOIN unrestricted_ssh_ports usp ON i.name = usp.name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Ensure SSH is restricted to only IP address that should have this access \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_rds_db_cluster_encrypted_with_cmk.yaml b/compliance/controls/pending/aws/aws_rds_db_cluster_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index 530635659..1ee2217e3 --- a/compliance/controls/pending/aws/aws_rds_db_cluster_encrypted_with_cmk.yaml +++ b/compliance/controls/pending/aws/aws_rds_db_cluster_encrypted_with_cmk.yaml @@ -1,13 +1,48 @@ +Description: Ensure RDS DB cluster is encrypted using CMK. The rule is non-compliant if the RDS DB cluster is not encrypted using CMK. ID: aws_rds_db_cluster_encrypted_with_cmk -Title: "RDS DB clusters should be encrypted with CMK" -Description: "Ensure RDS DB cluster is encrypted using CMK. The rule is non-compliant if the RDS DB cluster is not encrypted using CMK." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with rds_clusters as (\n select\n arn,\n region,\n account_id,\n kms_key_id,\n storage_encrypted,\n title,\n tags,\n _ctx\n from\n aws_rds_db_cluster\n), kms_keys as (\n select\n k.arn,\n k.key_manager,\n k.enabled\n from\n aws_kms_key as k\n)\nselect\n r.arn as resource,\n case\n when not storage_encrypted then 'alarm'\n when storage_encrypted and c.key_manager = 'CUSTOMER' then 'ok'\n else 'alarm'\n end as status,\n case\n when not storage_encrypted then title || ' not encrypted.'\n when storage_encrypted and c.key_manager = 'CUSTOMER' then title || ' encrypted with CMK.'\n else title || ' not encrypted with CMK.'\n end as reason\n \n \nfrom\n rds_clusters as r\n left join kms_keys as c on r.kms_key_id = c.arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH rds_clusters AS ( + SELECT + arn, + region, + account_id, + kms_key_id, + storage_encrypted, + title, + tags, + _ctx + FROM + aws_rds_db_cluster + ), kms_keys AS ( + SELECT + k.arn, + k.key_manager, + k.enabled + FROM + aws_kms_key AS k + ) + SELECT + r.arn AS resource, + CASE + WHEN NOT storage_encrypted THEN 'alarm' + WHEN storage_encrypted AND c.key_manager = 'CUSTOMER' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT storage_encrypted THEN title || ' not encrypted.' + WHEN storage_encrypted AND c.key_manager = 'CUSTOMER' THEN title || ' encrypted with CMK.' + ELSE title || ' not encrypted with CMK.' + END AS reason + FROM + rds_clusters AS r + LEFT JOIN kms_keys AS c ON r.kms_key_id = c.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB clusters should be encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_rds_db_instance_no_public_subnet.yaml b/compliance/controls/pending/aws/aws_rds_db_instance_no_public_subnet.yaml old mode 100755 new mode 100644 index 46d26a7fe..3370b84f7 --- a/compliance/controls/pending/aws/aws_rds_db_instance_no_public_subnet.yaml +++ b/compliance/controls/pending/aws/aws_rds_db_instance_no_public_subnet.yaml @@ -1,13 +1,95 @@ +Description: This control checks if RDS DB instance is configured with public subnet as there is a risk of exposing sensitive data. ID: aws_rds_db_instance_no_public_subnet -Title: "RDS DB instances should not use public subnet" -Description: "This control checks if RDS DB instance is configured with public subnet as there is a risk of exposing sensitive data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with subnets_with_explicit_route as (\n select\n distinct ( a ->> 'SubnetId') as all_sub\n from\n aws_vpc_route_table as t,\n jsonb_array_elements(associations) as a\n where\n a ->> 'SubnetId' is not null\n), public_subnets_with_explicit_route as (\n select\n distinct a ->> 'SubnetId' as SubnetId\n from\n aws_vpc_route_table as t,\n jsonb_array_elements(associations) as a,\n jsonb_array_elements(routes) as r\n where\n r ->> 'DestinationCidrBlock' = '0.0.0.0/0'\n and\n (\n r ->> 'GatewayId' like 'igw-%'\n or r ->> 'NatGatewayId' like 'nat-%'\n )\n and a ->> 'SubnetId' is not null\n), public_subnets_with_implicit_route as (\n select\n distinct route_table_id,\n vpc_id,\n region\n from\n aws_vpc_route_table as t,\n jsonb_array_elements(associations) as a,\n jsonb_array_elements(routes) as r\n where\n a ->> 'Main' = 'true'\n and r ->> 'DestinationCidrBlock' = '0.0.0.0/0'\n and (\n r ->> 'GatewayId' like 'igw-%'\n or r ->> 'NatGatewayId' like 'nat-%'\n )\n), subnet_accessibility as (\n select\n subnet_id,\n vpc_id,\n case\n when s.subnet_id in (select all_sub from subnets_with_explicit_route where all_sub not in (select SubnetId from public_subnets_with_explicit_route )) then 'private'\n when p.SubnetId is not null or s.vpc_id in ( select vpc_id from public_subnets_with_implicit_route) then 'public'\n else 'private'\n end as access\n from\n aws_vpc_subnet as s\n left join public_subnets_with_explicit_route as p on p.SubnetId = s.subnet_id\n), cluster_public_subnet as (\n select\n distinct arn,\n name as subnet_group_name\n from\n aws_rds_db_subnet_group,\n jsonb_array_elements(subnets) as s\n left join subnet_accessibility as a on a.subnet_id = s ->> 'SubnetIdentifier'\n where\n a.access = 'public'\n)\nselect\n c.arn as resource,\n case\n when s.subnet_group_name is not null then 'alarm'\n else 'ok'\n end as status,\n case\n when s.subnet_group_name is not null then c.title || ' has public subnet.'\n else c.title || ' has private subnet.'\n end as reason\n \n \nfrom\n aws_rds_db_instance as c\n left join cluster_public_subnet as s on s.subnet_group_name = c.db_subnet_group_name;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH subnets_with_explicit_route AS ( + SELECT DISTINCT + (a ->> 'SubnetId') AS all_sub + FROM + aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a + WHERE + a ->> 'SubnetId' IS NOT NULL + ), public_subnets_with_explicit_route AS ( + SELECT DISTINCT + a ->> 'SubnetId' AS SubnetId + FROM + aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE + r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND ( + r ->> 'GatewayId' LIKE 'igw-%' + OR r ->> 'NatGatewayId' LIKE 'nat-%' + ) + AND a ->> 'SubnetId' IS NOT NULL + ), public_subnets_with_implicit_route AS ( + SELECT DISTINCT + route_table_id, + vpc_id, + region + FROM + aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE + a ->> 'Main' = 'true' + AND r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND ( + r ->> 'GatewayId' LIKE 'igw-%' + OR r ->> 'NatGatewayId' LIKE 'nat-%' + ) + ), subnet_accessibility AS ( + SELECT + subnet_id, + vpc_id, + CASE + WHEN s.subnet_id IN ( + SELECT all_sub FROM subnets_with_explicit_route + WHERE all_sub NOT IN ( + SELECT SubnetId FROM public_subnets_with_explicit_route + ) + ) THEN 'private' + WHEN p.SubnetId IS NOT NULL + OR s.vpc_id IN ( + SELECT vpc_id FROM public_subnets_with_implicit_route + ) THEN 'public' + ELSE 'private' + END AS access + FROM aws_vpc_subnet AS s + LEFT JOIN public_subnets_with_explicit_route AS p + ON p.SubnetId = s.subnet_id + ), cluster_public_subnet AS ( + SELECT DISTINCT + arn, + name AS subnet_group_name + FROM + aws_rds_db_subnet_group, + jsonb_array_elements(subnets) AS s + LEFT JOIN subnet_accessibility AS a + ON a.subnet_id = s ->> 'SubnetIdentifier' + WHERE a.access = 'public' + ) + SELECT + c.arn AS resource, + CASE + WHEN s.subnet_group_name IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN s.subnet_group_name IS NOT NULL THEN c.title || ' has public subnet.' + ELSE c.title || ' has private subnet.' + END AS reason + FROM aws_rds_db_instance AS c + LEFT JOIN cluster_public_subnet AS s + ON s.subnet_group_name = c.db_subnet_group_name; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: RDS DB instances should not use public subnet \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_redshift_cluster_encrypted_with_cmk.yaml b/compliance/controls/pending/aws/aws_redshift_cluster_encrypted_with_cmk.yaml old mode 100755 new mode 100644 index fc0a0d903..7e038dabd --- a/compliance/controls/pending/aws/aws_redshift_cluster_encrypted_with_cmk.yaml +++ b/compliance/controls/pending/aws/aws_redshift_cluster_encrypted_with_cmk.yaml @@ -1,13 +1,47 @@ +Description: Ensure Redshift cluster is encrypted using CMK. The rule is non-compliant if the Redshift clusters is not encrypted using CMK. ID: aws_redshift_cluster_encrypted_with_cmk -Title: "Redshift clusters should be encrypted with CMK" -Description: "Ensure Redshift cluster is encrypted using CMK. The rule is non-compliant if the Redshift clusters is not encrypted using CMK." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with redshift_clusters as (\n select\n arn,\n region,\n account_id,\n kms_key_id,\n encrypted,\n title,\n tags,\n _ctx\n from\n aws_redshift_cluster\n), kms_keys as (\n select\n k.arn,\n k.key_manager\n from\n aws_kms_key as k\n)\nselect\n r.arn as resource,\n case\n when not encrypted then 'alarm'\n when encrypted and c.key_manager = 'CUSTOMER' then 'ok'\n else 'alarm'\n end as status,\n case\n when not encrypted then title || ' not encrypted.'\n when encrypted and c.key_manager = 'CUSTOMER' then title || ' encrypted with CMK.'\n else title || ' not encrypted with CMK.'\n end as reason\n \n \nfrom\n redshift_clusters as r\n left join kms_keys as c on r.kms_key_id = c.arn;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH redshift_clusters AS ( + SELECT + arn, + region, + account_id, + kms_key_id, + encrypted, + title, + tags, + _ctx + FROM + aws_redshift_cluster + ), kms_keys AS ( + SELECT + k.arn, + k.key_manager + FROM + aws_kms_key AS k + ) + SELECT + r.arn AS resource, + CASE + WHEN NOT encrypted THEN 'alarm' + WHEN encrypted AND c.key_manager = 'CUSTOMER' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT encrypted THEN title || ' not encrypted.' + WHEN encrypted AND c.key_manager = 'CUSTOMER' THEN title || ' encrypted with CMK.' + ELSE title || ' not encrypted with CMK.' + END AS reason + FROM + redshift_clusters AS r + LEFT JOIN kms_keys AS c ON r.kms_key_id = c.arn; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: Redshift clusters should be encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_s3_bucket_object_logging_enabled.yaml b/compliance/controls/pending/aws/aws_s3_bucket_object_logging_enabled.yaml old mode 100755 new mode 100644 index 017d601b0..8a73d22fd --- a/compliance/controls/pending/aws/aws_s3_bucket_object_logging_enabled.yaml +++ b/compliance/controls/pending/aws/aws_s3_bucket_object_logging_enabled.yaml @@ -1,13 +1,74 @@ +Description: Object-Level logging saves events in JSON format in CloudTrail. This is recommended from a security best practice perspective for buckets that contain sensitive data. ID: aws_s3_bucket_object_logging_enabled -Title: "S3 buckets object logging should be enabled" -Description: "Object-Level logging saves events in JSON format in CloudTrail. This is recommended from a security best practice perspective for buckets that contain sensitive data." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with object_logging_cloudtrails as (\n select\n d ->> 'Type' as type,\n replace(replace(v::text,'\"',''),'/','') as bucket_arn\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) e,\n jsonb_array_elements(e -> 'DataResources') as d,\n jsonb_array_elements(d -> 'Values') v\n where\n d ->> 'Type' = 'AWS::S3::Object'\n), object_logging_region as (\n select\n region as cloudtrail_region,\n replace(replace(v::text,'\"',''),'/','') as bucket_arn\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(event_selectors) e,\n jsonb_array_elements(e -> 'DataResources') as d,\n jsonb_array_elements(d -> 'Values') v\n where\n d ->> 'Type' = 'AWS::S3::Object'\n and replace(replace(v::text,'\"',''),'/','') = 'arn:aws:s3'\n group by\n region,\n bucket_arn\n),\nobject_logging_region_advance_es as (\n select\n region as cloudtrail_region\n from\n aws_cloudtrail_trail,\n jsonb_array_elements(advanced_event_selectors) a,\n jsonb_array_elements(a -> 'FieldSelectors') as f,\n jsonb_array_elements_text(f -> 'Equals') e\n where\n e = 'AWS::S3::Object'\n and f ->> 'Field' != 'eventCategory'\n group by\n region\n)\nselect\n distinct s.arn as resource,\n case\n when (s.arn = c.bucket_arn)\n or (r.bucket_arn = 'arn:aws:s3' and r. cloudtrail_region = s.region )\n or a. cloudtrail_region = s.region then 'ok'\n else 'alarm'\n end as status,\n case\n when (s.arn = c.bucket_arn)\n or (r.bucket_arn = 'arn:aws:s3' and r. cloudtrail_region = s.region )\n or a. cloudtrail_region = s.region then s.name || ' object logging enabled.'\n else s.name || ' object logging not enabled.'\n end as reason\n \n \nfrom\n aws_s3_bucket as s\n left join object_logging_cloudtrails as c on s.arn = c.bucket_arn\n left join object_logging_region as r on r. cloudtrail_region = s.region\n left join object_logging_region_advance_es as a on a. cloudtrail_region = s.region;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH object_logging_cloudtrails AS ( + SELECT + d ->> 'Type' AS type, + REPLACE(REPLACE(v::text,'\"',''),'/','') AS bucket_arn + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) e, + jsonb_array_elements(e -> 'DataResources') AS d, + jsonb_array_elements(d -> 'Values') v + WHERE + d ->> 'Type' = 'AWS::S3::Object' + ), + object_logging_region AS ( + SELECT + region AS cloudtrail_region, + REPLACE(REPLACE(v::text,'\"',''),'/','') AS bucket_arn + FROM + aws_cloudtrail_trail, + jsonb_array_elements(event_selectors) e, + jsonb_array_elements(e -> 'DataResources') AS d, + jsonb_array_elements(d -> 'Values') v + WHERE + d ->> 'Type' = 'AWS::S3::Object' + AND REPLACE(REPLACE(v::text,'\"',''),'/','') = 'arn:aws:s3' + GROUP BY + region, + bucket_arn + ), + object_logging_region_advance_es AS ( + SELECT + region AS cloudtrail_region + FROM + aws_cloudtrail_trail, + jsonb_array_elements(advanced_event_selectors) a, + jsonb_array_elements(a -> 'FieldSelectors') AS f, + jsonb_array_elements_text(f -> 'Equals') e + WHERE + e = 'AWS::S3::Object' + AND f ->> 'Field' != 'eventCategory' + GROUP BY + region + ) + SELECT + DISTINCT s.arn AS resource, + CASE + WHEN (s.arn = c.bucket_arn) + OR (r.bucket_arn = 'arn:aws:s3' AND r.cloudtrail_region = s.region) + OR a.cloudtrail_region = s.region THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (s.arn = c.bucket_arn) + OR (r.bucket_arn = 'arn:aws:s3' AND r.cloudtrail_region = s.region) + OR a.cloudtrail_region = s.region THEN s.name || ' object logging enabled.' + ELSE s.name || ' object logging not enabled.' + END AS reason + FROM + aws_s3_bucket AS s + LEFT JOIN object_logging_cloudtrails AS c ON s.arn = c.bucket_arn + LEFT JOIN object_logging_region AS r ON r.cloudtrail_region = s.region + LEFT JOIN object_logging_region_advance_es AS a ON a.cloudtrail_region = s.region Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: S3 buckets object logging should be enabled \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_vpc_subnet_multi_az_enabled.yaml b/compliance/controls/pending/aws/aws_vpc_subnet_multi_az_enabled.yaml old mode 100755 new mode 100644 index fbc525bf9..89e5047c7 --- a/compliance/controls/pending/aws/aws_vpc_subnet_multi_az_enabled.yaml +++ b/compliance/controls/pending/aws/aws_vpc_subnet_multi_az_enabled.yaml @@ -1,13 +1,46 @@ +Description: Ensure that each VPC has subnets spread across multiple availability zones. ID: aws_vpc_subnet_multi_az_enabled -Title: "VPCs subnets should exist in multiple availability zones" -Description: "Ensure that each VPC has subnets spread across multiple availability zones." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with subnet_list as (\n select\n distinct availability_zone,\n vpc_id,\n count(*)\n from\n aws_vpc_subnet\n group by\n vpc_id, availability_zone\n), zone_list as (\n select\n vpc_id,\n count(*) as num\n from\n subnet_list\n group by\n vpc_id\n)\nselect\n arn as resource,\n case\n when l.num is null then 'alarm'\n when l.num > 1 then 'ok'\n else 'alarm'\n end as status,\n case\n when l.num is null then v.title || ' no subnet exists.'\n when l.num > 1 then v.title || ' subnets exist in ' || num || ' availability zones.'\n else v.title || ' subnet(s) exist in single availability zone.'\n end as reason\n \n \nfrom\n aws_vpc as v\n left join zone_list as l on l.vpc_id = v.vpc_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH subnet_list AS ( + SELECT + DISTINCT availability_zone, + vpc_id, + COUNT(*) + FROM + aws_vpc_subnet + GROUP BY + vpc_id, availability_zone + ), zone_list AS ( + SELECT + vpc_id, + COUNT(*) AS num + FROM + subnet_list + GROUP BY + vpc_id + ) + SELECT + arn AS resource, + CASE + WHEN l.num IS NULL THEN 'alarm' + WHEN l.num > 1 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN l.num IS NULL THEN v.title || ' no subnet exists.' + WHEN l.num > 1 THEN v.title || ' subnets exist in ' || num || ' availability zones.' + ELSE v.title || ' subnet(s) exist in single availability zone.' + END AS reason + FROM + aws_vpc AS v + LEFT JOIN zone_list AS l ON l.vpc_id = v.vpc_id; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPCs subnets should exist in multiple availability zones \ No newline at end of file diff --git a/compliance/controls/pending/aws/aws_vpc_subnet_public_and_private.yaml b/compliance/controls/pending/aws/aws_vpc_subnet_public_and_private.yaml old mode 100755 new mode 100644 index 49b993454..63671aaab --- a/compliance/controls/pending/aws/aws_vpc_subnet_public_and_private.yaml +++ b/compliance/controls/pending/aws/aws_vpc_subnet_public_and_private.yaml @@ -1,13 +1,119 @@ +Description: Ensure that all VPCs have both public and private subnets configured. ID: aws_vpc_subnet_public_and_private -Title: "VPCs should have both public and private subnets configured" -Description: "Ensure that all VPCs have both public and private subnets configured." +IntegrationType: + - aws_cloud_account Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "with subnets_with_explicit_route as (\n select\n distinct ( a ->> 'SubnetId') as all_sub\n from\n aws_vpc_route_table as t,\n jsonb_array_elements(associations) as a\n where\n a ->> 'SubnetId' is not null\n), public_subnets_with_explicit_route as (\n select\n distinct a ->> 'SubnetId' as SubnetId\n from\n aws_vpc_route_table as t,\n jsonb_array_elements(associations) as a,\n jsonb_array_elements(routes) as r\n where\n r ->> 'DestinationCidrBlock' = '0.0.0.0/0'\n and\n (\n r ->> 'GatewayId' like 'igw-%'\n or r ->> 'NatGatewayId' like 'nat-%'\n )\n and a ->> 'SubnetId' is not null\n), public_subnets_with_implicit_route as (\n select\n distinct route_table_id,\n vpc_id,\n region\n from\n aws_vpc_route_table as t,\n jsonb_array_elements(associations) as a,\n jsonb_array_elements(routes) as r\n where\n a ->> 'Main' = 'true'\n and r ->> 'DestinationCidrBlock' = '0.0.0.0/0'\n and (\n r ->> 'GatewayId' like 'igw-%'\n or r ->> 'NatGatewayId' like 'nat-%'\n )\n), subnet_accessibility as (\nselect\n subnet_id,\n vpc_id,\n case\n when s.subnet_id in (select all_sub from subnets_with_explicit_route where all_sub not in (select SubnetId from public_subnets_with_explicit_route )) then 'private'\n when p.SubnetId is not null or s.vpc_id in ( select vpc_id from public_subnets_with_implicit_route) then 'public'\n else 'private'\n end as access\nfrom\naws_vpc_subnet as s\nleft join public_subnets_with_explicit_route as p on p.SubnetId = s.subnet_id\n)\nselect\n arn as resource,\n case\n when v.vpc_id not in (select vpc_id from subnet_accessibility) then 'alarm'\n when 'public' in (select access from subnet_accessibility where vpc_id = v.vpc_id) and 'private' in (select access from subnet_accessibility where vpc_id = v.vpc_id) then 'ok'\n when 'public' in (select access from subnet_accessibility where vpc_id = v.vpc_id) and not 'private' in (select access from subnet_accessibility where vpc_id = v.vpc_id) then 'alarm'\n when 'private' in (select access from subnet_accessibility where vpc_id = v.vpc_id) and not 'public' in (select access from subnet_accessibility where vpc_id = v.vpc_id) then 'alarm'\n end as status,\n case\n when v.vpc_id not in (select vpc_id from subnet_accessibility) then v.title || ' has no subnet.'\n when 'public' in (select access from subnet_accessibility where vpc_id = v.vpc_id) and 'private' in (select access from subnet_accessibility where vpc_id = v.vpc_id) then v.title || ' having both private and public subnet(s).'\n when 'public' in (select access from subnet_accessibility where vpc_id = v.vpc_id) and not 'private' in (select access from subnet_accessibility where vpc_id = v.vpc_id) then v.title || ' having only public subnet(s).'\n when 'private' in (select access from subnet_accessibility where vpc_id = v.vpc_id) and not 'public' in (select access from subnet_accessibility where vpc_id = v.vpc_id) then v.title || ' having only private subnet(s).'\n end as reason\n \n \nfrom\n aws_vpc as v;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + WITH subnets_with_explicit_route AS ( + SELECT DISTINCT (a ->> 'SubnetId') AS all_sub + FROM aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a + WHERE a ->> 'SubnetId' IS NOT NULL + ), public_subnets_with_explicit_route AS ( + SELECT DISTINCT a ->> 'SubnetId' AS SubnetId + FROM aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND ( + r ->> 'GatewayId' LIKE 'igw-%' + OR r ->> 'NatGatewayId' LIKE 'nat-%' + ) + AND a ->> 'SubnetId' IS NOT NULL + ), public_subnets_with_implicit_route AS ( + SELECT DISTINCT route_table_id, vpc_id, region + FROM aws_vpc_route_table AS t, + jsonb_array_elements(associations) AS a, + jsonb_array_elements(routes) AS r + WHERE a ->> 'Main' = 'true' + AND r ->> 'DestinationCidrBlock' = '0.0.0.0/0' + AND ( + r ->> 'GatewayId' LIKE 'igw-%' + OR r ->> 'NatGatewayId' LIKE 'nat-%' + ) + ), subnet_accessibility AS ( + SELECT subnet_id, vpc_id, + CASE + WHEN s.subnet_id IN ( + SELECT all_sub + FROM subnets_with_explicit_route + WHERE all_sub NOT IN (SELECT SubnetId FROM public_subnets_with_explicit_route) + ) THEN 'private' + WHEN p.SubnetId IS NOT NULL + OR s.vpc_id IN (SELECT vpc_id FROM public_subnets_with_implicit_route) + THEN 'public' + ELSE 'private' + END AS access + FROM aws_vpc_subnet AS s + LEFT JOIN public_subnets_with_explicit_route AS p + ON p.SubnetId = s.subnet_id + ) + SELECT arn AS resource, + CASE + WHEN v.vpc_id NOT IN (SELECT vpc_id FROM subnet_accessibility) THEN 'alarm' + WHEN 'public' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) AND 'private' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) THEN 'ok' + WHEN 'public' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) AND NOT 'private' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) THEN 'alarm' + WHEN 'private' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) AND NOT 'public' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) THEN 'alarm' + END AS status, + CASE + WHEN v.vpc_id NOT IN (SELECT vpc_id FROM subnet_accessibility) THEN v.title || ' has no subnet.' + WHEN 'public' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) AND 'private' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) THEN v.title || ' having both private and public subnet(s).' + WHEN 'public' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) AND NOT 'private' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) THEN v.title || ' having only public subnet(s).' + WHEN 'private' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) AND NOT 'public' IN ( + SELECT access + FROM subnet_accessibility + WHERE vpc_id = v.vpc_id + ) THEN v.title || ' having only private subnet(s).' + END AS reason + FROM aws_vpc AS v; Severity: low Tags: {} -IntegrationType: - - aws_cloud_account +Title: VPCs should have both public and private subnets configured \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_application_insights_linked_to_log_analytics_workspace.yaml b/compliance/controls/pending/azure/azure_application_insights_linked_to_log_analytics_workspace.yaml old mode 100755 new mode 100644 index a9b27c787..cfc7d34a1 --- a/compliance/controls/pending/azure/azure_application_insights_linked_to_log_analytics_workspace.yaml +++ b/compliance/controls/pending/azure/azure_application_insights_linked_to_log_analytics_workspace.yaml @@ -1,13 +1,29 @@ +Description: Link the Application Insights component to a Log Analytics workspace for logs encryption. Customer-managed keys are commonly required to meet regulatory compliance and for more control over the access to your data in Azure Monitor. Linking your component to a Log Analytics workspace that's enabled with a customer-managed key, ensures that your Application Insights logs meet this compliance requirement, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys. ID: azure_application_insights_linked_to_log_analytics_workspace -Title: "Azure Monitor Logs for Application Insights should be linked to a Log Analytics workspace" -Description: "Link the Application Insights component to a Log Analytics workspace for logs encryption. Customer-managed keys are commonly required to meet regulatory compliance and for more control over the access to your data in Azure Monitor. Linking your component to a Log Analytics workspace that's enabled with a customer-managed key, ensures that your Application Insights logs meet this compliance requirement, see https://docs.microsoft.com/azure/azure-monitor/platform/customer-managed-keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n when type = 'microsoft.insights/components' and workspace_resource_id is not null then 'ok'\n else 'alarm'\n end as status,\n case\n when type = 'microsoft.insights/components' and workspace_resource_id is not null then a.name || ' linked to log analytics workspace.'\n else a.name || ' not linked to log analytics workspace.'\n end as reason\n \n \n \nfrom\n azure_application_insight as a\n left join azure_subscription sub on sub.subscription_id = a.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN type = 'microsoft.insights/components' + AND workspace_resource_id IS NOT NULL THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN type = 'microsoft.insights/components' + AND workspace_resource_id IS NOT NULL THEN a.name || ' linked to log analytics workspace.' + ELSE a.name || ' not linked to log analytics workspace.' + END AS reason + FROM + azure_application_insight AS a + LEFT JOIN azure_subscription sub + ON sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Azure Monitor Logs for Application Insights should be linked to a Log Analytics workspace \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_appservice_web_app_worker_more_than_one.yaml b/compliance/controls/pending/azure/azure_appservice_web_app_worker_more_than_one.yaml old mode 100755 new mode 100644 index fb290eebe..2891546e3 --- a/compliance/controls/pending/azure/azure_appservice_web_app_worker_more_than_one.yaml +++ b/compliance/controls/pending/azure/azure_appservice_web_app_worker_more_than_one.yaml @@ -1,13 +1,26 @@ +Description: It is recommended to have more than one worker for failover. This control is non-compliant if Web apps have one or less than one worker. ID: azure_appservice_web_app_worker_more_than_one -Title: "Web app should have more than one worker" -Description: "It is recommended to have more than one worker for failover. This control is non-compliant if Web apps have one or less than one worker." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n p ->> 'ID' as resource,\n case\n when (p -> 'SiteProperties' -> 'siteConfig' ->> 'numberOfWorkers')::int > 1 then 'ok'\n else 'alarm'\n end as status,\n a.name || ' has ' || (p -> 'SiteProperties' -> 'siteConfig' ->> 'numberOfWorkers') || ' no of worker(s).' as reason\n \n \n \nfrom\n azure_app_service_plan as a,\n jsonb_array_elements(apps) as p,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + p ->> 'ID' AS resource, + CASE + WHEN (p -> 'SiteProperties' -> 'siteConfig' ->> 'numberOfWorkers')::int > 1 THEN 'ok' + ELSE 'alarm' + END AS status, + a.name || ' has ' || (p -> 'SiteProperties' -> 'siteConfig' ->> 'numberOfWorkers') || ' no of worker(s).' AS reason + FROM + azure_app_service_plan AS a, + jsonb_array_elements(apps) AS p, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Web app should have more than one worker \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_3_5.yaml b/compliance/controls/pending/azure/azure_cis_v130_3_5.yaml old mode 100755 new mode 100644 index a18cc8c5b..a873a22ba --- a/compliance/controls/pending/azure/azure_cis_v130_3_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_3_5.yaml @@ -1,13 +1,30 @@ +Description: Disable anonymous access to blob containers and disallow blob public access on storage account. ID: azure_cis_v130_3_5 -Title: "3.5 Ensure that 'Public access level' is set to Private for blob containers" -Description: "Disable anonymous access to blob containers and disallow blob public access on storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n container.id as resource,\n case\n when not account.allow_blob_public_access and container.public_access = 'None' then 'ok'\n else 'alarm'\n end as status,\n case\n when not account.allow_blob_public_access and container.public_access = 'None'\n then account.name || ' container ' || container.name || ' doesn''t allow anonymous access.'\n else account.name || ' container ' || container.name || ' allows anonymous access.'\n end as reason\n \n \n \nfrom\n azure_storage_container container\n join azure_storage_account account on container.account_name = account.name\n join azure_subscription sub on sub.subscription_id = account.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + container.id AS resource, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' + THEN account.name || ' container ' || container.name || ' doesn''t allow anonymous access.' + ELSE account.name || ' container ' || container.name || ' allows anonymous access.' + END AS reason + FROM + azure_storage_container container + JOIN azure_storage_account account + ON container.account_name = account.name + JOIN azure_subscription sub + ON sub.subscription_id = account.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.5 Ensure that 'Public access level' is set to Private for blob containers \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_1_1.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_1_1.yaml old mode 100755 new mode 100644 index e074c1bc4..028114149 --- a/compliance/controls/pending/azure/azure_cis_v130_4_1_1.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_1_1.yaml @@ -1,13 +1,29 @@ +Description: Enable auditing on SQL Servers. ID: azure_cis_v130_4_1_1 -Title: "4.1.1 Ensure that 'Auditing' is set to 'On'" -Description: "Enable auditing on SQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then name || ' auditing disabled.'\n else name || ' auditing enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN name || ' auditing disabled.' + ELSE name || ' auditing enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.1 Ensure that 'Auditing' is set to 'On' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_1_3.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_1_3.yaml old mode 100755 new mode 100644 index 6b5e5c636..b7e4058ff --- a/compliance/controls/pending/azure/azure_cis_v130_4_1_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_1_3.yaml @@ -1,13 +1,31 @@ +Description: SQL Server Audit Retention should be configured to be greater than 90 days. ID: azure_cis_v130_4_1_3 -Title: "4.1.3 Ensure that 'Auditing' Retention is 'greater than 90 days'" -Description: "SQL Server Audit Retention should be configured to be greater than 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then 'ok'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then name || ' audit retention set to unlimited days.'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then name || ' audit retention greater than 90 days.'\n else name || ' audit retention less than 90 days.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN 'ok' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN name || ' audit retention set to unlimited days.' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN name || ' audit retention greater than 90 days.' + ELSE name || ' audit retention less than 90 days.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.3 Ensure that 'Auditing' Retention is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_2_1.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_2_1.yaml old mode 100755 new mode 100644 index 31d4e8176..daba84356 --- a/compliance/controls/pending/azure/azure_cis_v130_4_2_1.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_2_1.yaml @@ -1,13 +1,29 @@ +Description: Enable "Azure Defender for SQL" on critical SQL Servers. ID: azure_cis_v130_4_2_1 -Title: "4.2.1 Ensure that Advanced Threat Protection (ATP) on a SQL server is set to 'Enabled'" -Description: "Enable \\\"Azure Defender for SQL\\\" on critical SQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then s.name || ' Azure defender disabled.'\n else s.name || ' Azure defender enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN s.name || ' Azure defender disabled.' + ELSE s.name || ' Azure defender enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.1 Ensure that Advanced Threat Protection (ATP) on a SQL server is set to 'Enabled' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_2_2.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_2_2.yaml old mode 100755 new mode 100644 index 150d52fcc..2863d0330 --- a/compliance/controls/pending/azure/azure_cis_v130_4_2_2.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_2_2.yaml @@ -1,13 +1,30 @@ +Description: Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases. ID: azure_cis_v130_4_2_2 -Title: "4.2.2 Ensure that Vulnerability Assessment (VA) is enabled on a SQL server by setting a Storage Account" -Description: "Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then s.name || ' VA setting disabled.'\n else s.name || ' VA setting enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN s.name || ' VA setting disabled.' + ELSE s.name || ' VA setting enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.2 Ensure that Vulnerability Assessment (VA) is enabled on a SQL server by setting a Storage Account \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_2_3.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_2_3.yaml old mode 100755 new mode 100644 index 694753812..bfa7486d1 --- a/compliance/controls/pending/azure/azure_cis_v130_4_2_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_2_3.yaml @@ -1,13 +1,46 @@ +Description: Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases. ID: azure_cis_v130_4_2_3 -Title: "4.2.3 Ensure that VA setting Periodic Recurring Scans is enabled on a SQL server" -Description: "Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false'\n )\n then s.name || ' VA setting periodic recurring scans disabled.'\n else s.name || ' VA setting periodic recurring scans enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false' + ) + THEN s.name || ' VA setting periodic recurring scans disabled.' + ELSE s.name || ' VA setting periodic recurring scans enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.3 Ensure that VA setting Periodic Recurring Scans is enabled on a SQL server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_2_4.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_2_4.yaml old mode 100755 new mode 100644 index c0d2892a8..c0062af8a --- a/compliance/controls/pending/azure/azure_cis_v130_4_2_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_2_4.yaml @@ -1,13 +1,44 @@ +Description: Configure 'Send scan reports to' with email ids of concerned data owners/stakeholders for a critical SQL servers. ID: azure_cis_v130_4_2_4 -Title: "4.2.4 Ensure that VA setting Send scan reports to is configured for a SQL server" -Description: "Configure 'Send scan reports to' with email ids of concerned data owners/stakeholders for a critical SQL servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]'\n )\n then s.name || ' VA scan reports and alerts not configured send email.'\n else s.name || ' VA scan reports and alerts configured to send email.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]' + ) + THEN s.name || ' VA scan reports and alerts not configured send email.' + ELSE s.name || ' VA scan reports and alerts configured to send email.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.4 Ensure that VA setting Send scan reports to is configured for a SQL server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_2_5.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_2_5.yaml old mode 100755 new mode 100644 index 6bae2b81a..b9f535a6d --- a/compliance/controls/pending/azure/azure_cis_v130_4_2_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_2_5.yaml @@ -1,13 +1,46 @@ +Description: Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'. ID: azure_cis_v130_4_2_5 -Title: "4.2.5 Ensure that VA setting 'Also send email notifications to admins and subscription owners' is set for a SQL server" -Description: "Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false'\n )\n then s.name || ' VA setting not configured to send email notifications to subscription admins and owners.'\n else s.name || ' VA setting configured to send email notifications to subscription admins and owners.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false' + ) + THEN s.name || ' VA setting not configured to send email notifications to subscription admins and owners.' + ELSE s.name || ' VA setting configured to send email notifications to subscription admins and owners.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.5 Ensure that VA setting 'Also send email notifications to admins and subscription owners' is set for a SQL server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_3_3.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_3_3.yaml old mode 100755 new mode 100644 index 23f353683..b82166598 --- a/compliance/controls/pending/azure/azure_cis_v130_4_3_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_3_3.yaml @@ -1,13 +1,31 @@ +Description: Enable log_checkpoints on PostgreSQL Servers. ID: azure_cis_v130_4_3_3 -Title: "4.3.3 Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_checkpoints on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_checkpoints off.'\n else s.name || ' server parameter log_checkpoints on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_checkpoints'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' + THEN s.name || ' server parameter log_checkpoints off.' + ELSE s.name || ' server parameter log_checkpoints on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_checkpoints' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.3 Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_3_4.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_3_4.yaml old mode 100755 new mode 100644 index 10000ed30..a4fd5a19c --- a/compliance/controls/pending/azure/azure_cis_v130_4_3_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_3_4.yaml @@ -1,13 +1,30 @@ +Description: Enable log_connections on PostgreSQL Servers. ID: azure_cis_v130_4_3_4 -Title: "4.3.4 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_connections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_connections off.'\n else s.name || ' server parameter log_connections on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_connections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_connections off.' + ELSE s.name || ' server parameter log_connections on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_connections' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.4 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_3_6.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_3_6.yaml old mode 100755 new mode 100644 index 155bf2d8a..0cf146746 --- a/compliance/controls/pending/azure/azure_cis_v130_4_3_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_3_6.yaml @@ -1,13 +1,30 @@ +Description: Enable connection_throttling on PostgreSQL Servers. ID: azure_cis_v130_4_3_6 -Title: "4.3.6 Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable connection_throttling on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter connection_throttling off.'\n else s.name || ' server parameter connection_throttling on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'connection_throttling'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter connection_throttling off.' + ELSE s.name || ' server parameter connection_throttling on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'connection_throttling' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.6 Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_3_7.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_3_7.yaml old mode 100755 new mode 100644 index d98d6f2e8..589913955 --- a/compliance/controls/pending/azure/azure_cis_v130_4_3_7.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_3_7.yaml @@ -1,13 +1,30 @@ +Description: Enable log_retention_days on PostgreSQL Servers. ID: azure_cis_v130_4_3_7 -Title: "4.3.7 Ensure server parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server" -Description: "Enable log_retention_days on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then 'alarm'\n else 'ok'\n end as status,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then s.name || ' log files are retained for 3 days or lesser.'\n else s.name || ' log files are retained for more than 3 days.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) as config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_retention_days'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 THEN s.name || ' log files are retained for 3 days or lesser.' + ELSE s.name || ' log files are retained for more than 3 days.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) AS config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_retention_days' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.7 Ensure server parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_4_5.yaml b/compliance/controls/pending/azure/azure_cis_v130_4_5.yaml old mode 100755 new mode 100644 index ebb278f2a..27c2b39ba --- a/compliance/controls/pending/azure/azure_cis_v130_4_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_4_5.yaml @@ -1,13 +1,29 @@ +Description: Based on business needs or criticality of data/databases hosted on a SQL server, it is recommended that the TDE protector is encrypted by a key that is managed by the data owner (Customer-managed key) ID: azure_cis_v130_4_5 -Title: "4.5 Ensure SQL server's TDE protector is encrypted with Customer-managed key" -Description: "Based on business needs or criticality of data/databases hosted a SQL server, it is recommended that the TDE protector is encrypted by a key that is managed by the data owner (Customer-managed key)" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when encryption ->> 'kind' = 'servicemanaged' then 'alarm'\n else 'ok'\n end as status,\n case\n when encryption ->> 'kind' = 'servicemanaged' then s.name || ' TDE protector not encrypted with CMK.'\n else s.name || ' TDE protector encrypted with CMK.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(encryption_protector) encryption,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN s.name || ' TDE protector not encrypted with CMK.' + ELSE s.name || ' TDE protector encrypted with CMK.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(encryption_protector) encryption, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.5 Ensure SQL server's TDE protector is encrypted with Customer-managed key \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_5_1_4.yaml b/compliance/controls/pending/azure/azure_cis_v130_5_1_4.yaml old mode 100755 new mode 100644 index e0fd4a501..c567e0058 --- a/compliance/controls/pending/azure/azure_cis_v130_5_1_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_5_1_4.yaml @@ -1,13 +1,32 @@ +Description: The storage account with the activity log export container is configured to use BYOK (Use Your Own Key). ID: azure_cis_v130_5_1_4 -Title: "5.1.4 Ensure the storage account containing the container with activity logs is encrypted with BYOK (Use Your Own Key)" -Description: "The storage account with the activity log export container is configured to use BYOK (Use Your Own Key)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault'\n then a.name || ' container insights-operational-logs encrypted with BYOK.'\n else a.name || ' container insights-operational-logs not encrypted with BYOK.'\n end as reason\n \n \n \nfrom\n azure_storage_container c,\n azure_storage_account a,\n azure_subscription sub\nwhere\n c.name = 'insights-operational-logs'\n and c.account_name = a.name\n and sub.subscription_id = a.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' + THEN a.name || ' container insights-operational-logs encrypted with BYOK.' + ELSE a.name || ' container insights-operational-logs not encrypted with BYOK.' + END AS reason + FROM + azure_storage_container c, + azure_storage_account a, + azure_subscription sub + WHERE + c.name = 'insights-operational-logs' + AND c.account_name = a.name + AND sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.4 Ensure the storage account containing the container with activity logs is encrypted with BYOK (Use Your Own Key) \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_6_4.yaml b/compliance/controls/pending/azure/azure_cis_v130_6_4.yaml old mode 100755 new mode 100644 index 42bce4783..2edb6e963 --- a/compliance/controls/pending/azure/azure_cis_v130_6_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_6_4.yaml @@ -1,13 +1,30 @@ +Description: Network Security Group Flow Logs should be enabled and the retention period is set to greater than or equal to 90 days. ID: azure_cis_v130_6_4 -Title: "6.4 Ensure that Network Security Group Flow Log retention period is 'greater than 90 days'" -Description: "Network Security Group Flow Logs should be enabled and the retention period is set to greater than or equal to 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sg.id resource,\n case\n when fl.id is null or not fl.enabled or fl.retention_policy_days < 90 then 'alarm'\n else 'ok'\n end as status,\n case\n when fl.id is null or not fl.enabled\n then sg.name || ' flowlog not enabled.'\n when fl.retention_policy_days < 90\n then sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.'\n else sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.'\n end as reason\n \n \n \nfrom\n azure_network_security_group sg\n left join azure_network_watcher_flow_log fl on sg.id = fl.target_resource_id\n join azure_subscription sub on sub.subscription_id = sg.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sg.id AS resource, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled OR fl.retention_policy_days < 90 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled THEN sg.name || ' flowlog not enabled.' + WHEN fl.retention_policy_days < 90 THEN sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.' + ELSE sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.' + END AS reason + FROM + azure_network_security_group sg + LEFT JOIN + azure_network_watcher_flow_log fl ON sg.id = fl.target_resource_id + JOIN + azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.4 Ensure that Network Security Group Flow Log retention period is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_6_5.yaml b/compliance/controls/pending/azure/azure_cis_v130_6_5.yaml old mode 100755 new mode 100644 index 522e4b9c9..eef1830a3 --- a/compliance/controls/pending/azure/azure_cis_v130_6_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_6_5.yaml @@ -1,13 +1,28 @@ +Description: Enable Network Watcher for Azure subscriptions. ID: azure_cis_v130_6_5 -Title: "6.5 Ensure that Network Watcher is 'Enabled'" -Description: "Enable Network Watcher for Azure subscriptions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n loc.id resource,\n case\n when watcher.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when watcher.id is null then 'Network watcher not enabled in ' || loc.name || '.'\n else 'Network watcher enabled in ' || loc.name || '.'\n end as reason,\n loc.name\n \n \n \nfrom\n azure_location loc\n left join azure_network_watcher watcher on watcher.region = loc.name\n join azure_subscription sub on sub.subscription_id = loc.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + loc.id AS resource, + CASE + WHEN watcher.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN watcher.id IS NULL THEN 'Network watcher not enabled in ' || loc.name || '.' + ELSE 'Network watcher enabled in ' || loc.name || '.' + END AS reason, + loc.name + FROM + azure_location loc + LEFT JOIN azure_network_watcher watcher ON watcher.region = loc.name + JOIN azure_subscription sub ON sub.subscription_id = loc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.5 Ensure that Network Watcher is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v130_9_10.yaml b/compliance/controls/pending/azure/azure_cis_v130_9_10.yaml old mode 100755 new mode 100644 index 68b1cb39a..ab042b5ce --- a/compliance/controls/pending/azure/azure_cis_v130_9_10.yaml +++ b/compliance/controls/pending/azure/azure_cis_v130_9_10.yaml @@ -1,13 +1,44 @@ +Description: By default, Azure Functions, Web and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions. ID: azure_cis_v130_9_10 -Title: "9.10 Ensure FTP deployments are disabled" -Description: "By default, Azure Functions, Web and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n fa.id as resource,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n \n \n from\n azure_app_service_function_app fa,\n azure_subscription sub\n where\n sub.subscription_id = fa.subscription_id\nunion\n select\n wa.id as resource,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n \n \n from\n azure_app_service_web_app as wa,\n azure_subscription as sub\n where\n sub.subscription_id = wa.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + fa.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason + FROM + azure_app_service_function_app fa, + azure_subscription sub + WHERE + sub.subscription_id = fa.subscription_id + UNION + SELECT + wa.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason + FROM + azure_app_service_web_app AS wa, + azure_subscription AS sub + WHERE + sub.subscription_id = wa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.10 Ensure FTP deployments are disabled \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_1_6.yaml b/compliance/controls/pending/azure/azure_cis_v140_1_6.yaml old mode 100755 new mode 100644 index 47b67ae8a..7840b2f14 --- a/compliance/controls/pending/azure/azure_cis_v140_1_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_1_6.yaml @@ -1,17 +1,17 @@ +Description: Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0. ID: azure_cis_v140_1_6 -Title: "1.6 Ensure that 'Number of days before users are asked to re-confirm their authentication information' is not set to \\\"0\\\"" -Description: "Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.6 Ensure that 'Number of days before users are asked to re-confirm their authentication information' is not set to "0" \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_1_8.yaml b/compliance/controls/pending/azure/azure_cis_v140_1_8.yaml old mode 100755 new mode 100644 index f4c79da69..a2cdf5973 --- a/compliance/controls/pending/azure/azure_cis_v140_1_8.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_1_8.yaml @@ -1,17 +1,17 @@ +Description: Ensure that all administrators are notified if any other administrator resets their password. ID: azure_cis_v140_1_8 -Title: "1.8 Ensure that 'Notify all admins when other admins reset their password?' is set to 'Yes'" -Description: "Ensure that all administrators are notified if any other administrator resets their password." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.8 Ensure that 'Notify all admins when other admins reset their password?' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_3_5.yaml b/compliance/controls/pending/azure/azure_cis_v140_3_5.yaml old mode 100755 new mode 100644 index d8b8e9e94..be987a4d8 --- a/compliance/controls/pending/azure/azure_cis_v140_3_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_3_5.yaml @@ -1,13 +1,28 @@ +Description: Disable anonymous access to blob containers and disallow blob public access on storage account. ID: azure_cis_v140_3_5 -Title: "3.5 Ensure that 'Public access level' is set to Private for blob containers" -Description: "Disable anonymous access to blob containers and disallow blob public access on storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n container.id as resource,\n case\n when not account.allow_blob_public_access and container.public_access = 'None' then 'ok'\n else 'alarm'\n end as status,\n case\n when not account.allow_blob_public_access and container.public_access = 'None'\n then account.name || ' container ' || container.name || ' doesn''t allow anonymous access.'\n else account.name || ' container ' || container.name || ' allows anonymous access.'\n end as reason\n \n \n \nfrom\n azure_storage_container container\n join azure_storage_account account on container.account_name = account.name\n join azure_subscription sub on sub.subscription_id = account.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + container.id AS resource, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' + THEN account.name || ' container ' || container.name || ' doesn''t allow anonymous access.' + ELSE account.name || ' container ' || container.name || ' allows anonymous access.' + END AS reason + FROM + azure_storage_container container + JOIN azure_storage_account account ON container.account_name = account.name + JOIN azure_subscription sub ON sub.subscription_id = account.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.5 Ensure that 'Public access level' is set to Private for blob containers \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_1_1.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_1_1.yaml old mode 100755 new mode 100644 index 8bf84c3a9..2777c4b1b --- a/compliance/controls/pending/azure/azure_cis_v140_4_1_1.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_1_1.yaml @@ -1,13 +1,29 @@ +Description: Enable auditing on SQL Servers. ID: azure_cis_v140_4_1_1 -Title: "4.1.1 Ensure that 'Auditing' is set to 'On'" -Description: "Enable auditing on SQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then name || ' auditing disabled.'\n else name || ' auditing enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN name || ' auditing disabled.' + ELSE name || ' auditing enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.1 Ensure that 'Auditing' is set to 'On' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_1_3.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_1_3.yaml old mode 100755 new mode 100644 index 0705db481..649ab5b4d --- a/compliance/controls/pending/azure/azure_cis_v140_4_1_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_1_3.yaml @@ -1,13 +1,31 @@ +Description: SQL Server Audit Retention should be configured to be greater than 90 days. ID: azure_cis_v140_4_1_3 -Title: "4.1.3 Ensure that 'Auditing' Retention is 'greater than 90 days'" -Description: "SQL Server Audit Retention should be configured to be greater than 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then 'ok'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then name || ' audit retention set to unlimited days.'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then name || ' audit retention greater than 90 days.'\n else name || ' audit retention less than 90 days.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN 'ok' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN name || ' audit retention set to unlimited days.' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN name || ' audit retention greater than 90 days.' + ELSE name || ' audit retention less than 90 days.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.3 Ensure that 'Auditing' Retention is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_2_1.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_2_1.yaml old mode 100755 new mode 100644 index 4abedd1ee..9d20a1fde --- a/compliance/controls/pending/azure/azure_cis_v140_4_2_1.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_2_1.yaml @@ -1,13 +1,29 @@ +Description: Enable "Azure Defender for SQL" on critical SQL Servers. ID: azure_cis_v140_4_2_1 -Title: "4.2.1 Ensure that Advanced Threat Protection (ATP) on a SQL server is set to 'Enabled'" -Description: "Enable \\\"Azure Defender for SQL\\\" on critical SQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then s.name || ' Azure defender disabled.'\n else s.name || ' Azure defender enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN s.name || ' Azure defender disabled.' + ELSE s.name || ' Azure defender enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.1 Ensure that Advanced Threat Protection (ATP) on a SQL server is set to 'Enabled' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_2_2.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_2_2.yaml old mode 100755 new mode 100644 index 2e8fc0f14..b1b2a327f --- a/compliance/controls/pending/azure/azure_cis_v140_4_2_2.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_2_2.yaml @@ -1,13 +1,30 @@ +Description: Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases. ID: azure_cis_v140_4_2_2 -Title: "4.2.2 Ensure that Vulnerability Assessment (VA) is enabled on a SQL server by setting a Storage Account" -Description: "Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then s.name || ' VA setting disabled.'\n else s.name || ' VA setting enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN s.name || ' VA setting disabled.' + ELSE s.name || ' VA setting enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.2 Ensure that Vulnerability Assessment (VA) is enabled on a SQL server by setting a Storage Account \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_2_3.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_2_3.yaml old mode 100755 new mode 100644 index 3445f449f..64653266b --- a/compliance/controls/pending/azure/azure_cis_v140_4_2_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_2_3.yaml @@ -1,13 +1,46 @@ +Description: Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases. ID: azure_cis_v140_4_2_3 -Title: "4.2.3 Ensure that VA setting Periodic Recurring Scans is enabled on a SQL server" -Description: "Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false'\n )\n then s.name || ' VA setting periodic recurring scans disabled.'\n else s.name || ' VA setting periodic recurring scans enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false' + ) + THEN s.name || ' VA setting periodic recurring scans disabled.' + ELSE s.name || ' VA setting periodic recurring scans enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.3 Ensure that VA setting Periodic Recurring Scans is enabled on a SQL server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_2_4.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_2_4.yaml old mode 100755 new mode 100644 index a33a36370..d1e8553b5 --- a/compliance/controls/pending/azure/azure_cis_v140_4_2_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_2_4.yaml @@ -1,13 +1,46 @@ +Description: Configure 'Send scan reports to' with email ids of concerned data owners/stakeholders for a critical SQL servers. ID: azure_cis_v140_4_2_4 -Title: "4.2.4 Ensure that VA setting 'Send scan reports to' is configured for a SQL server" -Description: "Configure 'Send scan reports to' with email ids of concerned data owners/stakeholders for a critical SQL servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]'\n )\n then s.name || ' VA scan reports and alerts not configured send email.'\n else s.name || ' VA scan reports and alerts configured to send email.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]' + ) + THEN s.name || ' VA scan reports and alerts not configured send email.' + ELSE s.name || ' VA scan reports and alerts configured to send email.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.4 Ensure that VA setting 'Send scan reports to' is configured for a SQL server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_2_5.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_2_5.yaml old mode 100755 new mode 100644 index 44956bc50..ae8889b5e --- a/compliance/controls/pending/azure/azure_cis_v140_4_2_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_2_5.yaml @@ -1,13 +1,46 @@ +Description: Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'. ID: azure_cis_v140_4_2_5 -Title: "4.2.5 Ensure that Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners' is set for each SQL server" -Description: "Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false'\n )\n then s.name || ' VA setting not configured to send email notifications to subscription admins and owners.'\n else s.name || ' VA setting configured to send email notifications to subscription admins and owners.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false' + ) + THEN s.name || ' VA setting not configured to send email notifications to subscription admins and owners.' + ELSE s.name || ' VA setting configured to send email notifications to subscription admins and owners.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.5 Ensure that Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners' is set for each SQL server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_3_2.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_3_2.yaml old mode 100755 new mode 100644 index 0c12819ca..4661d9084 --- a/compliance/controls/pending/azure/azure_cis_v140_4_3_2.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_3_2.yaml @@ -1,13 +1,30 @@ +Description: Enable log_checkpoints on PostgreSQL Servers. ID: azure_cis_v140_4_3_2 -Title: "4.3.2 Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_checkpoints on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_checkpoints off.'\n else s.name || ' server parameter log_checkpoints on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_checkpoints'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_checkpoints off.' + ELSE s.name || ' server parameter log_checkpoints on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_checkpoints' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.2 Ensure server parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_3_3.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_3_3.yaml old mode 100755 new mode 100644 index f22c4c1b2..e131a4a9b --- a/compliance/controls/pending/azure/azure_cis_v140_4_3_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_3_3.yaml @@ -1,13 +1,30 @@ +Description: Enable log_connections on PostgreSQL Servers. ID: azure_cis_v140_4_3_3 -Title: "4.3.3 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_connections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_connections off.'\n else s.name || ' server parameter log_connections on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_connections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_connections off.' + ELSE s.name || ' server parameter log_connections on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_connections' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.3 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_3_4.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_3_4.yaml old mode 100755 new mode 100644 index d2ccf16f7..24bfb5e2b --- a/compliance/controls/pending/azure/azure_cis_v140_4_3_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_3_4.yaml @@ -1,13 +1,30 @@ +Description: Enable log_disconnections on PostgreSQL Servers. ID: azure_cis_v140_4_3_4 -Title: "4.3.4 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_disconnections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then name || ' server parameter log_disconnections off.'\n else name || ' server parameter log_disconnections on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_disconnections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN name || ' server parameter log_disconnections off.' + ELSE name || ' server parameter log_disconnections on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_disconnections' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.4 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_3_5.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_3_5.yaml old mode 100755 new mode 100644 index 9b6ea847f..0c516f674 --- a/compliance/controls/pending/azure/azure_cis_v140_4_3_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_3_5.yaml @@ -1,13 +1,30 @@ +Description: Enable connection_throttling on PostgreSQL Servers. ID: azure_cis_v140_4_3_5 -Title: "4.3.5 Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable connection_throttling on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter connection_throttling off.'\n else s.name || ' server parameter connection_throttling on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'connection_throttling'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter connection_throttling off.' + ELSE s.name || ' server parameter connection_throttling on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'connection_throttling' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.5 Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_3_6.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_3_6.yaml old mode 100755 new mode 100644 index 8afac87b8..06ddc4b62 --- a/compliance/controls/pending/azure/azure_cis_v140_4_3_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_3_6.yaml @@ -1,13 +1,30 @@ +Description: Enable log_retention_days on PostgreSQL Servers. ID: azure_cis_v140_4_3_6 -Title: "4.3.6 Ensure server parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server" -Description: "Enable log_retention_days on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then 'alarm'\n else 'ok'\n end as status,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then s.name || ' log files are retained for 3 days or lesser.'\n else s.name || ' log files are retained for more than 3 days.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) as config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_retention_days'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::INTEGER <= 3 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::INTEGER <= 3 THEN s.name || ' log files are retained for 3 days or lesser.' + ELSE s.name || ' log files are retained for more than 3 days.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) AS config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_retention_days' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.6 Ensure server parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_4_6.yaml b/compliance/controls/pending/azure/azure_cis_v140_4_6.yaml old mode 100755 new mode 100644 index 308fb924e..bc20856ce --- a/compliance/controls/pending/azure/azure_cis_v140_4_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_4_6.yaml @@ -1,13 +1,29 @@ +Description: Based on business needs or criticality of data/databases hosted a SQL server, it is recommended that the TDE protector is encrypted by a key that is managed by the data owner (Customer-managed key) ID: azure_cis_v140_4_6 -Title: "4.6 Ensure SQL server's TDE protector is encrypted with Customer-managed key" -Description: "Based on business needs or criticality of data/databases hosted a SQL server, it is recommended that the TDE protector is encrypted by a key that is managed by the data owner (Customer-managed key)" +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when encryption ->> 'kind' = 'servicemanaged' then 'alarm'\n else 'ok'\n end as status,\n case\n when encryption ->> 'kind' = 'servicemanaged' then s.name || ' TDE protector not encrypted with CMK.'\n else s.name || ' TDE protector encrypted with CMK.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(encryption_protector) encryption,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN s.name || ' TDE protector not encrypted with CMK.' + ELSE s.name || ' TDE protector encrypted with CMK.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(encryption_protector) encryption, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.6 Ensure SQL server's TDE protector is encrypted with Customer-managed key \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_5_1_4.yaml b/compliance/controls/pending/azure/azure_cis_v140_5_1_4.yaml old mode 100755 new mode 100644 index 78cac51ef..d62a14a7d --- a/compliance/controls/pending/azure/azure_cis_v140_5_1_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_5_1_4.yaml @@ -1,13 +1,32 @@ +Description: The storage account with the activity log export container is configured to use BYOK (Use Your Own Key). ID: azure_cis_v140_5_1_4 -Title: "5.1.4 Ensure the storage account containing the container with activity logs is encrypted with BYOK (Use Your Own Key)" -Description: "The storage account with the activity log export container is configured to use BYOK (Use Your Own Key)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault'\n then a.name || ' container insights-operational-logs encrypted with BYOK.'\n else a.name || ' container insights-operational-logs not encrypted with BYOK.'\n end as reason\n \n \n \nfrom\n azure_storage_container c,\n azure_storage_account a,\n azure_subscription sub\nwhere\n c.name = 'insights-operational-logs'\n and c.account_name = a.name\n and sub.subscription_id = a.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' + THEN a.name || ' container insights-operational-logs encrypted with BYOK.' + ELSE a.name || ' container insights-operational-logs not encrypted with BYOK.' + END AS reason + FROM + azure_storage_container c, + azure_storage_account a, + azure_subscription sub + WHERE + c.name = 'insights-operational-logs' + AND c.account_name = a.name + AND sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.4 Ensure the storage account containing the container with activity logs is encrypted with BYOK (Use Your Own Key) \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_6_4.yaml b/compliance/controls/pending/azure/azure_cis_v140_6_4.yaml old mode 100755 new mode 100644 index a1793a695..07611ac01 --- a/compliance/controls/pending/azure/azure_cis_v140_6_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_6_4.yaml @@ -1,13 +1,32 @@ +Description: Network Security Group Flow Logs should be enabled and the retention period is set to greater than or equal to 90 days. ID: azure_cis_v140_6_4 -Title: "6.4 Ensure that Network Security Group Flow Log retention period is 'greater than 90 days'" -Description: "Network Security Group Flow Logs should be enabled and the retention period is set to greater than or equal to 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sg.id resource,\n case\n when fl.id is null or not fl.enabled or fl.retention_policy_days < 90 then 'alarm'\n else 'ok'\n end as status,\n case\n when fl.id is null or not fl.enabled\n then sg.name || ' flowlog not enabled.'\n when fl.retention_policy_days < 90\n then sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.'\n else sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.'\n end as reason\n \n \n \nfrom\n azure_network_security_group sg\n left join azure_network_watcher_flow_log fl on sg.id = fl.target_resource_id\n join azure_subscription sub on sub.subscription_id = sg.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sg.id AS resource, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled OR fl.retention_policy_days < 90 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled + THEN sg.name || ' flowlog not enabled.' + WHEN fl.retention_policy_days < 90 + THEN sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.' + ELSE sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.' + END AS reason + FROM + azure_network_security_group sg + LEFT JOIN + azure_network_watcher_flow_log fl ON sg.id = fl.target_resource_id + JOIN + azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.4 Ensure that Network Security Group Flow Log retention period is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_6_5.yaml b/compliance/controls/pending/azure/azure_cis_v140_6_5.yaml old mode 100755 new mode 100644 index 38ec69a83..bf0b84afc --- a/compliance/controls/pending/azure/azure_cis_v140_6_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_6_5.yaml @@ -1,13 +1,30 @@ +Description: Enable Network Watcher for Azure subscriptions. ID: azure_cis_v140_6_5 -Title: "6.5 Ensure that Network Watcher is 'Enabled'" -Description: "Enable Network Watcher for Azure subscriptions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n loc.id resource,\n case\n when watcher.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when watcher.id is null then 'Network watcher not enabled in ' || loc.name || '.'\n else 'Network watcher enabled in ' || loc.name || '.'\n end as reason,\n loc.name\n \n \n \nfrom\n azure_location loc\n left join azure_network_watcher watcher on watcher.region = loc.name\n join azure_subscription sub on sub.subscription_id = loc.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + loc.id AS resource, + CASE + WHEN watcher.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN watcher.id IS NULL THEN 'Network watcher not enabled in ' || loc.name || '.' + ELSE 'Network watcher enabled in ' || loc.name || '.' + END AS reason, + loc.name + FROM + azure_location loc + LEFT JOIN + azure_network_watcher watcher ON watcher.region = loc.name + JOIN + azure_subscription sub ON sub.subscription_id = loc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.5 Ensure that Network Watcher is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v140_9_10.yaml b/compliance/controls/pending/azure/azure_cis_v140_9_10.yaml old mode 100755 new mode 100644 index 90681ec8a..0a78109f9 --- a/compliance/controls/pending/azure/azure_cis_v140_9_10.yaml +++ b/compliance/controls/pending/azure/azure_cis_v140_9_10.yaml @@ -1,13 +1,44 @@ +Description: By default, Azure Functions, Web and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions. ID: azure_cis_v140_9_10 -Title: "9.10 Ensure FTP deployments are disabled" -Description: "By default, Azure Functions, Web and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n fa.id as resource,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n \n \n from\n azure_app_service_function_app fa,\n azure_subscription sub\n where\n sub.subscription_id = fa.subscription_id\nunion\n select\n wa.id as resource,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n \n \n from\n azure_app_service_web_app as wa,\n azure_subscription as sub\n where\n sub.subscription_id = wa.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + fa.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason + FROM + azure_app_service_function_app fa, + azure_subscription sub + WHERE + sub.subscription_id = fa.subscription_id + UNION + SELECT + wa.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason + FROM + azure_app_service_web_app AS wa, + azure_subscription AS sub + WHERE + sub.subscription_id = wa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.10 Ensure FTP deployments are disabled \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_1_13.yaml b/compliance/controls/pending/azure/azure_cis_v150_1_13.yaml old mode 100755 new mode 100644 index c28990c24..ebd845c15 --- a/compliance/controls/pending/azure/azure_cis_v150_1_13.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_1_13.yaml @@ -1,17 +1,17 @@ +Description: Require administrators to provide consent for the apps before use. ID: azure_cis_v150_1_13 -Title: "1.13 Ensure that 'Users can add gallery apps to My Apps' is set to 'No'" -Description: "Require administrators to provide consent for the apps before use." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.13 Ensure that 'Users can add gallery apps to My Apps' is set to 'No' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_1_18.yaml b/compliance/controls/pending/azure/azure_cis_v150_1_18.yaml old mode 100755 new mode 100644 index 848fc31f4..e10cae5c2 --- a/compliance/controls/pending/azure/azure_cis_v150_1_18.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_1_18.yaml @@ -1,17 +1,17 @@ +Description: Restricts group creation to administrators with permissions only. ID: azure_cis_v150_1_18 -Title: "1.18 Ensure that 'Restrict user ability to access groups features in the Access Pane' is Set to 'Yes'" -Description: "Restricts group creation to administrators with permissions only." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.18 Ensure that 'Restrict user ability to access groups features in the Access Pane' is Set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_3_13.yaml b/compliance/controls/pending/azure/azure_cis_v150_3_13.yaml old mode 100755 new mode 100644 index 0e9aae693..84bc45d9d --- a/compliance/controls/pending/azure/azure_cis_v150_3_13.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_3_13.yaml @@ -1,13 +1,37 @@ +Description: 'The Storage Blob service provides scalable, cost-efficient object storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.' ID: azure_cis_v150_3_13 -Title: "3.13 Ensure Storage logging is Enabled for Blob Service for 'Read', 'Write', and 'Delete' requests" -Description: "The Storage Blob service provides scalable, cost-efficient object storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n case\n when not (sa.blob_service_logging ->> 'Read') :: boolean\n or not (sa.blob_service_logging ->> 'Write') :: boolean\n or not (sa.blob_service_logging ->> 'Delete') :: boolean then 'alarm'\n else 'ok'\n end as status,\n case\n when not (sa.blob_service_logging ->> 'Read') :: boolean\n or not (sa.blob_service_logging ->> 'Write') :: boolean\n or not (sa.blob_service_logging ->> 'Delete') :: boolean then name || ' blob service logging not enabled for ' ||\n concat_ws(', ',\n case when not (sa.blob_service_logging ->> 'Write') :: boolean then 'write' end,\n case when not (sa.blob_service_logging ->> 'Read') :: boolean then 'read' end,\n case when not (sa.blob_service_logging ->> 'Delete') :: boolean then 'delete' end\n ) || ' requests.'\n else name || ' blob service logging enabled for read, write, delete requests.'\n end as reason\n \n \n \nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sa.id AS resource, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN name || ' blob service logging not enabled for ' || + CONCAT_WS(', ', + CASE WHEN NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN THEN 'write' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN THEN 'read' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN 'delete' END + ) || ' requests.' + ELSE name || ' blob service logging enabled for read, write, delete requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.13 Ensure Storage logging is Enabled for Blob Service for 'Read', 'Write', and 'Delete' requests \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_1_1.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_1_1.yaml old mode 100755 new mode 100644 index 058313200..e80a7b5b1 --- a/compliance/controls/pending/azure/azure_cis_v150_4_1_1.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_1_1.yaml @@ -1,13 +1,29 @@ +Description: Enable auditing on SQL Servers. ID: azure_cis_v150_4_1_1 -Title: "4.1.1 Ensure that 'Auditing' is set to 'On'" -Description: "Enable auditing on SQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then name || ' auditing disabled.'\n else name || ' auditing enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN name || ' auditing disabled.' + ELSE name || ' auditing enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.1 Ensure that 'Auditing' is set to 'On' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_1_3.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_1_3.yaml old mode 100755 new mode 100644 index 0f9ce2c30..339735c41 --- a/compliance/controls/pending/azure/azure_cis_v150_4_1_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_1_3.yaml @@ -1,13 +1,29 @@ +Description: Transparent Data Encryption (TDE) with Customer-managed key support provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. ID: azure_cis_v150_4_1_3 -Title: "4.1.3 Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted with Customer-managed key" -Description: "Transparent Data Encryption (TDE) with Customer-managed key support provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when encryption ->> 'kind' = 'servicemanaged' then 'alarm'\n else 'ok'\n end as status,\n case\n when encryption ->> 'kind' = 'servicemanaged' then s.name || ' TDE protector not encrypted with CMK.'\n else s.name || ' TDE protector encrypted with CMK.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(encryption_protector) encryption,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN s.name || ' TDE protector not encrypted with CMK.' + ELSE s.name || ' TDE protector encrypted with CMK.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(encryption_protector) encryption, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.3 Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted with Customer-managed key \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_1_6.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_1_6.yaml old mode 100755 new mode 100644 index a46dc41df..7e80f78b5 --- a/compliance/controls/pending/azure/azure_cis_v150_4_1_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_1_6.yaml @@ -1,13 +1,31 @@ +Description: SQL Server Audit Retention should be configured to be greater than 90 days. ID: azure_cis_v150_4_1_6 -Title: "4.1.6 Ensure that 'Auditing' Retention is 'greater than 90 days'" -Description: "SQL Server Audit Retention should be configured to be greater than 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then 'ok'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then name || ' audit retention set to unlimited days.'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then name || ' audit retention greater than 90 days.'\n else name || ' audit retention less than 90 days.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN 'ok' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN name || ' audit retention set to unlimited days.' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN name || ' audit retention greater than 90 days.' + ELSE name || ' audit retention less than 90 days.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.6 Ensure that 'Auditing' Retention is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_2_1.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_2_1.yaml old mode 100755 new mode 100644 index f08f31cac..82ab206af --- a/compliance/controls/pending/azure/azure_cis_v150_4_2_1.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_2_1.yaml @@ -1,13 +1,29 @@ +Description: Enable "Azure Defender for SQL" on critical SQL Servers. ID: azure_cis_v150_4_2_1 -Title: "4.2.1 Ensure that Microsoft Defender for SQL is set to 'On' for critical SQL Servers" -Description: "Enable \\\"Azure Defender for SQL\\\" on critical SQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then s.name || ' Azure defender disabled.'\n else s.name || ' Azure defender enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN s.name || ' Azure defender disabled.' + ELSE s.name || ' Azure defender enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.1 Ensure that Microsoft Defender for SQL is set to 'On' for critical SQL Servers \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_2_2.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_2_2.yaml old mode 100755 new mode 100644 index 3cf5958ad..97a3eeca3 --- a/compliance/controls/pending/azure/azure_cis_v150_4_2_2.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_2_2.yaml @@ -1,13 +1,30 @@ +Description: Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases. ID: azure_cis_v150_4_2_2 -Title: "4.2.2 Ensure that Vulnerability Assessment (VA) is enabled on a SQL server by setting a Storage Account" -Description: "Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then s.name || ' VA setting disabled.'\n else s.name || ' VA setting enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN s.name || ' VA setting disabled.' + ELSE s.name || ' VA setting enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.2 Ensure that Vulnerability Assessment (VA) is enabled on a SQL server by setting a Storage Account \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_2_3.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_2_3.yaml old mode 100755 new mode 100644 index 4c641726e..61fe3d455 --- a/compliance/controls/pending/azure/azure_cis_v150_4_2_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_2_3.yaml @@ -1,13 +1,47 @@ +Description: Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases. ID: azure_cis_v150_4_2_3 -Title: "4.2.3 Ensure that Vulnerability Assessment (VA) setting 'Periodic recurring scans' is set to 'on' for each SQL server" -Description: "Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false'\n )\n then s.name || ' VA setting periodic recurring scans disabled.'\n else s.name || ' VA setting periodic recurring scans enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false' + ) + THEN s.name || ' VA setting periodic recurring scans disabled.' + ELSE s.name || ' VA setting periodic recurring scans enabled.' + END AS reason + + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.3 Ensure that Vulnerability Assessment (VA) setting 'Periodic recurring scans' is set to 'on' for each SQL server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_2_4.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_2_4.yaml old mode 100755 new mode 100644 index d99543384..63c627401 --- a/compliance/controls/pending/azure/azure_cis_v150_4_2_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_2_4.yaml @@ -1,13 +1,46 @@ +Description: Configure 'Send scan reports to' with email ids of concerned data owners/stakeholders for a critical SQL servers. ID: azure_cis_v150_4_2_4 -Title: "4.2.4 Ensure that Vulnerability Assessment (VA) setting 'Send scan reports to' is configured for a SQL server" -Description: "Configure 'Send scan reports to' with email ids of concerned data owners/stakeholders for a critical SQL servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]'\n )\n then s.name || ' VA scan reports and alerts not configured send email.'\n else s.name || ' VA scan reports and alerts configured to send email.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]' + ) + THEN s.name || ' VA scan reports and alerts not configured send email.' + ELSE s.name || ' VA scan reports and alerts configured to send email.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.4 Ensure that Vulnerability Assessment (VA) setting 'Send scan reports to' is configured for a SQL server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_2_5.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_2_5.yaml old mode 100755 new mode 100644 index 021c2a96b..39f2184b1 --- a/compliance/controls/pending/azure/azure_cis_v150_4_2_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_2_5.yaml @@ -1,13 +1,46 @@ +Description: Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'. ID: azure_cis_v150_4_2_5 -Title: "4.2.5 Ensure that Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners' is set for each SQL Server" -Description: "Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false'\n )\n then s.name || ' VA setting not configured to send email notifications to subscription admins and owners.'\n else s.name || ' VA setting configured to send email notifications to subscription admins and owners.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false' + ) + THEN s.name || ' VA setting not configured to send email notifications to subscription admins and owners.' + ELSE s.name || ' VA setting configured to send email notifications to subscription admins and owners.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.5 Ensure that Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners' is set for each SQL Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_3_2.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_3_2.yaml old mode 100755 new mode 100644 index c90f543f8..5425796ef --- a/compliance/controls/pending/azure/azure_cis_v150_4_3_2.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_3_2.yaml @@ -1,13 +1,30 @@ +Description: Enable log_checkpoints on PostgreSQL Servers. ID: azure_cis_v150_4_3_2 -Title: "4.3.2 Ensure Server Parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_checkpoints on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_checkpoints off.'\n else s.name || ' server parameter log_checkpoints on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_checkpoints'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_checkpoints off.' + ELSE s.name || ' server parameter log_checkpoints on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_checkpoints' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.2 Ensure Server Parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_3_3.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_3_3.yaml old mode 100755 new mode 100644 index ed945d4e2..d5117059a --- a/compliance/controls/pending/azure/azure_cis_v150_4_3_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_3_3.yaml @@ -1,13 +1,30 @@ +Description: Enable log_connections on PostgreSQL Servers. ID: azure_cis_v150_4_3_3 -Title: "4.3.3 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_connections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_connections off.'\n else s.name || ' server parameter log_connections on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_connections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_connections off.' + ELSE s.name || ' server parameter log_connections on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_connections' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.3 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_3_4.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_3_4.yaml old mode 100755 new mode 100644 index 5031ba942..0a53b01b5 --- a/compliance/controls/pending/azure/azure_cis_v150_4_3_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_3_4.yaml @@ -1,13 +1,30 @@ +Description: Enable log_disconnections on PostgreSQL Servers. ID: azure_cis_v150_4_3_4 -Title: "4.3.4 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_disconnections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then name || ' server parameter log_disconnections off.'\n else name || ' server parameter log_disconnections on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_disconnections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN name || ' server parameter log_disconnections off.' + ELSE name || ' server parameter log_disconnections on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_disconnections' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.4 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_3_5.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_3_5.yaml old mode 100755 new mode 100644 index cbfe0dc33..29ea089ed --- a/compliance/controls/pending/azure/azure_cis_v150_4_3_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_3_5.yaml @@ -1,13 +1,30 @@ +Description: Enable connection_throttling on PostgreSQL Servers. ID: azure_cis_v150_4_3_5 -Title: "4.3.5 Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable connection_throttling on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter connection_throttling off.'\n else s.name || ' server parameter connection_throttling on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'connection_throttling'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter connection_throttling off.' + ELSE s.name || ' server parameter connection_throttling on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'connection_throttling' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.5 Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_3_6.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_3_6.yaml old mode 100755 new mode 100644 index a3c02b7cc..f88e3f90f --- a/compliance/controls/pending/azure/azure_cis_v150_4_3_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_3_6.yaml @@ -1,13 +1,30 @@ +Description: Enable log_retention_days on PostgreSQL Servers. ID: azure_cis_v150_4_3_6 -Title: "4.3.6 Ensure Server Parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server" -Description: "Enable log_retention_days on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then 'alarm'\n else 'ok'\n end as status,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then s.name || ' log files are retained for 3 days or lesser.'\n else s.name || ' log files are retained for more than 3 days.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) as config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_retention_days'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::INTEGER <= 3 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::INTEGER <= 3 THEN s.name || ' log files are retained for 3 days or lesser.' + ELSE s.name || ' log files are retained for more than 3 days.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) AS config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_retention_days' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.6 Ensure Server Parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_4_4_4.yaml b/compliance/controls/pending/azure/azure_cis_v150_4_4_4.yaml old mode 100755 new mode 100644 index 16d7221ab..5d2c0fb70 --- a/compliance/controls/pending/azure/azure_cis_v150_4_4_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_4_4_4.yaml @@ -1,13 +1,30 @@ +Description: Set audit_log_enabled to include CONNECTION on MySQL Servers. ID: azure_cis_v150_4_4_4 -Title: "4.4.4 Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL Database Server" -Description: "Set audit_log_enabled to include CONNECTION on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') = 'connection' then 'ok'\n else 'alarm'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') = 'connection' then s.name || ' server parameter audit_log_events has connection set.'\n else s.name || ' server parameter audit_log_events connection not set.'\n end as reason\n \n \n \nfrom\n azure_mysql_server as s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'audit_log_events'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') = 'connection' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') = 'connection' THEN s.name || ' server parameter audit_log_events has connection set.' + ELSE s.name || ' server parameter audit_log_events connection not set.' + END AS reason + FROM + azure_mysql_server AS s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'audit_log_events' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.4 Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_5_1_4.yaml b/compliance/controls/pending/azure/azure_cis_v150_5_1_4.yaml old mode 100755 new mode 100644 index be3436476..7c64fe821 --- a/compliance/controls/pending/azure/azure_cis_v150_5_1_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_5_1_4.yaml @@ -1,13 +1,32 @@ +Description: Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK). ID: azure_cis_v150_5_1_4 -Title: "5.1.4 Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key" -Description: "Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault'\n then a.name || ' container insights-operational-logs encrypted with BYOK.'\n else a.name || ' container insights-operational-logs not encrypted with BYOK.'\n end as reason\n \n \n \nfrom\n azure_storage_container c,\n azure_storage_account a,\n azure_subscription sub\nwhere\n c.name = 'insights-operational-logs'\n and c.account_name = a.name\n and sub.subscription_id = a.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' + THEN a.name || ' container insights-operational-logs encrypted with BYOK.' + ELSE a.name || ' container insights-operational-logs not encrypted with BYOK.' + END AS reason + FROM + azure_storage_container c, + azure_storage_account a, + azure_subscription sub + WHERE + c.name = 'insights-operational-logs' + AND c.account_name = a.name + AND sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.4 Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_6_5.yaml b/compliance/controls/pending/azure/azure_cis_v150_6_5.yaml old mode 100755 new mode 100644 index bde2b1180..2c3633d80 --- a/compliance/controls/pending/azure/azure_cis_v150_6_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_6_5.yaml @@ -1,13 +1,32 @@ +Description: Network Security Group Flow Logs should be enabled and the retention period is set to greater than or equal to 90 days. ID: azure_cis_v150_6_5 -Title: "6.5 Ensure that Network Security Group Flow Log retention period is 'greater than 90 days'" -Description: "Network Security Group Flow Logs should be enabled and the retention period is set to greater than or equal to 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sg.id resource,\n case\n when fl.id is null or not fl.enabled or fl.retention_policy_days < 90 then 'alarm'\n else 'ok'\n end as status,\n case\n when fl.id is null or not fl.enabled\n then sg.name || ' flowlog not enabled.'\n when fl.retention_policy_days < 90\n then sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.'\n else sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.'\n end as reason\n \n \n \nfrom\n azure_network_security_group sg\n left join azure_network_watcher_flow_log fl on sg.id = fl.target_resource_id\n join azure_subscription sub on sub.subscription_id = sg.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sg.id AS resource, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled OR fl.retention_policy_days < 90 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled + THEN sg.name || ' flowlog not enabled.' + WHEN fl.retention_policy_days < 90 + THEN sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.' + ELSE sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.' + END AS reason + FROM + azure_network_security_group sg + LEFT JOIN + azure_network_watcher_flow_log fl ON sg.id = fl.target_resource_id + JOIN + azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.5 Ensure that Network Security Group Flow Log retention period is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_6_6.yaml b/compliance/controls/pending/azure/azure_cis_v150_6_6.yaml old mode 100755 new mode 100644 index cc27cb523..2c6389980 --- a/compliance/controls/pending/azure/azure_cis_v150_6_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_6_6.yaml @@ -1,13 +1,30 @@ +Description: Enable Network Watcher for Azure subscriptions. ID: azure_cis_v150_6_6 -Title: "6.6 Ensure that Network Watcher is 'Enabled'" -Description: "Enable Network Watcher for Azure subscriptions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n loc.id resource,\n case\n when watcher.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when watcher.id is null then 'Network watcher not enabled in ' || loc.name || '.'\n else 'Network watcher enabled in ' || loc.name || '.'\n end as reason,\n loc.name\n \n \n \nfrom\n azure_location loc\n left join azure_network_watcher watcher on watcher.region = loc.name\n join azure_subscription sub on sub.subscription_id = loc.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + loc.id AS resource, + CASE + WHEN watcher.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN watcher.id IS NULL THEN 'Network watcher not enabled in ' || loc.name || '.' + ELSE 'Network watcher enabled in ' || loc.name || '.' + END AS reason, + loc.name + FROM + azure_location loc + LEFT JOIN azure_network_watcher watcher + ON watcher.region = loc.name + JOIN azure_subscription sub + ON sub.subscription_id = loc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.6 Ensure that Network Watcher is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_8_7.yaml b/compliance/controls/pending/azure/azure_cis_v150_8_7.yaml old mode 100755 new mode 100644 index 579c13a2d..d90102f24 --- a/compliance/controls/pending/azure/azure_cis_v150_8_7.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_8_7.yaml @@ -1,13 +1,31 @@ +Description: Private endpoints will secure network traffic from Azure Key Vault to the resources requesting secrets and keys. ID: azure_cis_v150_8_7 -Title: "8.7 Ensure that Private Endpoints are Used for Azure Key Vault" -Description: "Private endpoints will secure network traffic from Azure Key Vault to the resources requesting secrets and keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n -- Having private_endpoint_connections will not permit vault to use the same.\n -- In case'defaultAction' = 'Allow', All Network including internet is allowed, which will not satisfy the private endpoint connection.\n -- Default All network will have not network_acls associated.\n when network_acls is null or network_acls ->> 'defaultAction' = 'Allow' then 'alarm'\n when private_endpoint_connections is null then 'info'\n when private_endpoint_connections @> '[{\"PrivateLinkServiceConnectionStateStatus\": \"Approved\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when network_acls is null or network_acls ->> 'defaultAction' = 'Allow' then a.name || ' using public networks.'\n when private_endpoint_connections is null then a.name || ' no private link exists.'\n when private_endpoint_connections @> '[{\"PrivateLinkServiceConnectionStateStatus\": \"Approved\"}]'\n then a.name || ' using private link.'\n else a.name || ' private link not enabled.'\n end as reason\n \n \n \nfrom\n azure_key_vault a,\n azure_subscription sub;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' = 'Allow' THEN 'alarm' + WHEN private_endpoint_connections IS NULL THEN 'info' + WHEN private_endpoint_connections @> '[{"PrivateLinkServiceConnectionStateStatus": "Approved"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' = 'Allow' THEN a.name || ' using public networks.' + WHEN private_endpoint_connections IS NULL THEN a.name || ' no private link exists.' + WHEN private_endpoint_connections @> '[{"PrivateLinkServiceConnectionStateStatus": "Approved"}]' + THEN a.name || ' using private link.' + ELSE a.name || ' private link not enabled.' + END AS reason + FROM + azure_key_vault a, + azure_subscription sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.7 Ensure that Private Endpoints are Used for Azure Key Vault \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_9_10.yaml b/compliance/controls/pending/azure/azure_cis_v150_9_10.yaml old mode 100755 new mode 100644 index d88fc997c..75c2be56f --- a/compliance/controls/pending/azure/azure_cis_v150_9_10.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_9_10.yaml @@ -1,13 +1,44 @@ +Description: By default, Azure Functions, Web and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions. ID: azure_cis_v150_9_10 -Title: "9.10 Ensure FTP deployments are disabled" -Description: "By default, Azure Functions, Web and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n fa.id as resource,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n \n \n from\n azure_app_service_function_app fa,\n azure_subscription sub\n where\n sub.subscription_id = fa.subscription_id\nunion\n select\n wa.id as resource,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n \n \n from\n azure_app_service_web_app as wa,\n azure_subscription as sub\n where\n sub.subscription_id = wa.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + fa.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason + FROM + azure_app_service_function_app fa, + azure_subscription sub + WHERE + sub.subscription_id = fa.subscription_id + UNION + SELECT + wa.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason + FROM + azure_app_service_web_app AS wa, + azure_subscription AS sub + WHERE + sub.subscription_id = wa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.10 Ensure FTP deployments are disabled \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v150_9_3.yaml b/compliance/controls/pending/azure/azure_cis_v150_9_3.yaml old mode 100755 new mode 100644 index 08abb1253..eebe5ed70 --- a/compliance/controls/pending/azure/azure_cis_v150_9_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v150_9_3.yaml @@ -1,13 +1,28 @@ +Description: The TLS(Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards, such as PCI DSS. ID: azure_cis_v150_9_3 -Title: "9.3 Ensure web app is using the latest version of TLS encryption" -Description: "The TLS(Transport Layer Security) protocol secures transmission of data over the internet using standard encryption technology. Encryption should be set with the latest version of TLS. App service allows TLS 1.2 by default, which is the recommended TLS level by industry standards, such as PCI DSS." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n app.id as resource,\n case\n when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'minTlsVersion' < '1.2' then name || ' not using the latest version of TLS encryption.'\n else name || ' using the latest version of TLS encryption.'\n end as reason\n \n \n \nfrom\n azure_app_service_web_app as app,\n azure_subscription as sub\nwhere\n sub.subscription_id = app.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + app.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'minTlsVersion' < '1.2' THEN name || ' not using the latest version of TLS encryption.' + ELSE name || ' using the latest version of TLS encryption.' + END AS reason + FROM + azure_app_service_web_app AS app, + azure_subscription AS sub + WHERE + sub.subscription_id = app.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.3 Ensure web app is using the latest version of TLS encryption \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_1_11.yaml b/compliance/controls/pending/azure/azure_cis_v200_1_11.yaml old mode 100755 new mode 100644 index 6144bfc9b..0d261f7e9 --- a/compliance/controls/pending/azure/azure_cis_v200_1_11.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_1_11.yaml @@ -1,17 +1,17 @@ +Description: Require administrators to provide consent for applications before use. ID: azure_cis_v200_1_11 -Title: "1.11 Ensure 'User consent for applications' is set to 'Do not allow user consent'" -Description: "Require administrators to provide consent for applications before use." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.11 Ensure 'User consent for applications' is set to 'Do not allow user consent' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_2_1_10.yaml b/compliance/controls/pending/azure/azure_cis_v200_2_1_10.yaml old mode 100755 new mode 100644 index f95c2d947..c547eb524 --- a/compliance/controls/pending/azure/azure_cis_v200_2_1_10.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_2_1_10.yaml @@ -1,13 +1,28 @@ +Description: Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v200_2_1_10 -Title: "2.1.10 Ensure That Microsoft Defender for Key Vault Is Set To 'On'" -Description: "Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Key Vaults.'\n else 'Azure Defender off for Key Vaults.'\n end as reason\n \n \nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'KeyVaults';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Key Vaults.' + ELSE 'Azure Defender off for Key Vaults.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN azure_subscription sub ON sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'KeyVaults'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.10 Ensure That Microsoft Defender for Key Vault Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_3_13.yaml b/compliance/controls/pending/azure/azure_cis_v200_3_13.yaml old mode 100755 new mode 100644 index 7f929d51c..bfaecd45c --- a/compliance/controls/pending/azure/azure_cis_v200_3_13.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_3_13.yaml @@ -1,13 +1,37 @@ +Description: 'The Storage Blob service provides scalable, cost-efficient object storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages.' ID: azure_cis_v200_3_13 -Title: "3.13 Ensure Storage logging is Enabled for Blob Service for 'Read', 'Write', and 'Delete' requests" -Description: "The Storage Blob service provides scalable, cost-efficient object storage in the cloud. Storage Logging happens server-side and allows details for both successful and failed requests to be recorded in the storage account. These logs allow users to see the details of read, write, and delete operations against the blobs. Storage Logging log entries contain the following information about individual requests: timing information such as start time, end-to-end latency, and server latency; authentication details; concurrency information; and the sizes of the request and response messages." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n case\n when not (sa.blob_service_logging ->> 'Read') :: boolean\n or not (sa.blob_service_logging ->> 'Write') :: boolean\n or not (sa.blob_service_logging ->> 'Delete') :: boolean then 'alarm'\n else 'ok'\n end as status,\n case\n when not (sa.blob_service_logging ->> 'Read') :: boolean\n or not (sa.blob_service_logging ->> 'Write') :: boolean\n or not (sa.blob_service_logging ->> 'Delete') :: boolean then name || ' blob service logging not enabled for ' ||\n concat_ws(', ',\n case when not (sa.blob_service_logging ->> 'Write') :: boolean then 'write' end,\n case when not (sa.blob_service_logging ->> 'Read') :: boolean then 'read' end,\n case when not (sa.blob_service_logging ->> 'Delete') :: boolean then 'delete' end\n ) || ' requests.'\n else name || ' blob service logging enabled for read, write, delete requests.'\n end as reason\n \n \n \nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sa.id AS resource, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN + OR NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN name || ' blob service logging not enabled for ' || + CONCAT_WS(', ', + CASE WHEN NOT (sa.blob_service_logging ->> 'Write')::BOOLEAN THEN 'write' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Read')::BOOLEAN THEN 'read' END, + CASE WHEN NOT (sa.blob_service_logging ->> 'Delete')::BOOLEAN THEN 'delete' END + ) || ' requests.' + ELSE name || ' blob service logging enabled for read, write, delete requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.13 Ensure Storage logging is Enabled for Blob Service for 'Read', 'Write', and 'Delete' requests \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_3_7.yaml b/compliance/controls/pending/azure/azure_cis_v200_3_7.yaml old mode 100755 new mode 100644 index e63a8b3c9..90858a70f --- a/compliance/controls/pending/azure/azure_cis_v200_3_7.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_3_7.yaml @@ -1,13 +1,30 @@ +Description: Disallowing public access for a storage account overrides the public access settings for individual containers in that storage account. ID: azure_cis_v200_3_7 -Title: "3.7 Ensure that 'Public access level' is disabled for storage accounts with blob containers" -Description: "Disallowing public access for a storage account overrides the public access settings for individual containers in that storage account." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n container.id as resource,\n case\n when not account.allow_blob_public_access and container.public_access = 'None' then 'ok'\n else 'alarm'\n end as status,\n case\n when not account.allow_blob_public_access and container.public_access = 'None'\n then account.name || ' container ' || container.name || ' doesn''t allow anonymous access.'\n else account.name || ' container ' || container.name || ' allows anonymous access.'\n end as reason\n \n \n \nfrom\n azure_storage_container container\n join azure_storage_account account on container.account_name = account.name\n join azure_subscription sub on sub.subscription_id = account.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + container.id AS resource, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' + THEN account.name || ' container ' || container.name || ' doesn''t allow anonymous access.' + ELSE account.name || ' container ' || container.name || ' allows anonymous access.' + END AS reason + FROM + azure_storage_container container + JOIN azure_storage_account account + ON container.account_name = account.name + JOIN azure_subscription sub + ON sub.subscription_id = account.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.7 Ensure that 'Public access level' is disabled for storage accounts with blob containers \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_1_1.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_1_1.yaml old mode 100755 new mode 100644 index 807fb2fb8..86757eaa9 --- a/compliance/controls/pending/azure/azure_cis_v200_4_1_1.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_1_1.yaml @@ -1,13 +1,29 @@ +Description: Enable auditing on SQL Servers. ID: azure_cis_v200_4_1_1 -Title: "4.1.1 Ensure that 'Auditing' is set to 'On'" -Description: "Enable auditing on SQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then name || ' auditing disabled.'\n else name || ' auditing enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN name || ' auditing disabled.' + ELSE name || ' auditing enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.1 Ensure that 'Auditing' is set to 'On' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_1_3.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_1_3.yaml old mode 100755 new mode 100644 index 0bb338d4a..a7bc72237 --- a/compliance/controls/pending/azure/azure_cis_v200_4_1_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_1_3.yaml @@ -1,13 +1,29 @@ +Description: Transparent Data Encryption (TDE) with Customer-managed key support provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. ID: azure_cis_v200_4_1_3 -Title: "4.1.3 Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted with Customer-managed key" -Description: "Transparent Data Encryption (TDE) with Customer-managed key support provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when encryption ->> 'kind' = 'servicemanaged' then 'alarm'\n else 'ok'\n end as status,\n case\n when encryption ->> 'kind' = 'servicemanaged' then s.name || ' TDE protector not encrypted with CMK.'\n else s.name || ' TDE protector encrypted with CMK.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(encryption_protector) encryption,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN s.name || ' TDE protector not encrypted with CMK.' + ELSE s.name || ' TDE protector encrypted with CMK.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(encryption_protector) encryption, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.3 Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted with Customer-managed key \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_1_5.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_1_5.yaml old mode 100755 new mode 100644 index abde4554b..e27f8d6b9 --- a/compliance/controls/pending/azure/azure_cis_v200_4_1_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_1_5.yaml @@ -1,13 +1,31 @@ +Description: Enable Transparent Data Encryption on every SQL server. ID: azure_cis_v200_4_1_5 -Title: "4.1.5 Ensure that 'Data encryption' is set to 'On' on a SQL Database" -Description: "Enable Transparent Data Encryption on every SQL server." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.database_id resource,\n case\n when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then 'ok'\n else 'alarm'\n end as status,\n case\n when transparent_data_encryption ->> 'status' = 'Enabled' or transparent_data_encryption ->> 'state' = 'Enabled' then s.title || ' transparent data encryption enabled.'\n else s.title || ' transparent data encryption disabled.'\n end as reason\n \n \n \nfrom\n azure_sql_database as s,\n azure_subscription as sub\nwhere\n sub.subscription_id = s.subscription_id\n and s.name <> 'master';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.database_id resource, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' + OR transparent_data_encryption ->> 'state' = 'Enabled' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN transparent_data_encryption ->> 'status' = 'Enabled' + OR transparent_data_encryption ->> 'state' = 'Enabled' THEN s.title || ' transparent data encryption enabled.' + ELSE s.title || ' transparent data encryption disabled.' + END AS reason + FROM + azure_sql_database AS s, + azure_subscription AS sub + WHERE + sub.subscription_id = s.subscription_id + AND s.name <> 'master'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.5 Ensure that 'Data encryption' is set to 'On' on a SQL Database \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_1_6.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_1_6.yaml old mode 100755 new mode 100644 index b3eeb0582..5106d1cc1 --- a/compliance/controls/pending/azure/azure_cis_v200_4_1_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_1_6.yaml @@ -1,13 +1,31 @@ +Description: SQL Server Audit Retention should be configured to be greater than 90 days. ID: azure_cis_v200_4_1_6 -Title: "4.1.6 Ensure that 'Auditing' Retention is 'greater than 90 days'" -Description: "SQL Server Audit Retention should be configured to be greater than 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then 'ok'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then name || ' audit retention set to unlimited days.'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then name || ' audit retention greater than 90 days.'\n else name || ' audit retention less than 90 days.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN 'ok' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN name || ' audit retention set to unlimited days.' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN name || ' audit retention greater than 90 days.' + ELSE name || ' audit retention less than 90 days.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.6 Ensure that 'Auditing' Retention is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_2_1.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_2_1.yaml old mode 100755 new mode 100644 index ca6b8216a..21196d095 --- a/compliance/controls/pending/azure/azure_cis_v200_4_2_1.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_2_1.yaml @@ -1,13 +1,29 @@ +Description: Enable "Azure Defender for SQL" on critical SQL Servers. ID: azure_cis_v200_4_2_1 -Title: "4.2.1 Ensure that Microsoft Defender for SQL is set to 'On' for critical SQL Servers" -Description: "Enable \\\"Azure Defender for SQL\\\" on critical SQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then s.name || ' Azure defender disabled.'\n else s.name || ' Azure defender enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN s.name || ' Azure defender disabled.' + ELSE s.name || ' Azure defender enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.1 Ensure that Microsoft Defender for SQL is set to 'On' for critical SQL Servers \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_2_2.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_2_2.yaml old mode 100755 new mode 100644 index bd8b56a67..a8dbf000a --- a/compliance/controls/pending/azure/azure_cis_v200_4_2_2.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_2_2.yaml @@ -1,13 +1,30 @@ +Description: Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases. ID: azure_cis_v200_4_2_2 -Title: "4.2.2 Ensure that Vulnerability Assessment (VA) is enabled on a SQL server by setting a Storage Account" -Description: "Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when security -> 'properties' ->> 'state' = 'Disabled' then s.name || ' VA setting disabled.'\n else s.name || ' VA setting enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN security -> 'properties' ->> 'state' = 'Disabled' THEN s.name || ' VA setting disabled.' + ELSE s.name || ' VA setting enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.2 Ensure that Vulnerability Assessment (VA) is enabled on a SQL server by setting a Storage Account \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_2_3.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_2_3.yaml old mode 100755 new mode 100644 index 7d9cb51ed..a56af4909 --- a/compliance/controls/pending/azure/azure_cis_v200_4_2_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_2_3.yaml @@ -1,13 +1,46 @@ +Description: Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases. ID: azure_cis_v200_4_2_3 -Title: "4.2.3 Ensure that Vulnerability Assessment (VA) setting 'Periodic recurring scans' is set to 'on' for each SQL server" -Description: "Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false'\n )\n then s.name || ' VA setting periodic recurring scans disabled.'\n else s.name || ' VA setting periodic recurring scans enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'isEnabled' = 'false' + ) + THEN s.name || ' VA setting periodic recurring scans disabled.' + ELSE s.name || ' VA setting periodic recurring scans enabled.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.3 Ensure that Vulnerability Assessment (VA) setting 'Periodic recurring scans' is set to 'on' for each SQL server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_2_4.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_2_4.yaml old mode 100755 new mode 100644 index ffdf065f6..69f5bf842 --- a/compliance/controls/pending/azure/azure_cis_v200_4_2_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_2_4.yaml @@ -1,13 +1,44 @@ +Description: Configure 'Send scan reports to' with email ids of concerned data owners/stakeholders for a critical SQL servers. ID: azure_cis_v200_4_2_4 -Title: "4.2.4 Ensure that Vulnerability Assessment (VA) setting 'Send scan reports to' is configured for a SQL server" -Description: "Configure 'Send scan reports to' with email ids of concerned data owners/stakeholders for a critical SQL servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]'\n )\n then s.name || ' VA scan reports and alerts not configured send email.'\n else s.name || ' VA scan reports and alerts configured to send email.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emails' = '[]' + ) + THEN s.name || ' VA scan reports and alerts not configured, send email.' + ELSE s.name || ' VA scan reports and alerts configured to send email.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.4 Ensure that Vulnerability Assessment (VA) setting 'Send scan reports to' is configured for a SQL server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_2_5.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_2_5.yaml old mode 100755 new mode 100644 index da2f2a3d3..add041b7a --- a/compliance/controls/pending/azure/azure_cis_v200_4_2_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_2_5.yaml @@ -1,13 +1,46 @@ +Description: Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'. ID: azure_cis_v200_4_2_5 -Title: "4.2.5 Ensure that Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners' is set for each SQL Server" -Description: "Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false'\n )\n then 'alarm'\n else 'ok'\n end as status,\n case\n when\n security -> 'properties' ->> 'state' = 'Disabled'\n or\n (\n security -> 'properties' ->> 'state' = 'Enabled'\n and assessment -> 'properties' ->> 'storageContainerPath' is not null\n and assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false'\n )\n then s.name || ' VA setting not configured to send email notifications to subscription admins and owners.'\n else s.name || ' VA setting configured to send email notifications to subscription admins and owners.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_security_alert_policy) security,\n jsonb_array_elements(server_vulnerability_assessment) assessment,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false' + ) + THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN + security -> 'properties' ->> 'state' = 'Disabled' + OR + ( + security -> 'properties' ->> 'state' = 'Enabled' + AND assessment -> 'properties' ->> 'storageContainerPath' IS NOT NULL + AND assessment -> 'properties' -> 'recurringScans' ->> 'emailSubscriptionAdmins' = 'false' + ) + THEN s.name || ' VA setting not configured to send email notifications to subscription admins and owners.' + ELSE s.name || ' VA setting configured to send email notifications to subscription admins and owners.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_security_alert_policy) security, + jsonb_array_elements(server_vulnerability_assessment) assessment, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.2.5 Ensure that Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners' is set for each SQL Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_3_2.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_3_2.yaml old mode 100755 new mode 100644 index e082af83c..e3ee12b1b --- a/compliance/controls/pending/azure/azure_cis_v200_4_3_2.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_3_2.yaml @@ -1,13 +1,30 @@ +Description: Enable log_checkpoints on PostgreSQL Servers. ID: azure_cis_v200_4_3_2 -Title: "4.3.2 Ensure Server Parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_checkpoints on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_checkpoints off.'\n else s.name || ' server parameter log_checkpoints on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_checkpoints'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_checkpoints off.' + ELSE s.name || ' server parameter log_checkpoints on.' + END AS reason + FROM + azure_postgresql_server s, + JSONB_ARRAY_ELEMENTS(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_checkpoints' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.2 Ensure Server Parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_3_3.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_3_3.yaml old mode 100755 new mode 100644 index 0d4ca9e44..95de67c38 --- a/compliance/controls/pending/azure/azure_cis_v200_4_3_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_3_3.yaml @@ -1,13 +1,30 @@ +Description: Enable log_connections on PostgreSQL Servers. ID: azure_cis_v200_4_3_3 -Title: "4.3.3 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_connections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_connections off.'\n else s.name || ' server parameter log_connections on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_connections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_connections off.' + ELSE s.name || ' server parameter log_connections on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_connections' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.3 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_3_4.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_3_4.yaml old mode 100755 new mode 100644 index 8cd88a0d7..61ad9b201 --- a/compliance/controls/pending/azure/azure_cis_v200_4_3_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_3_4.yaml @@ -1,13 +1,30 @@ +Description: Enable log_disconnections on PostgreSQL Servers. ID: azure_cis_v200_4_3_4 -Title: "4.3.4 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_disconnections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then name || ' server parameter log_disconnections off.'\n else name || ' server parameter log_disconnections on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_disconnections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN name || ' server parameter log_disconnections off.' + ELSE name || ' server parameter log_disconnections on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_disconnections' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.4 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_3_6.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_3_6.yaml old mode 100755 new mode 100644 index 16c338a3e..16ed8152f --- a/compliance/controls/pending/azure/azure_cis_v200_4_3_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_3_6.yaml @@ -1,13 +1,30 @@ +Description: Ensure log_retention_days on PostgreSQL Servers is set to an appropriate value. ID: azure_cis_v200_4_3_6 -Title: "4.3.6 Ensure Server Parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server" -Description: "Ensure log_retention_days on PostgreSQL Servers is set to an appropriate value." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then 'alarm'\n else 'ok'\n end as status,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then s.name || ' log files are retained for 3 days or lesser.'\n else s.name || ' log files are retained for more than 3 days.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) as config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_retention_days'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 THEN s.name || ' log files are retained for 3 days or lesser.' + ELSE s.name || ' log files are retained for more than 3 days.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) AS config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_retention_days' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.6 Ensure Server Parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_4_3.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_4_3.yaml old mode 100755 new mode 100644 index 8c9f7693a..9166475ca --- a/compliance/controls/pending/azure/azure_cis_v200_4_4_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_4_3.yaml @@ -1,13 +1,30 @@ +Description: Enable audit_log_enabled on MySQL Servers. ID: azure_cis_v200_4_4_3 -Title: "4.4.3 Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL Database Server" -Description: "Enable audit_log_enabled on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter audit_log_enabled off.'\n else s.name || ' server parameter audit_log_enabled on.'\n end as reason\n \n \n \nfrom\n azure_mysql_server as s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'audit_log_enabled'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter audit_log_enabled off.' + ELSE s.name || ' server parameter audit_log_enabled on.' + END AS reason + FROM + azure_mysql_server AS s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'audit_log_enabled' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.3 Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_4_4_4.yaml b/compliance/controls/pending/azure/azure_cis_v200_4_4_4.yaml old mode 100755 new mode 100644 index a136ed933..6e6503e53 --- a/compliance/controls/pending/azure/azure_cis_v200_4_4_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_4_4_4.yaml @@ -1,13 +1,30 @@ +Description: Set audit_log_enabled to include CONNECTION on MySQL Servers. ID: azure_cis_v200_4_4_4 -Title: "4.4.4 Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL Database Server" -Description: "Set audit_log_enabled to include CONNECTION on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') = 'connection' then 'ok'\n else 'alarm'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') = 'connection' then s.name || ' server parameter audit_log_events has connection set.'\n else s.name || ' server parameter audit_log_events connection not set.'\n end as reason\n \n \n \nfrom\n azure_mysql_server as s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'audit_log_events'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') = 'connection' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') = 'connection' THEN s.name || ' server parameter audit_log_events has connection set.' + ELSE s.name || ' server parameter audit_log_events connection not set.' + END AS reason + FROM + azure_mysql_server AS s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'audit_log_events' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.4 Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_5_1_4.yaml b/compliance/controls/pending/azure/azure_cis_v200_5_1_4.yaml old mode 100755 new mode 100644 index c9f5e9d23..9445117e1 --- a/compliance/controls/pending/azure/azure_cis_v200_5_1_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_5_1_4.yaml @@ -1,13 +1,32 @@ +Description: Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK). ID: azure_cis_v200_5_1_4 -Title: "5.1.4 Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key" -Description: "Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault'\n then a.name || ' container insights-activity-logs encrypted with BYOK.'\n else a.name || ' container insights-activity-logs not encrypted with BYOK.'\n end as reason\n \n \n \nfrom\n azure_storage_container c,\n azure_storage_account a,\n azure_subscription sub\nwhere\n c.name = 'insights-activity-logs'\n and c.account_name = a.name\n and sub.subscription_id = a.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' + THEN a.name || ' container insights-activity-logs encrypted with BYOK.' + ELSE a.name || ' container insights-activity-logs not encrypted with BYOK.' + END AS reason + FROM + azure_storage_container c, + azure_storage_account a, + azure_subscription sub + WHERE + c.name = 'insights-activity-logs' + AND c.account_name = a.name + AND sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 5.1.4 Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_6_5.yaml b/compliance/controls/pending/azure/azure_cis_v200_6_5.yaml old mode 100755 new mode 100644 index 8680e9ccb..e60d245a6 --- a/compliance/controls/pending/azure/azure_cis_v200_6_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_6_5.yaml @@ -1,13 +1,32 @@ +Description: Network Security Group Flow Logs should be enabled and the retention period set to greater than or equal to 90 days. ID: azure_cis_v200_6_5 -Title: "6.5 Ensure that Network Security Group Flow Log retention period is 'greater than 90 days'" -Description: "Network Security Group Flow Logs should be enabled and the retention period set to greater than or equal to 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sg.id resource,\n case\n when fl.id is null or not fl.enabled or fl.retention_policy_days < 90 then 'alarm'\n else 'ok'\n end as status,\n case\n when fl.id is null or not fl.enabled\n then sg.name || ' flowlog not enabled.'\n when fl.retention_policy_days < 90\n then sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.'\n else sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.'\n end as reason\n \n \n \nfrom\n azure_network_security_group sg\n left join azure_network_watcher_flow_log fl on sg.id = fl.target_resource_id\n join azure_subscription sub on sub.subscription_id = sg.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sg.id AS resource, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled OR fl.retention_policy_days < 90 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled + THEN sg.name || ' flowlog not enabled.' + WHEN fl.retention_policy_days < 90 + THEN sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.' + ELSE sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.' + END AS reason + FROM + azure_network_security_group sg + LEFT JOIN + azure_network_watcher_flow_log fl ON sg.id = fl.target_resource_id + JOIN + azure_subscription sub ON sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.5 Ensure that Network Security Group Flow Log retention period is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_6_6.yaml b/compliance/controls/pending/azure/azure_cis_v200_6_6.yaml old mode 100755 new mode 100644 index f8b9aacbd..5252ed6dc --- a/compliance/controls/pending/azure/azure_cis_v200_6_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_6_6.yaml @@ -1,13 +1,28 @@ +Description: Enable Network Watcher for Azure subscriptions. ID: azure_cis_v200_6_6 -Title: "6.6 Ensure that Network Watcher is 'Enabled'" -Description: "Enable Network Watcher for Azure subscriptions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n loc.id resource,\n case\n when watcher.id is null then 'alarm'\n else 'ok'\n end as status,\n case\n when watcher.id is null then 'Network watcher not enabled in ' || loc.name || '.'\n else 'Network watcher enabled in ' || loc.name || '.'\n end as reason,\n loc.name\n \n \n \nfrom\n azure_location loc\n left join azure_network_watcher watcher on watcher.region = loc.name\n join azure_subscription sub on sub.subscription_id = loc.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + loc.id AS resource, + CASE + WHEN watcher.id IS NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN watcher.id IS NULL THEN 'Network watcher not enabled in ' || loc.name || '.' + ELSE 'Network watcher enabled in ' || loc.name || '.' + END AS reason, + loc.name + FROM + azure_location loc + LEFT JOIN azure_network_watcher watcher ON watcher.region = loc.name + JOIN azure_subscription sub ON sub.subscription_id = loc.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.6 Ensure that Network Watcher is 'Enabled' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_8_7.yaml b/compliance/controls/pending/azure/azure_cis_v200_8_7.yaml old mode 100755 new mode 100644 index 5c67c084e..aa62f3f2c --- a/compliance/controls/pending/azure/azure_cis_v200_8_7.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_8_7.yaml @@ -1,13 +1,31 @@ +Description: Private endpoints will secure network traffic from Azure Key Vault to the resources requesting secrets and keys. ID: azure_cis_v200_8_7 -Title: "8.7 Ensure that Private Endpoints are Used for Azure Key Vault" -Description: "Private endpoints will secure network traffic from Azure Key Vault to the resources requesting secrets and keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n -- Having private_endpoint_connections will not permit vault to use the same.\n -- In case'defaultAction' = 'Allow', All Network including internet is allowed, which will not satisfy the private endpoint connection.\n -- Default All network will have not network_acls associated.\n when network_acls is null or network_acls ->> 'defaultAction' = 'Allow' then 'alarm'\n when private_endpoint_connections is null then 'info'\n when private_endpoint_connections @> '[{\"PrivateLinkServiceConnectionStateStatus\": \"Approved\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when network_acls is null or network_acls ->> 'defaultAction' = 'Allow' then a.name || ' using public networks.'\n when private_endpoint_connections is null then a.name || ' no private link exists.'\n when private_endpoint_connections @> '[{\"PrivateLinkServiceConnectionStateStatus\": \"Approved\"}]'\n then a.name || ' using private link.'\n else a.name || ' private link not enabled.'\n end as reason\n \n \n \nfrom\n azure_key_vault a,\n azure_subscription sub;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' = 'Allow' THEN 'alarm' + WHEN private_endpoint_connections IS NULL THEN 'info' + WHEN private_endpoint_connections @> '[{"PrivateLinkServiceConnectionStateStatus": "Approved"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' = 'Allow' THEN a.name || ' using public networks.' + WHEN private_endpoint_connections IS NULL THEN a.name || ' no private link exists.' + WHEN private_endpoint_connections @> '[{"PrivateLinkServiceConnectionStateStatus": "Approved"}]' + THEN a.name || ' using private link.' + ELSE a.name || ' private link not enabled.' + END AS reason + FROM + azure_key_vault a, + azure_subscription sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.7 Ensure that Private Endpoints are Used for Azure Key Vault \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v200_9_10.yaml b/compliance/controls/pending/azure/azure_cis_v200_9_10.yaml old mode 100755 new mode 100644 index f244eec06..a9dc46b2f --- a/compliance/controls/pending/azure/azure_cis_v200_9_10.yaml +++ b/compliance/controls/pending/azure/azure_cis_v200_9_10.yaml @@ -1,13 +1,44 @@ +Description: By default, Azure Functions, Web, and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions. ID: azure_cis_v200_9_10 -Title: "9.10 Ensure FTP deployments are Disabled" -Description: "By default, Azure Functions, Web, and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n fa.id as resource,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n \n \n from\n azure_app_service_function_app fa,\n azure_subscription sub\n where\n sub.subscription_id = fa.subscription_id\nunion\n select\n wa.id as resource,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n \n \n from\n azure_app_service_web_app as wa,\n azure_subscription as sub\n where\n sub.subscription_id = wa.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + fa.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason + FROM + azure_app_service_function_app fa, + azure_subscription sub + WHERE + sub.subscription_id = fa.subscription_id + UNION + SELECT + wa.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason + FROM + azure_app_service_web_app AS wa, + azure_subscription AS sub + WHERE + sub.subscription_id = wa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.10 Ensure FTP deployments are Disabled \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_1_3.yaml b/compliance/controls/pending/azure/azure_cis_v210_1_3.yaml old mode 100755 new mode 100644 index f9e83565f..05ee3ef63 --- a/compliance/controls/pending/azure/azure_cis_v210_1_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_1_3.yaml @@ -1,17 +1,17 @@ +Description: Require administrators or appropriately delegated users to create new tenants. ID: azure_cis_v210_1_3 -Title: "1.3 Ensure that 'Restrict non-admin users from creating tenants' is set to 'Yes'" -Description: "Require administrators or appropriately delegated users to create new tenants." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: | - select - 'active_directory' as resource, - 'info' as status, - 'Manual verification required.' as reason; - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + 'active_directory' AS resource, + 'info' AS status, + 'Manual verification required.' AS reason; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 1.3 Ensure that 'Restrict non-admin users from creating tenants' is set to 'Yes' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_2_1_9.yaml b/compliance/controls/pending/azure/azure_cis_v210_2_1_9.yaml old mode 100755 new mode 100644 index 0a85eeced..87630c388 --- a/compliance/controls/pending/azure/azure_cis_v210_2_1_9.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_2_1_9.yaml @@ -1,13 +1,31 @@ +Description: Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. ID: azure_cis_v210_2_1_9 -Title: "2.1.9 Ensure That Microsoft Defender for Key Vault Is Set To 'On'" -Description: "Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sub_pricing.id as resource,\n case\n when pricing_tier = 'Standard' then 'ok'\n else 'alarm'\n end as status,\n case\n when pricing_tier = 'Standard' then 'Azure Defender on for Key Vaults.'\n else 'Azure Defender off for Key Vaults.'\n end as reason\n \n \nfrom\n azure_security_center_subscription_pricing sub_pricing\n right join azure_subscription sub on sub_pricing.subscription_id = sub.subscription_id\nwhere\n name = 'KeyVaults';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sub_pricing.id AS resource, + CASE + WHEN pricing_tier = 'Standard' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN pricing_tier = 'Standard' THEN 'Azure Defender on for Key Vaults.' + ELSE 'Azure Defender off for Key Vaults.' + END AS reason + FROM + azure_security_center_subscription_pricing sub_pricing + RIGHT JOIN + azure_subscription sub + ON + sub_pricing.subscription_id = sub.subscription_id + WHERE + name = 'KeyVaults'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 2.1.9 Ensure That Microsoft Defender for Key Vault Is Set To 'On' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_3_17.yaml b/compliance/controls/pending/azure/azure_cis_v210_3_17.yaml old mode 100755 new mode 100644 index ca486ff12..6191d4bae --- a/compliance/controls/pending/azure/azure_cis_v210_3_17.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_3_17.yaml @@ -1,13 +1,31 @@ +Description: The Azure Storage setting 'Allow Blob Anonymous Access' (aka 'allowBlobPublicAccess') controls whether anonymous access is allowed for blob data in a storage account. When this property is set to True, it enables public read access to blob data, which can be convenient for sharing data but may carry security risks. When set to False, it disallows public access to blob data, providing a more secure storage environment. ID: azure_cis_v210_3_17 -Title: "3.17 Ensure that `Allow Blob Anonymous Access` is set to `Disabled`" -Description: "The Azure Storage setting 'Allow Blob Anonymous Access' (aka 'allowBlobPublicAccess') controls whether anonymous access is allowed for blob data in a storage account. When this property is set to True, it enables public read access to blob data, which can be convenient for sharing data but may carry security risks. When set to False, it disallows public access to blob data, providing a more secure storage environment." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n container.id as resource,\n case\n when not account.allow_blob_public_access and container.public_access = 'None' then 'ok'\n else 'alarm'\n end as status,\n case\n when not account.allow_blob_public_access and container.public_access = 'None'\n then account.name || ' container ' || container.name || ' doesn''t allow anonymous access.'\n else account.name || ' container ' || container.name || ' allows anonymous access.'\n end as reason\n \n \n \nfrom\n azure_storage_container container\n join azure_storage_account account on container.account_name = account.name\n join azure_subscription sub on sub.subscription_id = account.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + container.id AS resource, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN NOT account.allow_blob_public_access AND container.public_access = 'None' THEN + account.name || ' container ' || container.name || ' doesn''t allow anonymous access.' + ELSE + account.name || ' container ' || container.name || ' allows anonymous access.' + END AS reason + FROM + azure_storage_container container + JOIN + azure_storage_account account ON container.account_name = account.name + JOIN + azure_subscription sub ON sub.subscription_id = account.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 3.17 Ensure that `Allow Blob Anonymous Access` is set to `Disabled` \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_4_1_1.yaml b/compliance/controls/pending/azure/azure_cis_v210_4_1_1.yaml old mode 100755 new mode 100644 index e3efc38a9..deebee921 --- a/compliance/controls/pending/azure/azure_cis_v210_4_1_1.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_4_1_1.yaml @@ -1,13 +1,29 @@ +Description: Enable auditing on SQL Servers. ID: azure_cis_v210_4_1_1 -Title: "4.1.1 Ensure that 'Auditing' is set to 'On'" -Description: "Enable auditing on SQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then 'alarm'\n else 'ok'\n end as status,\n case\n when audit -> 'properties' ->> 'state' = 'Disabled' then name || ' auditing disabled.'\n else name || ' auditing enabled.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN audit -> 'properties' ->> 'state' = 'Disabled' THEN name || ' auditing disabled.' + ELSE name || ' auditing enabled.' + END AS reason + FROM + azure_sql_server s, + JSONB_ARRAY_ELEMENTS(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.1 Ensure that 'Auditing' is set to 'On' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_4_1_3.yaml b/compliance/controls/pending/azure/azure_cis_v210_4_1_3.yaml old mode 100755 new mode 100644 index 4f5aa441c..6bbd3744b --- a/compliance/controls/pending/azure/azure_cis_v210_4_1_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_4_1_3.yaml @@ -1,13 +1,29 @@ +Description: Transparent Data Encryption (TDE) with Customer-managed key support provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. ID: azure_cis_v210_4_1_3 -Title: "4.1.3 Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted with Customer-managed key" -Description: "Transparent Data Encryption (TDE) with Customer-managed key support provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when encryption ->> 'kind' = 'servicemanaged' then 'alarm'\n else 'ok'\n end as status,\n case\n when encryption ->> 'kind' = 'servicemanaged' then s.name || ' TDE protector not encrypted with CMK.'\n else s.name || ' TDE protector encrypted with CMK.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(encryption_protector) encryption,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN encryption ->> 'kind' = 'servicemanaged' THEN s.name || ' TDE protector not encrypted with CMK.' + ELSE s.name || ' TDE protector encrypted with CMK.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(encryption_protector) encryption, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.3 Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted with Customer-managed key \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_4_1_6.yaml b/compliance/controls/pending/azure/azure_cis_v210_4_1_6.yaml old mode 100755 new mode 100644 index 44f93da6c..47d214fce --- a/compliance/controls/pending/azure/azure_cis_v210_4_1_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_4_1_6.yaml @@ -1,13 +1,31 @@ +Description: SQL Server Audit Retention should be configured to be greater than 90 days. ID: azure_cis_v210_4_1_6 -Title: "4.1.6 Ensure that 'Auditing' Retention is 'greater than 90 days'" -Description: "SQL Server Audit Retention should be configured to be greater than 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then 'ok'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then 'ok'\n else 'alarm'\n end as status,\n case\n when (audit -> 'properties' ->> 'retentionDays')::integer = 0 then name || ' audit retention set to unlimited days.'\n when (audit -> 'properties' ->> 'retentionDays')::integer >= 90 then name || ' audit retention greater than 90 days.'\n else name || ' audit retention less than 90 days.'\n end as reason\n \n \n \nfrom\n azure_sql_server s,\n jsonb_array_elements(server_audit_policy) audit,\n azure_subscription sub\nwhere\n sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN 'ok' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN (audit -> 'properties' ->> 'retentionDays')::integer = 0 THEN name || ' audit retention set to unlimited days.' + WHEN (audit -> 'properties' ->> 'retentionDays')::integer >= 90 THEN name || ' audit retention greater than 90 days.' + ELSE name || ' audit retention less than 90 days.' + END AS reason + FROM + azure_sql_server s, + jsonb_array_elements(server_audit_policy) audit, + azure_subscription sub + WHERE + sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.1.6 Ensure that 'Auditing' Retention is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_4_3_2.yaml b/compliance/controls/pending/azure/azure_cis_v210_4_3_2.yaml old mode 100755 new mode 100644 index 1d9bdeb75..9e8fd0890 --- a/compliance/controls/pending/azure/azure_cis_v210_4_3_2.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_4_3_2.yaml @@ -1,13 +1,30 @@ +Description: Enable log_checkpoints on PostgreSQL Servers. ID: azure_cis_v210_4_3_2 -Title: "4.3.2 Ensure Server Parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_checkpoints on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_checkpoints off.'\n else s.name || ' server parameter log_checkpoints on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_checkpoints'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_checkpoints off.' + ELSE s.name || ' server parameter log_checkpoints on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_checkpoints' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.2 Ensure Server Parameter 'log_checkpoints' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_4_3_3.yaml b/compliance/controls/pending/azure/azure_cis_v210_4_3_3.yaml old mode 100755 new mode 100644 index fbba00108..2f72971ab --- a/compliance/controls/pending/azure/azure_cis_v210_4_3_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_4_3_3.yaml @@ -1,13 +1,30 @@ +Description: Enable log_connections on PostgreSQL Servers. ID: azure_cis_v210_4_3_3 -Title: "4.3.3 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_connections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter log_connections off.'\n else s.name || ' server parameter log_connections on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_connections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter log_connections off.' + ELSE s.name || ' server parameter log_connections on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_connections' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.3 Ensure server parameter 'log_connections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_4_3_4.yaml b/compliance/controls/pending/azure/azure_cis_v210_4_3_4.yaml old mode 100755 new mode 100644 index 7ac1740aa..5d659f1cd --- a/compliance/controls/pending/azure/azure_cis_v210_4_3_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_4_3_4.yaml @@ -1,13 +1,30 @@ +Description: Enable log_disconnections on PostgreSQL Servers. ID: azure_cis_v210_4_3_4 -Title: "4.3.4 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_disconnections on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then name || ' server parameter log_disconnections off.'\n else name || ' server parameter log_disconnections on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_disconnections'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN name || ' server parameter log_disconnections off.' + ELSE name || ' server parameter log_disconnections on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_disconnections' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.4 Ensure server parameter 'log_disconnections' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_4_3_5.yaml b/compliance/controls/pending/azure/azure_cis_v210_4_3_5.yaml old mode 100755 new mode 100644 index 4d4a7d512..a6c360983 --- a/compliance/controls/pending/azure/azure_cis_v210_4_3_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_4_3_5.yaml @@ -1,13 +1,30 @@ +Description: Enable connection_throttling on PostgreSQL Servers. ID: azure_cis_v210_4_3_5 -Title: "4.3.5 Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable connection_throttling on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter connection_throttling off.'\n else s.name || ' server parameter connection_throttling on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'connection_throttling'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN s.name || ' server parameter connection_throttling off.' + ELSE s.name || ' server parameter connection_throttling on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'connection_throttling' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.5 Ensure server parameter 'connection_throttling' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_4_3_6.yaml b/compliance/controls/pending/azure/azure_cis_v210_4_3_6.yaml old mode 100755 new mode 100644 index 55b9213fa..5c38d88d6 --- a/compliance/controls/pending/azure/azure_cis_v210_4_3_6.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_4_3_6.yaml @@ -1,13 +1,30 @@ +Description: Ensure log_retention_days on PostgreSQL Servers is set to an appropriate value. ID: azure_cis_v210_4_3_6 -Title: "4.3.6 Ensure Server Parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server" -Description: "Ensure log_retention_days on PostgreSQL Servers is set to an appropriate value." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then 'alarm'\n else 'ok'\n end as status,\n case\n when (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 then s.name || ' log files are retained for 3 days or lesser.'\n else s.name || ' log files are retained for more than 3 days.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) as config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_retention_days'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN (config -> 'ConfigurationProperties' ->> 'value')::integer <= 3 THEN s.name || ' log files are retained for 3 days or lesser.' + ELSE s.name || ' log files are retained for more than 3 days.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) AS config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_retention_days' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.3.6 Ensure Server Parameter 'log_retention_days' is greater than 3 days for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_4_4_3.yaml b/compliance/controls/pending/azure/azure_cis_v210_4_4_3.yaml old mode 100755 new mode 100644 index 8ef15b583..6fc0a50cf --- a/compliance/controls/pending/azure/azure_cis_v210_4_4_3.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_4_4_3.yaml @@ -1,13 +1,31 @@ +Description: Enable audit_log_enabled on MySQL Servers. ID: azure_cis_v210_4_4_3 -Title: "4.4.3 Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL Database Server" -Description: "Enable audit_log_enabled on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then s.name || ' server parameter audit_log_enabled off.'\n else s.name || ' server parameter audit_log_enabled on.'\n end as reason\n \n \n \nfrom\n azure_mysql_server as s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'audit_log_enabled'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' + THEN s.name || ' server parameter audit_log_enabled off.' + ELSE s.name || ' server parameter audit_log_enabled on.' + END AS reason + FROM + azure_mysql_server AS s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'audit_log_enabled' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.3 Ensure server parameter 'audit_log_enabled' is set to 'ON' for MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_4_4_4.yaml b/compliance/controls/pending/azure/azure_cis_v210_4_4_4.yaml old mode 100755 new mode 100644 index 9cf8382f4..4c3bdd6c5 --- a/compliance/controls/pending/azure/azure_cis_v210_4_4_4.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_4_4_4.yaml @@ -1,13 +1,30 @@ +Description: Set audit_log_enabled to include CONNECTION on MySQL Servers. ID: azure_cis_v210_4_4_4 -Title: "4.4.4 Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL Database Server" -Description: "Set audit_log_enabled to include CONNECTION on MySQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') = 'connection' then 'ok'\n else 'alarm'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') = 'connection' then s.name || ' server parameter audit_log_events has connection set.'\n else s.name || ' server parameter audit_log_events connection not set.'\n end as reason\n \n \n \nfrom\n azure_mysql_server as s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'audit_log_events'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') = 'connection' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') = 'connection' THEN s.name || ' server parameter audit_log_events has connection set.' + ELSE s.name || ' server parameter audit_log_events connection not set.' + END AS reason + FROM + azure_mysql_server AS s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'audit_log_events' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 4.4.4 Ensure server parameter 'audit_log_events' has 'CONNECTION' set for MySQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_6_5.yaml b/compliance/controls/pending/azure/azure_cis_v210_6_5.yaml old mode 100755 new mode 100644 index d379d2992..040aeffb9 --- a/compliance/controls/pending/azure/azure_cis_v210_6_5.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_6_5.yaml @@ -1,13 +1,36 @@ +Description: Network Security Group Flow Logs should be enabled and the retention period set to greater than or equal to 90 days. ID: azure_cis_v210_6_5 -Title: "6.5 Ensure that Network Security Group Flow Log retention period is 'greater than 90 days'" -Description: "Network Security Group Flow Logs should be enabled and the retention period set to greater than or equal to 90 days." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sg.id resource,\n case\n when fl.id is null or not fl.enabled or fl.retention_policy_days < 90 then 'alarm'\n else 'ok'\n end as status,\n case\n when fl.id is null or not fl.enabled\n then sg.name || ' flowlog not enabled.'\n when fl.retention_policy_days < 90\n then sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.'\n else sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.'\n end as reason\n \n \n \nfrom\n azure_network_security_group sg\n left join azure_network_watcher_flow_log fl on sg.id = fl.target_resource_id\n join azure_subscription sub on sub.subscription_id = sg.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sg.id AS resource, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled OR fl.retention_policy_days < 90 THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN fl.id IS NULL OR NOT fl.enabled + THEN sg.name || ' flowlog not enabled.' + WHEN fl.retention_policy_days < 90 + THEN sg.name || ' flowlog ' || fl.title || ' retention period is less than 90 days.' + ELSE sg.name || ' flowlog ' || fl.title || ' retention period is ' || fl.retention_policy_days || ' days.' + END AS reason + FROM + azure_network_security_group sg + LEFT JOIN + azure_network_watcher_flow_log fl + ON + sg.id = fl.target_resource_id + JOIN + azure_subscription sub + ON + sub.subscription_id = sg.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 6.5 Ensure that Network Security Group Flow Log retention period is 'greater than 90 days' \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_8_7.yaml b/compliance/controls/pending/azure/azure_cis_v210_8_7.yaml old mode 100755 new mode 100644 index 6eb901d99..5f58d10d2 --- a/compliance/controls/pending/azure/azure_cis_v210_8_7.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_8_7.yaml @@ -1,13 +1,31 @@ +Description: Private endpoints will secure network traffic from Azure Key Vault to the resources requesting secrets and keys. ID: azure_cis_v210_8_7 -Title: "8.7 Ensure that Private Endpoints are Used for Azure Key Vault" -Description: "Private endpoints will secure network traffic from Azure Key Vault to the resources requesting secrets and keys." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n -- Having private_endpoint_connections will not permit vault to use the same.\n -- In case'defaultAction' = 'Allow', All Network including internet is allowed, which will not satisfy the private endpoint connection.\n -- Default All network will have not network_acls associated.\n when network_acls is null or network_acls ->> 'defaultAction' = 'Allow' then 'alarm'\n when private_endpoint_connections is null then 'info'\n when private_endpoint_connections @> '[{\"PrivateLinkServiceConnectionStateStatus\": \"Approved\"}]' then 'ok'\n else 'alarm'\n end as status,\n case\n when network_acls is null or network_acls ->> 'defaultAction' = 'Allow' then a.name || ' using public networks.'\n when private_endpoint_connections is null then a.name || ' no private link exists.'\n when private_endpoint_connections @> '[{\"PrivateLinkServiceConnectionStateStatus\": \"Approved\"}]'\n then a.name || ' using private link.'\n else a.name || ' private link not enabled.'\n end as reason\n \n \n \nfrom\n azure_key_vault a,\n azure_subscription sub;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' = 'Allow' THEN 'alarm' + WHEN private_endpoint_connections IS NULL THEN 'info' + WHEN private_endpoint_connections @> '[{"PrivateLinkServiceConnectionStateStatus": "Approved"}]' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN network_acls IS NULL OR network_acls ->> 'defaultAction' = 'Allow' THEN a.name || ' using public networks.' + WHEN private_endpoint_connections IS NULL THEN a.name || ' no private link exists.' + WHEN private_endpoint_connections @> '[{"PrivateLinkServiceConnectionStateStatus": "Approved"}]' + THEN a.name || ' using private link.' + ELSE a.name || ' private link not enabled.' + END AS reason + FROM + azure_key_vault a, + azure_subscription sub; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 8.7 Ensure that Private Endpoints are Used for Azure Key Vault \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_cis_v210_9_9.yaml b/compliance/controls/pending/azure/azure_cis_v210_9_9.yaml old mode 100755 new mode 100644 index 0d5f39315..805f12761 --- a/compliance/controls/pending/azure/azure_cis_v210_9_9.yaml +++ b/compliance/controls/pending/azure/azure_cis_v210_9_9.yaml @@ -1,13 +1,46 @@ +Description: By default, Azure Functions, Web, and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions. ID: azure_cis_v210_9_9 -Title: "9.9 Ensure FTP deployments are Disabled" -Description: "By default, Azure Functions, Web, and API Services can be deployed over FTP. If FTP is required for an essential deployment workflow, FTPS should be required for FTP login for all App Service Apps and Functions." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n fa.id as resource,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n \n \n from\n azure_app_service_function_app fa,\n azure_subscription sub\n where\n sub.subscription_id = fa.subscription_id\nunion\n select\n wa.id as resource,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then 'alarm'\n else 'ok'\n end as status,\n case\n when configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' then name || ' FTP deployments enabled.'\n else name || ' FTP deployments disabled.'\n end as reason\n \n \n \n from\n azure_app_service_web_app as wa,\n azure_subscription as sub\n where\n sub.subscription_id = wa.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + fa.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason + FROM + azure_app_service_function_app fa, + azure_subscription sub + WHERE + sub.subscription_id = fa.subscription_id + + UNION + + SELECT + wa.id AS resource, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN configuration -> 'properties' ->> 'ftpsState' = 'AllAllowed' THEN name || ' FTP deployments enabled.' + ELSE name || ' FTP deployments disabled.' + END AS reason + FROM + azure_app_service_web_app wa, + azure_subscription sub + WHERE + sub.subscription_id = wa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: 9.9 Ensure FTP deployments are Disabled \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_compute_windows_vm_secure_boot_enabled.yaml b/compliance/controls/pending/azure/azure_compute_windows_vm_secure_boot_enabled.yaml old mode 100755 new mode 100644 index 2ee8396bc..3894a429c --- a/compliance/controls/pending/azure/azure_compute_windows_vm_secure_boot_enabled.yaml +++ b/compliance/controls/pending/azure/azure_compute_windows_vm_secure_boot_enabled.yaml @@ -1,13 +1,37 @@ +Description: Enable Secure Boot on supported Windows virtual machines to mitigate against malicious and unauthorized changes to the boot chain. Once enabled, only trusted bootloaders, kernel and kernel drivers will be allowed to run. This assessment applies to Trusted Launch and Confidential Windows virtual machines. ID: azure_compute_windows_vm_secure_boot_enabled -Title: "Secure Boot should be enabled on supported Windows virtual machines" -Description: "Enable Secure Boot on supported Windows virtual machines to mitigate against malicious and unauthorized changes to the boot chain. Once enabled, only trusted bootloaders, kernel and kernel drivers will be allowed to run. This assessment applies to Trusted Launch and Confidential Windows virtual machines." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n when image_offer not like '%Windows%' or os_type not like 'Windows%' then 'skip'\n when security_profile ->> 'securityType' in ('TrustedLaunch','ConfidentialVM') and security_profile ->> 'uefiSettings' is not null and security_profile -> 'uefiSettings' ->> 'secureBootEnabled' = 'true' then 'ok'\n else 'alarm'\n end as status,\n case\n when image_offer not like '%Windows%' or os_type not like 'Windows%' then a.title || ' is not a windows VM.'\n when security_profile ->> 'securityType' in ('TrustedLaunch','ConfidentialVM') and security_profile ->> 'uefiSettings' is not null and security_profile -> 'uefiSettings' ->> 'secureBootEnabled' = 'true' then a.title || ' secure boot enabled.'\n else a.title || ' secure boot disabled.'\n end as reason\n \n \n \nfrom\n azure_compute_virtual_machine as a,\n azure_subscription as sub\nwhere\n sub.subscription_id = a.subscription_id\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN image_offer NOT LIKE '%Windows%' OR os_type NOT LIKE 'Windows%' THEN 'skip' + WHEN security_profile ->> 'securityType' IN ('TrustedLaunch', 'ConfidentialVM') + AND security_profile ->> 'uefiSettings' IS NOT NULL + AND security_profile -> 'uefiSettings' ->> 'secureBootEnabled' = 'true' + THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN image_offer NOT LIKE '%Windows%' OR os_type NOT LIKE 'Windows%' + THEN a.title || ' is not a Windows VM.' + WHEN security_profile ->> 'securityType' IN ('TrustedLaunch', 'ConfidentialVM') + AND security_profile ->> 'uefiSettings' IS NOT NULL + AND security_profile -> 'uefiSettings' ->> 'secureBootEnabled' = 'true' + THEN a.title || ' secure boot enabled.' + ELSE a.title || ' secure boot disabled.' + END AS reason + FROM + azure_compute_virtual_machine AS a, + azure_subscription AS sub + WHERE + sub.subscription_id = a.subscription_id Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Secure Boot should be enabled on supported Windows virtual machines \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_iot_hub_private_link_used.yaml b/compliance/controls/pending/azure/azure_iot_hub_private_link_used.yaml old mode 100755 new mode 100644 index 55711d287..5b959043c --- a/compliance/controls/pending/azure/azure_iot_hub_private_link_used.yaml +++ b/compliance/controls/pending/azure/azure_iot_hub_private_link_used.yaml @@ -1,13 +1,31 @@ +Description: Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to the IoT Hub device provisioning service, data leakage risks are reduced. ID: azure_iot_hub_private_link_used -Title: "IoT Hub device provisioning service instances should use private link" -Description: "Azure Private Link lets you connect your virtual network to Azure services without a public IP address at the source or destination. The Private Link platform handles the connectivity between the consumer and services over the Azure backbone network. By mapping private endpoints to the IoT Hub device provisioning service, data leakage risks are reduced." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n -- Only applicable to standard tier\n when sku_tier = 'Basic' then 'skip'\n when pec -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' then 'ok'\n else 'alarm'\n end as status,\n case\n when sku_tier = 'Basic' then a.name || ' is of ' || sku_tier || ' tier.'\n when pec -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' then a.name || ' using private link.'\n else a.name || ' not using private link.'\n end as reason\n \n \n \nfrom\n azure_iothub a,\n jsonb_array_elements(private_endpoint_connections) as pec,\n azure_subscription sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN sku_tier = 'Basic' THEN 'skip' + WHEN pec -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_tier = 'Basic' THEN a.name || ' is of ' || sku_tier || ' tier.' + WHEN pec -> 'properties' -> 'privateLinkServiceConnectionState' ->> 'status' = 'Approved' THEN a.name || ' using private link.' + ELSE a.name || ' not using private link.' + END AS reason + FROM + azure_iothub a, + jsonb_array_elements(private_endpoint_connections) AS pec, + azure_subscription sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: IoT Hub device provisioning service instances should use private link \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_mariadb_server_private_link_used.yaml b/compliance/controls/pending/azure/azure_mariadb_server_private_link_used.yaml old mode 100755 new mode 100644 index efc2ae53d..c8b612bc8 --- a/compliance/controls/pending/azure/azure_mariadb_server_private_link_used.yaml +++ b/compliance/controls/pending/azure/azure_mariadb_server_private_link_used.yaml @@ -1,13 +1,30 @@ +Description: Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for MariaDB. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure. ID: azure_mariadb_server_private_link_used -Title: "Private endpoint should be enabled for MariaDB servers" -Description: "Private endpoint connections enforce secure communication by enabling private connectivity to Azure Database for MariaDB. Configure a private endpoint connection to enable access to traffic coming only from known networks and prevent access from all other IP addresses, including within Azure." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n -- Only applicable to standard tier\n when sku_tier = 'Basic' then 'skip'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then 'ok'\n else 'alarm'\n end as status,\n case\n when sku_tier = 'Basic' then a.name || ' is of ' || sku_tier || ' tier.'\n when private_endpoint_connections @> '[{\"privateLinkServiceConnectionStateStatus\": \"Approved\"}]'::jsonb then a.name || ' using private link.'\n else a.name || ' not using private link.'\n end as reason\n \n \n \nfrom\n azure_mariadb_server a,\n azure_subscription sub\nwhere\n sub.subscription_id = a.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN sku_tier = 'Basic' THEN 'skip' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN sku_tier = 'Basic' THEN a.name || ' is of ' || sku_tier || ' tier.' + WHEN private_endpoint_connections @> '[{"privateLinkServiceConnectionStateStatus": "Approved"}]'::jsonb THEN a.name || ' using private link.' + ELSE a.name || ' not using private link.' + END AS reason + FROM + azure_mariadb_server a, + azure_subscription sub + WHERE + sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Private endpoint should be enabled for MariaDB servers \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_monitor_logs_storage_container_insights_activity_logs_encrypted_with_byok.yaml b/compliance/controls/pending/azure/azure_monitor_logs_storage_container_insights_activity_logs_encrypted_with_byok.yaml old mode 100755 new mode 100644 index 0458aadda..8687e07e3 --- a/compliance/controls/pending/azure/azure_monitor_logs_storage_container_insights_activity_logs_encrypted_with_byok.yaml +++ b/compliance/controls/pending/azure/azure_monitor_logs_storage_container_insights_activity_logs_encrypted_with_byok.yaml @@ -1,13 +1,32 @@ +Description: Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK). ID: azure_monitor_logs_storage_container_insights_activity_logs_encrypted_with_byok -Title: "Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key" -Description: "Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault'\n then a.name || ' container insights-activity-logs encrypted with BYOK.'\n else a.name || ' container insights-activity-logs not encrypted with BYOK.'\n end as reason\n \n \n \nfrom\n azure_storage_container c,\n azure_storage_account a,\n azure_subscription sub\nwhere\n c.name = 'insights-activity-logs'\n and c.account_name = a.name\n and sub.subscription_id = a.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' + THEN a.name || ' container insights-activity-logs encrypted with BYOK.' + ELSE a.name || ' container insights-activity-logs not encrypted with BYOK.' + END AS reason + FROM + azure_storage_container c, + azure_storage_account a, + azure_subscription sub + WHERE + c.name = 'insights-activity-logs' + AND c.account_name = a.name + AND sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_monitor_logs_storage_container_insights_operational_logs_encrypted_with_byok.yaml b/compliance/controls/pending/azure/azure_monitor_logs_storage_container_insights_operational_logs_encrypted_with_byok.yaml old mode 100755 new mode 100644 index c16b08c26..8273bd205 --- a/compliance/controls/pending/azure/azure_monitor_logs_storage_container_insights_operational_logs_encrypted_with_byok.yaml +++ b/compliance/controls/pending/azure/azure_monitor_logs_storage_container_insights_operational_logs_encrypted_with_byok.yaml @@ -1,13 +1,32 @@ +Description: Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK). ID: azure_monitor_logs_storage_container_insights_operational_logs_encrypted_with_byok -Title: "Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key" -Description: "Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK)." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n a.id as resource,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault' then 'ok'\n else 'alarm'\n end as status,\n case\n when a.encryption_key_source = 'Microsoft.Keyvault'\n then a.name || ' container insights-operational-logs encrypted with BYOK.'\n else a.name || ' container insights-operational-logs not encrypted with BYOK.'\n end as reason\n \n \n \nfrom\n azure_storage_container c,\n azure_storage_account a,\n azure_subscription sub\nwhere\n c.name = 'insights-operational-logs'\n and c.account_name = a.name\n and sub.subscription_id = a.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + a.id AS resource, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN a.encryption_key_source = 'Microsoft.Keyvault' + THEN a.name || ' container insights-operational-logs encrypted with BYOK.' + ELSE a.name || ' container insights-operational-logs not encrypted with BYOK.' + END AS reason + FROM + azure_storage_container c, + azure_storage_account a, + azure_subscription sub + WHERE + c.name = 'insights-operational-logs' + AND c.account_name = a.name + AND sub.subscription_id = a.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Ensure the storage account containing the container with activity logs is encrypted with Customer Managed Key \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_postgres_db_server_log_duration_on.yaml b/compliance/controls/pending/azure/azure_postgres_db_server_log_duration_on.yaml old mode 100755 new mode 100644 index 8d7728b1b..66e48329e --- a/compliance/controls/pending/azure/azure_postgres_db_server_log_duration_on.yaml +++ b/compliance/controls/pending/azure/azure_postgres_db_server_log_duration_on.yaml @@ -1,13 +1,30 @@ +Description: Enable log_duration on PostgreSQL Servers. ID: azure_postgres_db_server_log_duration_on -Title: "Ensure server parameter 'log_duration' is set to 'ON' for PostgreSQL Database Server" -Description: "Enable log_duration on PostgreSQL Servers." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n s.id as resource,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then 'alarm'\n else 'ok'\n end as status,\n case\n when lower(config -> 'ConfigurationProperties' ->> 'value') != 'on' then name || ' server parameter log_duration off.'\n else name || ' server parameter log_duration on.'\n end as reason\n \n \n \nfrom\n azure_postgresql_server s,\n jsonb_array_elements(server_configurations) config,\n azure_subscription sub\nwhere\n config ->> 'Name' = 'log_duration'\n and sub.subscription_id = s.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + s.id AS resource, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN LOWER(config -> 'ConfigurationProperties' ->> 'value') != 'on' THEN name || ' server parameter log_duration off.' + ELSE name || ' server parameter log_duration on.' + END AS reason + FROM + azure_postgresql_server s, + jsonb_array_elements(server_configurations) config, + azure_subscription sub + WHERE + config ->> 'Name' = 'log_duration' + AND sub.subscription_id = s.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Ensure server parameter 'log_duration' is set to 'ON' for PostgreSQL Database Server \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_storage_account_containing_vhd_os_disk_cmk_encrypted.yaml b/compliance/controls/pending/azure/azure_storage_account_containing_vhd_os_disk_cmk_encrypted.yaml old mode 100755 new mode 100644 index 72550da65..a78c15b78 --- a/compliance/controls/pending/azure/azure_storage_account_containing_vhd_os_disk_cmk_encrypted.yaml +++ b/compliance/controls/pending/azure/azure_storage_account_containing_vhd_os_disk_cmk_encrypted.yaml @@ -1,13 +1,32 @@ +Description: This policy identifies Azure Storage account containing VHD OS disk which are not encrypted with CMK. VHD's attached to Virtual Machines are stored in Azure storage. By default Azure Storage account is encrypted using Microsoft Managed Keys. It is recommended to use Customer Managed Keys to encrypt data in Azure Storage accounts for better control on the data. ID: azure_storage_account_containing_vhd_os_disk_cmk_encrypted -Title: "Storage account containing VHD OS disk not encrypted with CMK" -Description: "This policy identifies Azure Storage account containing VHD OS disk which are not encrypted with CMK. VHD's attached to Virtual Machines are stored in Azure storage. By default Azure Storage account is encrypted using Microsoft Managed Keys. It is recommended to use Customer Managed Keys to encrypt data in Azure Storage accounts for better control on the data." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n case\n when sa.encryption_key_source = 'Microsoft.Storage'\n and vm.os_disk_vhd_uri is not null then 'alarm'\n else 'ok'\n end as status,\n case\n when sa.encryption_key_source = 'Microsoft.Storage'\n and vm.os_disk_vhd_uri is not null then sa.name || ' storage account containing VHD OS disk not encrypted with CMK.'\n else sa.name || ' storage account containing VHD OS disk encrypted with CMK.'\n end as reason\n \n \n \n \nfrom\n azure_storage_account sa,\n azure_compute_virtual_machine vm,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id\n and vm.os_disk_vhd_uri like '%' || sa.name || '%';\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sa.id AS resource, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' + AND vm.os_disk_vhd_uri IS NOT NULL THEN 'alarm' + ELSE 'ok' + END AS status, + CASE + WHEN sa.encryption_key_source = 'Microsoft.Storage' + AND vm.os_disk_vhd_uri IS NOT NULL THEN sa.name || ' storage account containing VHD OS disk not encrypted with CMK.' + ELSE sa.name || ' storage account containing VHD OS disk encrypted with CMK.' + END AS reason + FROM + azure_storage_account sa, + azure_compute_virtual_machine vm, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id + AND vm.os_disk_vhd_uri LIKE '%' || sa.name || '%'; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Storage account containing VHD OS disk not encrypted with CMK \ No newline at end of file diff --git a/compliance/controls/pending/azure/azure_storage_account_queues_logging_enabled.yaml b/compliance/controls/pending/azure/azure_storage_account_queues_logging_enabled.yaml old mode 100755 new mode 100644 index aeee78c78..302f3f78e --- a/compliance/controls/pending/azure/azure_storage_account_queues_logging_enabled.yaml +++ b/compliance/controls/pending/azure/azure_storage_account_queues_logging_enabled.yaml @@ -1,13 +1,36 @@ +Description: Storage Logging records details of requests (read, write, and delete operations) against your Azure queues. This policy identifies Azure storage accounts that do not have logging enabled for queues. As a best practice, enable logging for read, write, and delete request types on queues. ID: azure_storage_account_queues_logging_enabled -Title: "Storage account logging (Classic Diagnostic Setting) for queues should be enabled" -Description: "Storage Logging records details of requests (read, write, and delete operations) against your Azure queues. This policy identifies Azure storage accounts that do not have logging enabled for queues. As a best practice, enable logging for read, write, and delete request types on queues." +IntegrationType: + - azure_subscription Query: Engine: CloudQL-v0.0.1 - QueryToExecute: "select\n sa.id as resource,\n case\n when lower(sa.sku_tier) = 'standard'\n and (queue_logging_write and queue_logging_read and queue_logging_delete) then 'ok'\n else 'alarm'\n end as status,\n case\n when lower(sa.sku_tier) = 'standard'\n and (queue_logging_write and queue_logging_read and queue_logging_delete)\n then sa.name || ' storage account logging for queues is enabled.'\n else sa.name || ' storage account logging for queues is disabled for ' ||\n concat_ws(', ',\n case when not queue_logging_write then 'write' end,\n case when not queue_logging_read then 'read' end,\n case when not queue_logging_delete then 'delete' end\n ) || ' requests.'\n end as reason\n \n \n \nfrom\n azure_storage_account sa,\n azure_subscription sub\nwhere\n sub.subscription_id = sa.subscription_id;\n" - PrimaryTable: "" ListOfTables: [] Parameters: [] + PrimaryTable: "" + QueryToExecute: | + SELECT + sa.id AS resource, + CASE + WHEN LOWER(sa.sku_tier) = 'standard' + AND (queue_logging_write AND queue_logging_read AND queue_logging_delete) THEN 'ok' + ELSE 'alarm' + END AS status, + CASE + WHEN LOWER(sa.sku_tier) = 'standard' + AND (queue_logging_write AND queue_logging_read AND queue_logging_delete) + THEN sa.name || ' storage account logging for queues is enabled.' + ELSE sa.name || ' storage account logging for queues is disabled for ' || + CONCAT_WS(', ', + CASE WHEN NOT queue_logging_write THEN 'write' END, + CASE WHEN NOT queue_logging_read THEN 'read' END, + CASE WHEN NOT queue_logging_delete THEN 'delete' END + ) || ' requests.' + END AS reason + FROM + azure_storage_account sa, + azure_subscription sub + WHERE + sub.subscription_id = sa.subscription_id; Severity: low Tags: {} -IntegrationType: - - azure_subscription +Title: Storage account logging (Classic Diagnostic Setting) for queues should be enabled \ No newline at end of file diff --git a/compliance/controls/processed_files.log b/compliance/controls/processed_files.log deleted file mode 100644 index 451323102..000000000 --- a/compliance/controls/processed_files.log +++ /dev/null @@ -1,2846 +0,0 @@ -./azure/azure_cis_v130_1_4.yaml processed successfully. -./azure/azure_cis_v130_1_15.yaml processed successfully. -./azure/azure_cis_v210_3_13.yaml processed successfully. -./azure/azure_monitor_log_profile_retention_365_days.yaml processed successfully. -./azure/azure_cis_v210_7_5.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_4333.yaml processed successfully. -./azure/azure_cis_v140_1_3.yaml processed successfully. -./azure/azure_log_analytics_workspace_block_log_ingestion_and_querying_from_public.yaml processed successfully. -./azure/azure_synapse_workspace_encryption_at_rest_using_cmk.yaml processed successfully. -./azure/azure_cis_v150_2_1_5.yaml processed successfully. -./azure/azure_cis_v150_5_2_7.yaml processed successfully. -./azure/azure_cis_v200_4_4_2.yaml processed successfully. -./azure/azure_cis_v130_5_3.yaml processed successfully. -./azure/azure_iam_subscription_owner_max_3.yaml processed successfully. -./azure/azure_monitor_logs_storage_container_not_public_accessible.yaml processed successfully. -./azure/azure_keyvault_with_rbac_secret_expiration_set.yaml processed successfully. -./azure/azure_data_factory_uses_git_repository.yaml processed successfully. -./azure/azure_cis_v200_2_1_12.yaml processed successfully. -./azure/azure_cis_v210_3_2.yaml processed successfully. -./azure/azure_monitor_log_alert_delete_public_ip_address.yaml processed successfully. -./azure/azure_cis_v130_9_3.yaml processed successfully. -./azure/azure_cis_v150_1_9.yaml processed successfully. -./azure/azure_cis_v200_5_1_1.yaml processed successfully. -./azure/azure_network_interface_ip_forwarding_disabled.yaml processed successfully. -./azure/azure_securitycenter_security_alerts_to_owner_enabled.yaml processed successfully. -./azure/azure_cis_v140_9_4.yaml processed successfully. -./azure/azure_cis_v210_6_1.yaml processed successfully. -./azure/azure_postgres_sql_ssl_enabled.yaml processed successfully. -./azure/azure_keyvault_with_non_rbac_key_expiration_set.yaml processed successfully. -./azure/azure_cis_v200_3_8.yaml processed successfully. -./azure/azure_appservice_api_app_cors_no_star.yaml processed successfully. -./azure/azure_cis_v130_2_13.yaml processed successfully. -./azure/azure_container_registry_use_virtual_service_endpoint.yaml processed successfully. -./azure/azure_log_profile_enabled_for_all_subscription.yaml processed successfully. -./azure/azure_cis_v210_5_4.yaml processed successfully. -./azure/azure_cis_v140_3_2.yaml processed successfully. -./azure/azure_storage_sync_private_link_used.yaml processed successfully. -./azure/azure_cis_v150_4_4_1.yaml processed successfully. -./azure/azure_sql_server_transparent_data_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v200_2_1_6.yaml processed successfully. -./azure/azure_cis_v200_5_2_4.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_25.yaml processed successfully. -./azure/azure_kubernetes_cluster_node_restrict_public_access.yaml processed successfully. -./azure/azure_storage_account_tables_logging_enabled.yaml processed successfully. -./azure/azure_iot_hub_encrypted_with_cmk.yaml processed successfully. -./azure/azure_cis_v210_1_14.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_app_service_web_app_mandatory.yaml processed successfully. -./azure/azure_cis_v140_7_5.yaml processed successfully. -./azure/azure_compute_vm_scale_set_system_updates_installed.yaml processed successfully. -./azure/azure_cognitive_service_local_auth_disabled.yaml processed successfully. -./azure/azure_mysql_server_audit_logging_enabled.yaml processed successfully. -./azure/azure_cis_v130_7_2.yaml processed successfully. -./azure/azure_compute_vm_disaster_recovery_enabled.yaml processed successfully. -./azure/azure_cis_v140_2_6.yaml processed successfully. -./azure/azure_kubernetes_cluster_http_application_routing_disabled.yaml processed successfully. -./azure/azure_appservice_api_app_use_https.yaml processed successfully. -./azure/azure_monitor_log_alert_create_update_public_ip_address.yaml processed successfully. -./azure/azure_cis_v150_1_21.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_postgresql_server_mandatory.yaml processed successfully. -./azure/azure_cis_v130_2_1.yaml processed successfully. -./azure/azure_cis_v150_3_8.yaml processed successfully. -./azure/azure_cosmosdb_account_uses_aad_and_rbac.yaml processed successfully. -./azure/azure_appservice_plan_minimum_sku.yaml processed successfully. -./azure/azure_cis_v210_1_2_3.yaml processed successfully. -./azure/azure_cis_v210_9_4.yaml processed successfully. -./azure/azure_cis_v140_6_1.yaml processed successfully. -./azure/azure_databox_edge_device_double_encryption_enabled.yaml processed successfully. -./azure/azure_kubernetes_cluster_container_use_allowed_images.yaml processed successfully. -./azure/azure_cis_v150_4_1_2.yaml processed successfully. -./azure/azure_cis_v130_6_6.yaml processed successfully. -./azure/azure_cis_v200_1_9.yaml processed successfully. -./azure/azure_cis_v150_5_1_2.yaml processed successfully. -./azure/azure_kubernetes_cluster_container_use_allowed_capabilities.yaml processed successfully. -./azure/azure_kubernetes_cluster_key_vault_secret_rotation_enabled.yaml processed successfully. -./azure/azure_cis_v210_7_9.yaml processed successfully. -./azure/azure_compute_vm_remote_access_restricted_all_ports.yaml processed successfully. -./azure/azure_keyvault_vault_private_link_used.yaml processed successfully. -./azure/azure_cis_v150_9_2.yaml processed successfully. -./azure/azure_cis_v200_6_7.yaml processed successfully. -./azure/azure_cis_v130_1_19.yaml processed successfully. -./azure/azure_cis_v130_1_8.yaml processed successfully. -./azure/azure_cis_v210_1_22.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_log_alert_mandatory.yaml processed successfully. -./azure/azure_compute_vm_max_password_age_70_days_windows.yaml processed successfully. -./azure/azure_cis_v140_1_12.yaml processed successfully. -./azure/azure_appservice_authentication_enabled.yaml processed successfully. -./azure/azure_cis_v210_2_1_3.yaml processed successfully. -./azure/azure_cis_v210_5_2_1.yaml processed successfully. -./azure/azure_container_registry_trust_policy_enabled.yaml processed successfully. -./azure/azure_cis_v150_2_1_9.yaml processed successfully. -./azure/azure_search_service_uses_private_link.yaml processed successfully. -./azure/azure_mysql_server_encrypted_at_rest_using_cmk.yaml processed successfully. -./azure/azure_appservice_function_app_cors_no_star.yaml processed successfully. -./azure/azure_cis_v140_9_8.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_app_service_environment_mandatory.yaml processed successfully. -./azure/azure_cis_v200_1_2_6.yaml processed successfully. -./azure/azure_cis_v140_2_14.yaml processed successfully. -./azure/azure_cis_v150_1_5.yaml processed successfully. -./azure/azure_cis_v200_7_3.yaml processed successfully. -./azure/azure_cis_v150_8_6.yaml processed successfully. -./azure/azure_signalr_service_private_link_used.yaml processed successfully. -./azure/azure_network_security_group_not_configured_gateway_subnets.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_data_factory_mandatory.yaml processed successfully. -./azure/azure_cis_v150_1_17.yaml processed successfully. -./azure/azure_batch_account_encrypted_with_cmk.yaml processed successfully. -./azure/azure_apimanagement_service_with_virtual_network.yaml processed successfully. -./azure/azure_cis_v210_2_1_13.yaml processed successfully. -./azure/azure_search_service_public_network_access_disabled.yaml processed successfully. -./azure/azure_cis_v200_3_4.yaml processed successfully. -./azure/azure_sql_server_auditing_storage_account_destination_retention_90_days.yaml processed successfully. -./azure/azure_cis_v200_1_1_3.yaml processed successfully. -./azure/azure_cis_v200_5_2_8.yaml processed successfully. -./azure/azure_cis_v130_5_2_1.yaml processed successfully. -./azure/azure_cis_v130_3_9.yaml processed successfully. -./azure/azure_cis_v140_5_2_2.yaml processed successfully. -./azure/azure_cis_v150_2_1_10.yaml processed successfully. -./azure/azure_cis_v200_9_2.yaml processed successfully. -./azure/azure_synapse_workspace_vulnerability_assessment_enabled.yaml processed successfully. -./azure/azure_cis_v210_1_18.yaml processed successfully. -./azure/azure_cis_v150_10_1.yaml processed successfully. -./azure/azure_cis_v130_1_23.yaml processed successfully. -./azure/azure_sql_server_va_setting_scan_reports_configured.yaml processed successfully. -./azure/azure_cis_v150_3_4.yaml processed successfully. -./azure/azure_cis_v130_4_3_5.yaml processed successfully. -./azure/azure_cis_v150_3_10.yaml processed successfully. -./azure/azure_container_registry_admin_user_disabled.yaml processed successfully. -./azure/azure_cis_v210_4_5_3.yaml processed successfully. -./azure/azure_compute_vm_scale_set_logging_enabled.yaml processed successfully. -./azure/azure_cis_v200_1_5.yaml processed successfully. -./azure/azure_cosmosdb_account_key_based_metadata_write_access_disabled.yaml processed successfully. -./azure/azure_cis_v150_7_3.yaml processed successfully. -./azure/azure_appservice_web_app_ftps_enabled.yaml processed successfully. -./azure/azure_cis_v200_8_6.yaml processed successfully. -./azure/azure_compute_vm_scale_set_endpoint_protection_solution_installed.yaml processed successfully. -./azure/azure_cis_v150_1_2_5.yaml processed successfully. -./azure/azure_cis_v210_9_8.yaml processed successfully. -./azure/azure_compute_unattached_disk_encrypted_with_cmk.yaml processed successfully. -./azure/azure_cis_v210_5_1_4.yaml processed successfully. -./azure/azure_cis_v210_4_1_4.yaml processed successfully. -./azure/azure_postgresql_server_infrastructure_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v210_5_1_5.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_mssql_elasticpool_mandatory.yaml processed successfully. -./azure/azure_cis_v210_4_1_5.yaml processed successfully. -./azure/azure_cis_v200_1_4.yaml processed successfully. -./azure/azure_kubernetes_cluster_container_cpu_and_memory_resource_limit.yaml processed successfully. -./azure/azure_cis_v150_7_2.yaml processed successfully. -./azure/azure_appservice_web_app_register_with_active_directory_enabled.yaml processed successfully. -./azure/azure_cis_v150_1_2_4.yaml processed successfully. -./azure/azure_kubernetes_cluster_max_pod_50.yaml processed successfully. -./azure/azure_cis_v210_4_5_2.yaml processed successfully. -./azure/azure_cis_v140_4_3_7.yaml processed successfully. -./azure/azure_cis_v150_3_5.yaml processed successfully. -./azure/azure_cis_v150_3_11.yaml processed successfully. -./azure/azure_cis_v150_5_2_10.yaml processed successfully. -./azure/azure_monitor_log_cluster_encrypted_with_cmk.yaml processed successfully. -./azure/azure_cis_v210_1_19.yaml processed successfully. -./azure/azure_appservice_function_app_uses_managed_identity.yaml processed successfully. -./azure/azure_network_security_group_subnet_associated.yaml processed successfully. -./azure/azure_cis_v130_1_22.yaml processed successfully. -./azure/azure_cis_v150_2_1_11.yaml processed successfully. -./azure/azure_kubernetes_cluster_container_host_process_id_not_shared.yaml processed successfully. -./azure/azure_appservice_web_app_cors_no_star.yaml processed successfully. -./azure/azure_cis_v200_9_3.yaml processed successfully. -./azure/azure_apimanagement_service_client_certificate_enabled.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_data_lake_store_mandatory.yaml processed successfully. -./azure/azure_cis_v140_5_2_3.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_udp_port_1434.yaml processed successfully. -./azure/azure_cis_v200_1_1_2.yaml processed successfully. -./azure/azure_compute_vm_scale_set_automatic_upgrade_enabled.yaml processed successfully. -./azure/azure_cis_v200_5_2_9.yaml processed successfully. -./azure/azure_cis_v130_3_8.yaml processed successfully. -./azure/azure_cis_v200_9_11.yaml processed successfully. -./azure/azure_cis_v210_2_1_12.yaml processed successfully. -./azure/azure_cis_v200_3_5.yaml processed successfully. -./azure/azure_cis_v150_5_3.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_53.yaml processed successfully. -./azure/azure_cis_v150_1_16.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_resource_manager.yaml processed successfully. -./azure/azure_cis_v140_2_15.yaml processed successfully. -./azure/azure_cis_v130_5_1_5.yaml processed successfully. -./azure/azure_cis_v150_1_4.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_udp_port_53.yaml processed successfully. -./azure/azure_cis_v200_7_2.yaml processed successfully. -./azure/azure_compute_vm_non_internet_facing_protected_with_nsg.yaml processed successfully. -./azure/azure_cognitive_account_public_network_access_disabled.yaml processed successfully. -./azure/azure_cis_v140_9_9.yaml processed successfully. -./azure/azure_monitor_logs_storage_container_encryptes_with_byok.yaml processed successfully. -./azure/azure_securitycenter_mcas_integration.yaml processed successfully. -./azure/azure_cis_v150_2_1_8.yaml processed successfully. -./azure/azure_cis_v150_1_1_1.yaml processed successfully. -./azure/azure_network_sg_flowlog_retention_period_greater_than_90.yaml processed successfully. -./azure/azure_cis_v140_1_13.yaml processed successfully. -./azure/azure_eventhub_namespace_use_virtual_service_endpoint.yaml processed successfully. -./azure/azure_kubernetes_cluster_pod_host_path_volume_use_allowed_host_path.yaml processed successfully. -./azure/azure_cis_v210_2_1_2.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_virtual_network_gateway_mandatory.yaml processed successfully. -./azure/azure_cis_v130_1_18.yaml processed successfully. -./azure/azure_cis_v130_1_9.yaml processed successfully. -./azure/azure_cis_v210_1_23.yaml processed successfully. -./azure/azure_log_analytics_workspace_block_non_azure_ingestion.yaml processed successfully. -./azure/azure_kubernetes_cluster_container_privilege_escalation_restricted.yaml processed successfully. -./azure/azure_cis_v210_7_8.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_cosmosdb_mongo_database_mandatory.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_data_lake_analytics_account_mandatory.yaml processed successfully. -./azure/azure_appservice_api_app_latest_tls_version.yaml processed successfully. -./azure/azure_appservice_api_app_client_certificates_on.yaml processed successfully. -./azure/azure_appservice_function_app_ftps_enabled.yaml processed successfully. -./azure/azure_appservice_web_app_latest_java_version.yaml processed successfully. -./azure/azure_storage_account_infrastructure_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v150_5_1_3.yaml processed successfully. -./azure/azure_cis_v200_1_8.yaml processed successfully. -./azure/azure_cis_v150_2_2_1.yaml processed successfully. -./azure/azure_cis_v210_1_2_2.yaml processed successfully. -./azure/azure_cis_v210_9_5.yaml processed successfully. -./azure/azure_cis_v200_1_10.yaml processed successfully. -./azure/azure_cis_v150_1_20.yaml processed successfully. -./azure/azure_cis_v130_4_3_8.yaml processed successfully. -./azure/azure_cis_v200_4_3_1.yaml processed successfully. -./azure/azure_cis_v150_3_9.yaml processed successfully. -./azure/azure_cis_v200_5_3_1.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_application_security_group_mandatory.yaml processed successfully. -./azure/azure_logic_app_integration_service_environment_encrypted_with_cmk.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_135.yaml processed successfully. -./azure/azure_cis_v140_2_7.yaml processed successfully. -./azure/azure_kubernetes_cluster_authorized_ip_range_defined.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_appservice.yaml processed successfully. -./azure/azure_compute_vm_scale_set_boot_diagnostics_enabled.yaml processed successfully. -./azure/azure_logic_app_workflow_logging_enabled.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_storage_account_mandatory.yaml processed successfully. -./azure/azure_cis_v130_7_3.yaml processed successfully. -./azure/azure_container_registry_quarantine_policy_enabled.yaml processed successfully. -./azure/azure_cis_v210_1_15.yaml processed successfully. -./azure/azure_storage_account_queue_services_logging_enabled.yaml processed successfully. -./azure/azure_cis_v210_8_1.yaml processed successfully. -./azure/azure_cis_v140_7_4.yaml processed successfully. -./azure/azure_cis_v130_3_4.yaml processed successfully. -./azure/azure_cosmosdb_use_virtual_service_endpoint.yaml processed successfully. -./azure/azure_cis_v200_2_1_7.yaml processed successfully. -./azure/azure_cis_v200_5_2_5.yaml processed successfully. -./azure/azure_cis_v140_3_3.yaml processed successfully. -./azure/azure_monitor_log_alert_delete_policy_assignment.yaml processed successfully. -./azure/azure_cis_v210_4_3_8.yaml processed successfully. -./azure/azure_cis_v130_2_12.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_1433.yaml processed successfully. -./azure/azure_compute_vm_administrators_group_with_extra_accounts_windows.yaml processed successfully. -./azure/azure_cis_v200_3_9.yaml processed successfully. -./azure/azure_securitycenter_notify_alerts_configured.yaml processed successfully. -./azure/azure_cis_v140_9_5.yaml processed successfully. -./azure/azure_keyvault_certificate_validity_12_months.yaml processed successfully. -./azure/azure_cis_v130_9_2.yaml processed successfully. -./azure/azure_cis_v150_1_8.yaml processed successfully. -./azure/azure_cis_v200_2_1_13.yaml processed successfully. -./azure/azure_cis_v210_3_3.yaml processed successfully. -./azure/azure_appservice_api_app_ftps_enabled.yaml processed successfully. -./azure/azure_storage_account_blob_containers_public_access_private.yaml processed successfully. -./azure/azure_iam_deprecated_account.yaml processed successfully. -./azure/azure_appservice_web_app_remote_debugging_disabled.yaml processed successfully. -./azure/azure_cis_v150_2_1_4.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_log_profile_mandatory.yaml processed successfully. -./azure/azure_cis_v150_5_2_6.yaml processed successfully. -./azure/azure_cognitive_account_private_link_used.yaml processed successfully. -./azure/azure_cis_v140_8_1.yaml processed successfully. -./azure/azure_cis_v210_7_4.yaml processed successfully. -./azure/azure_keyvault_logging_enabled.yaml processed successfully. -./azure/azure_cis_v140_1_2.yaml processed successfully. -./azure/azure_container_instance_container_group_identity_provider_enabled.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_storage.yaml processed successfully. -./azure/azure_cis_v130_1_5.yaml processed successfully. -./azure/azure_cis_v130_1_14.yaml processed successfully. -./azure/azure_sql_server_tde_protector_cmk_encrypted.yaml processed successfully. -./azure/azure_keyvault_rbac_enabled.yaml processed successfully. -./azure/azure_cis_v210_3_12.yaml processed successfully. -./azure/azure_sql_database_vulnerability_findings_resolved.yaml processed successfully. -./azure/azure_cis_v140_1_9.yaml processed successfully. -./azure/azure_network_security_group_remote_access_restricted.yaml processed successfully. -./azure/azure_kubernetes_cluster_sku_standard.yaml processed successfully. -./azure/azure_storage_account_use_virtual_service_endpoint.yaml processed successfully. -./azure/azure_keyvault_with_non_rbac_secret_expiration_set.yaml processed successfully. -./azure/azure_mariadb_server_public_network_access_disabled.yaml processed successfully. -./azure/azure_cis_v150_9_4.yaml processed successfully. -./azure/azure_cis_v200_6_1.yaml processed successfully. -./azure/azure_hdinsight_cluster_encryption_in_transit_enabled.yaml processed successfully. -./azure/azure_cis_v210_1_24.yaml processed successfully. -./azure/azure_search_service_uses_sku_supporting_private_link.yaml processed successfully. -./azure/azure_cis_v200_2_1_18.yaml processed successfully. -./azure/azure_keyvault_managed_hms_purge_protection_enabled.yaml processed successfully. -./azure/azure_cis_v210_3_8.yaml processed successfully. -./azure/azure_cis_v140_1_14.yaml processed successfully. -./azure/azure_cis_v140_4_4_2.yaml processed successfully. -./azure/azure_cis_v210_5_2_7.yaml processed successfully. -./azure/azure_cis_v210_2_1_5.yaml processed successfully. -./azure/azure_kubernetes_cluster_container_use_allowed_apparmor_profile.yaml processed successfully. -./azure/azure_postgres_db_server_log_checkpoints_on.yaml processed successfully. -./azure/azure_authorize_access_to_security_functions_and_information.yaml processed successfully. -./azure/azure_healthcare_fhir_azure_api_encrypted_at_rest_with_cmk.yaml processed successfully. -./azure/azure_network_watcher_flow_log_traffic_analytics_enabled.yaml processed successfully. -./azure/azure_cis_v140_5_1_1.yaml processed successfully. -./azure/azure_compute_vm_malware_agent_automatic_upgrade_enabled.yaml processed successfully. -./azure/azure_cis_v140_2_12.yaml processed successfully. -./azure/azure_appservice_function_app_client_certificates_on.yaml processed successfully. -./azure/azure_cis_v200_1_21.yaml processed successfully. -./azure/azure_compute_vm_meet_security_option_audit_requirement_windows.yaml processed successfully. -./azure/azure_cis_v130_4_1_2.yaml processed successfully. -./azure/azure_cis_v130_9_9.yaml processed successfully. -./azure/azure_cis_v200_7_5.yaml processed successfully. -./azure/azure_audit_diagnostic_setting.yaml processed successfully. -./azure/azure_cis_v130_5_1_2.yaml processed successfully. -./azure/azure_cis_v150_1_3.yaml processed successfully. -./azure/azure_cosmosdb_account_encryption_at_rest_using_cmk.yaml processed successfully. -./azure/azure_cis_v150_1_11.yaml processed successfully. -./azure/azure_compute_vm_administrators_group_with_specified_members_windows.yaml processed successfully. -./azure/azure_kusto_cluster_disk_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v210_2_1_15.yaml processed successfully. -./azure/azure_keyvault_key_expiration_set.yaml processed successfully. -./azure/azure_sql_db_active_directory_admin_configured.yaml processed successfully. -./azure/azure_cis_v200_3_2.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_mssql_managed_instance_mandatory.yaml processed successfully. -./azure/azure_cis_v200_2_1_22.yaml processed successfully. -./azure/azure_cis_v130_5_2_7.yaml processed successfully. -./azure/azure_cis_v150_2_6.yaml processed successfully. -./azure/azure_network_lb_no_basic_sku.yaml processed successfully. -./azure/azure_cis_v140_5_2_4.yaml processed successfully. -./azure/azure_cis_v210_4_4_1.yaml processed successfully. -./azure/azure_cis_v140_3_8.yaml processed successfully. -./azure/azuread_spn_with_more_than_one_active_client_secret_created_x_days_ago.yaml processed successfully. -./azure/azure_application_gateway_waf_enabled.yaml processed successfully. -./azure/azure_compute_vm_log_analytics_agent_installed_windows.yaml processed successfully. -./azure/azure_cis_v200_9_4.yaml processed successfully. -./azure/azure_cis_v150_6_1.yaml processed successfully. -./azure/azure_compute_vm_scale_set_uses_managed_disks.yaml processed successfully. -./azure/azure_container_registry_geo_replication_enabled.yaml processed successfully. -./azure/azure_cis_v210_1_9.yaml processed successfully. -./azure/azure_eventhub_namespace_logging_enabled.yaml processed successfully. -./azure/azure_cis_v200_5_4.yaml processed successfully. -./azure/azure_compute_disk_access_uses_private_link.yaml processed successfully. -./azure/azure_cis_v150_3_2.yaml processed successfully. -./azure/azure_cosmosdb_account_with_firewall_rules.yaml processed successfully. -./azure/azure_machine_learning_workspace_encrypted_with_cmk.yaml processed successfully. -./azure/azure_compute_vm_windows_defender_exploit_guard_enabled.yaml processed successfully. -./azure/azure_postgres_db_server_log_retention_days_3.yaml processed successfully. -./azure/azure_cis_v150_7_5.yaml processed successfully. -./azure/azure_redis_cache_uses_private_link.yaml processed successfully. -./azure/azure_cis_v200_1_3.yaml processed successfully. -./azure/azure_databox_job_double_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v150_1_2_3.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_app_service_function_app_mandatory.yaml processed successfully. -./azure/azure_compute_vm_restrict_previous_24_passwords_resuse_windows.yaml processed successfully. -./azure/azure_eventgrid_domain_private_link_used.yaml processed successfully. -./azure/azure_cis_v210_4_1_2.yaml processed successfully. -./azure/azure_compute_vm_vulnerability_assessment_solution_enabled.yaml processed successfully. -./azure/azure_securitycenter_additional_email_configured.yaml processed successfully. -./azure/azure_cis_v210_5_1_2.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_mysql_server_mandatory.yaml processed successfully. -./azure/azure_cis_v130_8_1.yaml processed successfully. -./azure/azure_cis_v150_9_8.yaml processed successfully. -./azure/azure_cis_v130_1_2.yaml processed successfully. -./azure/azure_cis_v130_1_13.yaml processed successfully. -./azure/azure_cis_v210_3_15.yaml processed successfully. -./azure/azure_storage_account_encryption_at_rest_using_cmk.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_compute_availability_set_mandatory.yaml processed successfully. -./azure/azure_compute_vm_password_complexity_setting_enabled_windows.yaml processed successfully. -./azure/azure_cis_v140_1_5.yaml processed successfully. -./azure/azure_cis_v210_7_3.yaml processed successfully. -./azure/azure_cis_v140_8_6.yaml processed successfully. -./azure/azure_monitor_application_insights_configured.yaml processed successfully. -./azure/azure_frontdoor_waf_enabled.yaml processed successfully. -./azure/azure_appservice_web_app_latest_dotnet_framework_version.yaml processed successfully. -./azure/azure_cis_v150_5_2_1.yaml processed successfully. -./azure/azure_cis_v150_2_1_3.yaml processed successfully. -./azure/azure_appservice_web_app_latest_http_version.yaml processed successfully. -./azure/azure_cis_v140_1_18.yaml processed successfully. -./azure/azure_cis_v210_3_4.yaml processed successfully. -./azure/azure_cis_v200_10_1.yaml processed successfully. -./azure/azure_cis_v200_2_1_14.yaml processed successfully. -./azure/azure_cis_v200_3_10.yaml processed successfully. -./azure/azure_cis_v200_5_1_7.yaml processed successfully. -./azure/azure_cis_v130_9_5.yaml processed successfully. -./azure/azure_appservice_web_app_http_logs_enabled.yaml processed successfully. -./azure/azure_cis_v140_9_2.yaml processed successfully. -./azure/azure_cis_v210_6_7.yaml processed successfully. -./azure/azure_mariadb_server_geo_redundant_backup_enabled.yaml processed successfully. -./azure/azure_kubernetes_cluster_network_policy_enabled.yaml processed successfully. -./azure/azure_postgres_db_server_log_connections_on.yaml processed successfully. -./azure/azure_compute_vm_secure_communication_protocols_configured.yaml processed successfully. -./azure/azure_compute_vm_min_password_age_1_day_windows.yaml processed successfully. -./azure/azure_cis_v210_2_1_19.yaml processed successfully. -./azure/azure_cis_v130_2_15.yaml processed successfully. -./azure/azure_sql_database_allow_internet_access.yaml processed successfully. -./azure/azure_cis_v140_5_2_8.yaml processed successfully. -./azure/azure_cis_v140_3_4.yaml processed successfully. -./azure/azure_cis_v140_1_22.yaml processed successfully. -./azure/azure_cis_v130_3_3.yaml processed successfully. -./azure/azure_cis_v200_5_2_2.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_23.yaml processed successfully. -./azure/azure_appservice_web_app_uses_managed_identity.yaml processed successfully. -./azure/azure_cis_v210_1_12.yaml processed successfully. -./azure/azure_iam_user_no_built_in_contributor_role.yaml processed successfully. -./azure/azure_monitor_log_profile_enabled_for_all_categories.yaml processed successfully. -./azure/azure_cis_v210_1_5.yaml processed successfully. -./azure/azure_cis_v140_7_3.yaml processed successfully. -./azure/azure_cis_v210_8_6.yaml processed successfully. -./azure/azure_compute_vm_meet_security_option_requirement_windows.yaml processed successfully. -./azure/azure_cis_v200_9_8.yaml processed successfully. -./azure/azure_cis_v130_7_4.yaml processed successfully. -./azure/azure_cis_v150_2_3_2.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_mariadb_server_mandatory.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_keyvault.yaml processed successfully. -./azure/azure_compute_vm_meet_security_options_network_access_requirement_windows.yaml processed successfully. -./azure/azure_monitor_logs_storage_container_insights_operational_logs_not_public_accessible.yaml processed successfully. -./azure/azure_automation_account_variable_encryption_enabled.yaml processed successfully. -./azure/azure_sql_server_va_setting_reports_notify_admins.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_containerregistry.yaml processed successfully. -./azure/azure_compute_vm_with_no_specified_certificates_in_trusted_root_windows.yaml processed successfully. -./azure/azure_app_service_environment_internal_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v130_2_7.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_servicebus_namespace_mandatory.yaml processed successfully. -./azure/azure_network_security_group_https_access_restricted.yaml processed successfully. -./azure/azure_cis_v210_9_2.yaml processed successfully. -./azure/azure_cis_v210_1_2_5.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_sqldb.yaml processed successfully. -./azure/azure_cis_v200_1_17.yaml processed successfully. -./azure/azure_cis_v150_4_1_4.yaml processed successfully. -./azure/azure_compute_vm_utilizing_managed_disk.yaml processed successfully. -./azure/azure_cis_v150_5_1_5.yaml processed successfully. -./azure/azure_compute_vm_network_traffic_data_collection_linux_agent_installed.yaml processed successfully. -./azure/azure_cis_v150_9_11.yaml processed successfully. -./azure/azure_cis_v130_6_1.yaml processed successfully. -./azure/azure_cis_v150_4_1_5.yaml processed successfully. -./azure/azure_monitor_log_alert_create_policy_assignment.yaml processed successfully. -./azure/azure_cis_v140_6_6.yaml processed successfully. -./azure/azure_cis_v210_9_3.yaml processed successfully. -./azure/azure_eventhub_namespace_private_link_used.yaml processed successfully. -./azure/azure_cis_v210_1_2_4.yaml processed successfully. -./azure/azure_cis_v200_1_16.yaml processed successfully. -./azure/azure_cis_v150_4_5_2.yaml processed successfully. -./azure/azure_cis_v130_2_6.yaml processed successfully. -./azure/azure_sql_db_public_network_access_disabled.yaml processed successfully. -./azure/azure_network_public_ip_no_basic_sku.yaml processed successfully. -./azure/azure_cis_v200_4_3_7.yaml processed successfully. -./azure/azure_data_factory_encrypted_with_cmk.yaml processed successfully. -./azure/azure_cis_v140_2_1.yaml processed successfully. -./azure/azure_cognitive_account_encrypted_with_cmk.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_firewall_mandatory.yaml processed successfully. -./azure/azure_eventgrid_topic_identity_provider_enabled.yaml processed successfully. -./azure/azure_cis_v210_2_1_22.yaml processed successfully. -./azure/azure_storage_account_blob_service_logging_enabled.yaml processed successfully. -./azure/azure_signalr_service_no_free_tier_sku.yaml processed successfully. -./azure/azure_cis_v200_9_9.yaml processed successfully. -./azure/azure_cis_v130_7_5.yaml processed successfully. -./azure/azure_batch_account_identity_provider_enabled.yaml processed successfully. -./azure/azure_cis_v150_2_3_3.yaml processed successfully. -./azure/azure_cis_v210_1_13.yaml processed successfully. -./azure/azure_kubernetes_cluster_addon_azure_policy_enabled.yaml processed successfully. -./azure/azure_network_bastion_host_min_1.yaml processed successfully. -./azure/azure_cis_v210_1_4.yaml processed successfully. -./azure/azure_cis_v140_7_2.yaml processed successfully. -./azure/azure_compute_vm_passwords_stored_using_reversible_encryption_windows.yaml processed successfully. -./azure/azure_servicebus_namespace_no_overly_permissive_network_access.yaml processed successfully. -./azure/azure_cis_v130_3_2.yaml processed successfully. -./azure/azure_cis_v200_5_2_3.yaml processed successfully. -./azure/azure_cis_v200_2_1_1.yaml processed successfully. -./azure/azure_storage_account_min_tls_1_2.yaml processed successfully. -./azure/azure_cis_v140_5_2_9.yaml processed successfully. -./azure/azure_recovery_service_vault_encrypted_with_cmk.yaml processed successfully. -./azure/azure_cis_v130_2_14.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_cosmosdb_account_mandatory.yaml processed successfully. -./azure/azure_network_ddos_enabled.yaml processed successfully. -./azure/azure_cis_v210_2_1_18.yaml processed successfully. -./azure/azure_appservice_web_app_failed_request_tracing_enabled.yaml processed successfully. -./azure/azure_cis_v200_4_5_1.yaml processed successfully. -./azure/azure_sql_server_uses_private_link.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_udp_port_138.yaml processed successfully. -./azure/azure_cis_v210_6_6.yaml processed successfully. -./azure/azure_cis_v140_9_3.yaml processed successfully. -./azure/azure_appservice_web_app_client_certificates_on.yaml processed successfully. -./azure/azure_cis_v200_3_11.yaml processed successfully. -./azure/azure_kubernetes_cluster_privilege_containers_restricted.yaml processed successfully. -./azure/azure_cis_v200_5_1_6.yaml processed successfully. -./azure/azure_cis_v150_2_4_1.yaml processed successfully. -./azure/azure_cis_v130_9_4.yaml processed successfully. -./azure/azure_iam_user_not_allowed_to_create_security_group.yaml processed successfully. -./azure/azure_compute_vm_container_security_configurations_vulnerabilities_remediated.yaml processed successfully. -./azure/azure_cis_v210_1_1_1.yaml processed successfully. -./azure/azure_cis_v140_1_19.yaml processed successfully. -./azure/azure_cis_v210_3_5.yaml processed successfully. -./azure/azure_cis_v140_5_3.yaml processed successfully. -./azure/azure_cis_v200_2_1_15.yaml processed successfully. -./azure/azure_cis_v210_2_1_8.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_network_interface_mandatory.yaml processed successfully. -./azure/azure_cis_v150_2_1_2.yaml processed successfully. -./azure/azure_monitor_diagnostic_settings_captures_proper_categories.yaml processed successfully. -./azure/azure_cis_v140_1_4.yaml processed successfully. -./azure/azure_cis_v140_8_7.yaml processed successfully. -./azure/azure_cis_v210_7_2.yaml processed successfully. -./azure/azure_compute_vm_and_sacle_set_encryption_at_host_enabled.yaml processed successfully. -./azure/azure_cis_v150_9_9.yaml processed successfully. -./azure/azure_appservice_function_app_remote_debugging_disabled.yaml processed successfully. -./azure/azure_cis_v130_1_3.yaml processed successfully. -./azure/azure_cis_v130_1_12.yaml processed successfully. -./azure/azure_mysql_ssl_enabled.yaml processed successfully. -./azure/azure_cis_v210_3_14.yaml processed successfully. -./azure/azure_network_security_group_outbound_access_restricted.yaml processed successfully. -./azure/azure_compute_vm_temp_disks_cache_and_data_flows_encrypted.yaml processed successfully. -./azure/azure_mysql_server_infrastructure_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v210_2_2_1.yaml processed successfully. -./azure/azure_cis_v210_5_1_3.yaml processed successfully. -./azure/azure_mysql_server_min_tls_1_2.yaml processed successfully. -./azure/azure_cis_v200_8_1.yaml processed successfully. -./azure/azure_cis_v150_7_4.yaml processed successfully. -./azure/azure_eventgrid_domain_restrict_public_access.yaml processed successfully. -./azure/azure_compute_vm_log_analytics_agent_installed.yaml processed successfully. -./azure/azure_cis_v150_1_2_2.yaml processed successfully. -./azure/azure_securitycenter_automatic_provisioning_monitoring_agent_on.yaml processed successfully. -./azure/azure_servicebus_use_virtual_service_endpoint.yaml processed successfully. -./azure/azure_postgres_db_server_log_disconnections_on.yaml processed successfully. -./azure/azure_cis_v140_4_3_1.yaml processed successfully. -./azure/azure_monitor_log_alert_create_update_security_solution.yaml processed successfully. -./azure/azure_cis_v130_4_3_2.yaml processed successfully. -./azure/azure_cis_v150_3_3.yaml processed successfully. -./azure/azure_container_registry_encrypted_with_cmk.yaml processed successfully. -./azure/azure_cosmosdb_account_uses_private_link.yaml processed successfully. -./azure/azure_kusto_cluster_sku_with_sla.yaml processed successfully. -./azure/azure_cis_v210_1_8.yaml processed successfully. -./azure/azure_network_security_group_udp_service_restricted.yaml processed successfully. -./azure/azure_application_insights_block_log_ingestion_and_querying_from_public.yaml processed successfully. -./azure/azure_data_factory_uses_private_link.yaml processed successfully. -./azure/azure_cis_v200_9_5.yaml processed successfully. -./azure/azure_cis_v140_5_2_5.yaml processed successfully. -./azure/azure_kubernetes_cluster_upgraded_with_non_vulnerable_version.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_3306.yaml processed successfully. -./azure/azure_cis_v140_3_9.yaml processed successfully. -./azure/azure_sql_database_long_term_geo_redundant_backup_enabled.yaml processed successfully. -./azure/azure_compute_vm_guest_configuration_installed.yaml processed successfully. -./azure/azure_cis_v200_1_1_4.yaml processed successfully. -./azure/azure_cis_v130_5_2_6.yaml processed successfully. -./azure/azure_cis_v140_3_12.yaml processed successfully. -./azure/azure_cis_v210_2_1_14.yaml processed successfully. -./azure/azure_storage_account_uses_private_link.yaml processed successfully. -./azure/azure_appservice_web_app_latest_tls_version.yaml processed successfully. -./azure/azure_iam_no_custom_subscription_owner_roles_created.yaml processed successfully. -./azure/azure_compute_vm_security_configuration_vulnerabilities_remediated.yaml processed successfully. -./azure/azure_mariadb_server_ssl_enabled.yaml processed successfully. -./azure/azure_cis_v150_4_3_8.yaml processed successfully. -./azure/azure_cis_v200_3_3.yaml processed successfully. -./azure/azure_compute_vm_guest_configuration_with_no_managed_identity.yaml processed successfully. -./azure/azure_iam_user_not_allowed_to_register_application.yaml processed successfully. -./azure/azure_cis_v150_1_10.yaml processed successfully. -./azure/azure_recovery_service_vault_uses_private_link.yaml processed successfully. -./azure/azure_cis_v140_2_13.yaml processed successfully. -./azure/azure_cis_v200_1_2_1.yaml processed successfully. -./azure/azure_cis_v200_1_20.yaml processed successfully. -./azure/azure_cis_v130_9_8.yaml processed successfully. -./azure/azure_datalake_analytics_account_logging_enabled.yaml processed successfully. -./azure/azure_cis_v150_8_1.yaml processed successfully. -./azure/azure_cis_v200_7_4.yaml processed successfully. -./azure/azure_cis_v130_5_1_3.yaml processed successfully. -./azure/azure_batch_account_logging_enabled.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_batch_account_mandatory.yaml processed successfully. -./azure/azure_compute_vm_scale_set_ssh_key_authentication_linux.yaml processed successfully. -./azure/azure_monitor_log_alert_delete_security_solution.yaml processed successfully. -./azure/azure_compute_vm_meet_security_baseline_requirements_windows.yaml processed successfully. -./azure/azure_cis_v200_2_1_19.yaml processed successfully. -./azure/azure_cis_v210_3_9.yaml processed successfully. -./azure/azure_cis_v140_1_15.yaml processed successfully. -./azure/azure_cis_v210_5_2_6.yaml processed successfully. -./azure/azure_cis_v210_2_1_4.yaml processed successfully. -./azure/azure_cis_v150_9_5.yaml processed successfully. -./azure/azure_compute_disk_unattached_encrypted_with_cmk.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_key_vault_mandatory.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_logic_app_workflow_mandatory.yaml processed successfully. -./azure/azure_cis_v210_1_25.yaml processed successfully. -./azure/azure_compute_vm_password_file_permissions_0644_linux.yaml processed successfully. -./azure/azure_storage_account_block_public_access.yaml processed successfully. -./azure/azure_arc_compute_machine_windows_log_analytics_agent_installed.yaml processed successfully. -./azure/azure_cis_v200_1_19.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_containers.yaml processed successfully. -./azure/azure_redis_cache_ssl_enabled.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_container_registry_mandatory.yaml processed successfully. -./azure/azure_cis_v150_1_2_1.yaml processed successfully. -./azure/azure_cis_v200_8_2.yaml processed successfully. -./azure/azure_securitycenter_container_image_scan_enabled.yaml processed successfully. -./azure/azure_compute_vm_guest_configuration_with_user_and_system_assigned_managed_identity.yaml processed successfully. -./azure/azure_machine_learning_workspace_private_link_used.yaml processed successfully. -./azure/azure_cis_v130_2_9.yaml processed successfully. -./azure/azure_cis_v150_3_14.yaml processed successfully. -./azure/azure_cis_v130_4_3_1.yaml processed successfully. -./azure/azure_cis_v200_4_3_8.yaml processed successfully. -./azure/azure_cis_v210_8_8.yaml processed successfully. -./azure/azure_compute_vm_malware_agent_installed.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_key_vault_key_mandatory.yaml processed successfully. -./azure/azure_cis_v150_6_3.yaml processed successfully. -./azure/azure_cis_v200_9_6.yaml processed successfully. -./azure/azure_container_instance_container_group_in_virtual_network.yaml processed successfully. -./azure/azure_cis_v140_5_2_6.yaml processed successfully. -./azure/azure_iot_hub_logging_enabled.yaml processed successfully. -./azure/azure_cis_v140_3_11.yaml processed successfully. -./azure/azure_cis_v200_2_1_20.yaml processed successfully. -./azure/azure_cis_v130_5_2_5.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_route_table_mandatory.yaml processed successfully. -./azure/azure_automation_account_encrypted_with_cmk.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_network_security_group_mandatory.yaml processed successfully. -./azure/azure_cis_v210_2_1_17.yaml processed successfully. -./azure/azure_eventhub_namespace_cmk_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v210_5_3_1.yaml processed successfully. -./azure/azure_cis_v210_4_3_1.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_k8s.yaml processed successfully. -./azure/azure_container_registry_uses_private_link.yaml processed successfully. -./azure/azure_cis_v150_8_2.yaml processed successfully. -./azure/azure_cis_v200_7_7.yaml processed successfully. -./azure/azure_cis_v140_2_10.yaml processed successfully. -./azure/azure_cis_v200_1_2_2.yaml processed successfully. -./azure/azure_cis_v200_1_23.yaml processed successfully. -./azure/azure_web_pub_sub_private_link_used.yaml processed successfully. -./azure/azure_securitycenter_wdatp_integration.yaml processed successfully. -./azure/azure_sql_server_azure_defender_enabled.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_udp_port_137.yaml processed successfully. -./azure/azure_cis_v140_5_1_3.yaml processed successfully. -./azure/azure_kusto_cluster_double_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v150_1_1_4.yaml processed successfully. -./azure/azure_keyvault_with_rbac_key_expiration_set.yaml processed successfully. -./azure/azure_compute_vm_guest_configuration_installed_linux.yaml processed successfully. -./azure/azure_compute_vm_allowlist_rules_in_adaptive_application_control_policy_updated.yaml processed successfully. -./azure/azure_cis_v210_5_2_5.yaml processed successfully. -./azure/azure_cis_v210_2_1_7.yaml processed successfully. -./azure/azure_cis_v140_1_16.yaml processed successfully. -./azure/azure_postgres_sql_server_encrypted_at_rest_using_cmk.yaml processed successfully. -./azure/azure_cis_v200_6_3.yaml processed successfully. -./azure/azure_cis_v150_9_6.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_api_management_mandatory.yaml processed successfully. -./azure/azure_appservice_function_app_latest_http_version.yaml processed successfully. -./azure/azure_spring_cloud_service_network_injection_enabled.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_network_watcher_flow_log_mandatory.yaml processed successfully. -./azure/azure_compute_vm_vulnerability_findings_resolved_for_sql_server.yaml processed successfully. -./azure/azure_cis_v130_6_2.yaml processed successfully. -./azure/azure_cis_v150_5_1_6.yaml processed successfully. -./azure/azure_cis_v200_1_15.yaml processed successfully. -./azure/azure_monitor_log_alert_for_administrative_operations.yaml processed successfully. -./azure/azure_search_service_uses_managed_identity.yaml processed successfully. -./azure/azure_iam_deprecated_account_with_owner_roles.yaml processed successfully. -./azure/azure_cis_v210_1_2_7.yaml processed successfully. -./azure/azure_compute_vm_data_and_os_disk_uses_managed_disk.yaml processed successfully. -./azure/azure_sql_server_auditing_retention_period_90.yaml processed successfully. -./azure/azure_cis_v150_1_25.yaml processed successfully. -./azure/azure_cis_v150_4_5_1.yaml processed successfully. -./azure/azure_cis_v130_2_5.yaml processed successfully. -./azure/azure_cis_v210_2_1_21.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_server.yaml processed successfully. -./azure/azure_cis_v140_2_2.yaml processed successfully. -./azure/azure_eventgrid_domain_identity_provider_enabled.yaml processed successfully. -./azure/azure_cis_v130_7_6.yaml processed successfully. -./azure/azure_container_registry_retention_policy_enabled.yaml processed successfully. -./azure/azure_cis_v210_8_4.yaml processed successfully. -./azure/azure_arc_compute_machine_linux_log_analytics_agent_installed.yaml processed successfully. -./azure/azure_cis_v140_7_1.yaml processed successfully. -./azure/azure_cis_v210_1_7.yaml processed successfully. -./azure/azure_bot_service_encrypted_with_cmk.yaml processed successfully. -./azure/azure_monitor_log_alert_delete_nsg_rule.yaml processed successfully. -./azure/azure_storage_account_blobs_logging_enabled.yaml processed successfully. -./azure/azure_cis_v210_1_10.yaml processed successfully. -./azure/azure_securitycenter_pricing_standard.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_compute_disk_encryption_set_mandatory.yaml processed successfully. -./azure/azure_cis_v130_3_1.yaml processed successfully. -./azure/azure_storage_account_secure_transfer_required_enabled.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_21.yaml processed successfully. -./azure/azure_cis_v130_5_2_9.yaml processed successfully. -./azure/azure_cis_v200_2_1_2.yaml processed successfully. -./azure/azure_cis_v140_1_20.yaml processed successfully. -./azure/azure_postgres_db_server_allow_access_to_azure_services_disabled.yaml processed successfully. -./azure/azure_monitor_log_cluster_infrastructure_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v140_3_6.yaml processed successfully. -./azure/azure_keyvault_vault_use_virtual_service_endpoint.yaml processed successfully. -./azure/azure_securitycenter_asc_default_setting_not_disabled.yaml processed successfully. -./azure/azure_app_configuration_private_link_used.yaml processed successfully. -./azure/azure_cis_v150_4_3_7.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_opensource_relational_db.yaml processed successfully. -./azure/azure_cis_v200_4_5_2.yaml processed successfully. -./azure/azure_network_security_group_ssh_access_restricted.yaml processed successfully. -./azure/azure_sql_server_use_virtual_service_endpoint.yaml processed successfully. -./azure/azure_compute_vm_meet_security_options_user_account_control_requirement_windows.yaml processed successfully. -./azure/azure_monitor_logs_storage_container_insights_activity_logs_not_public_accessible.yaml processed successfully. -./azure/azure_compute_vm_scale_set_log_analytics_agent_installed.yaml processed successfully. -./azure/azure_cis_v130_9_7.yaml processed successfully. -./azure/azure_cis_v150_2_4_2.yaml processed successfully. -./azure/azure_eventgrid_topic_private_link_used.yaml processed successfully. -./azure/azure_cis_v200_5_1_5.yaml processed successfully. -./azure/azure_cis_v200_3_12.yaml processed successfully. -./azure/azure_compute_vm_azure_backup_enabled.yaml processed successfully. -./azure/azure_cis_v210_5_2_9.yaml processed successfully. -./azure/azure_cis_v200_2_1_16.yaml processed successfully. -./azure/azure_cis_v210_1_1_2.yaml processed successfully. -./azure/azure_cis_v210_3_6.yaml processed successfully. -./azure/azure_appservice_web_app_latest_python_version.yaml processed successfully. -./azure/azure_cis_v150_5_2_3.yaml processed successfully. -./azure/azure_cis_v150_2_1_1.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_sqlservervm.yaml processed successfully. -./azure/azure_cis_v140_8_4.yaml processed successfully. -./azure/azure_cis_v210_7_1.yaml processed successfully. -./azure/azure_cis_v140_1_7.yaml processed successfully. -./azure/azure_cis_v130_1_11.yaml processed successfully. -./azure/azure_cis_v130_8_3.yaml processed successfully. -./azure/azure_compute_os_and_data_disk_encrypted_with_cmk.yaml processed successfully. -./azure/azure_cis_v210_3_16.yaml processed successfully. -./azure/azure_cis_v130_1_1.yaml processed successfully. -./azure/azure_storage_account_table_service_logging_enabled.yaml processed successfully. -./azure/azure_cis_v130_1_10.yaml processed successfully. -./azure/azure_cis_v130_8_2.yaml processed successfully. -./azure/azure_cis_v140_8_5.yaml processed successfully. -./azure/azure_appservice_web_app_always_on.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_sql_database_mandatory.yaml processed successfully. -./azure/azure_compute_vm_meet_security_baseline_requirements_linux.yaml processed successfully. -./azure/azure_cosmosdb_account_virtual_network_filter_enabled.yaml processed successfully. -./azure/azure_cis_v150_5_2_2.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_public_ip_mandatory.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_key_vault_managed_hardware_security_module_mandatory.yaml processed successfully. -./azure/azure_keyvault_soft_delete_enabled.yaml processed successfully. -./azure/azure_cis_v210_5_2_8.yaml processed successfully. -./azure/azure_container_instance_container_group_secured_environment_variable.yaml processed successfully. -./azure/azure_network_network_peering_connected.yaml processed successfully. -./azure/azure_postgres_db_server_geo_redundant_backup_enabled.yaml processed successfully. -./azure/azure_cis_v200_2_1_17.yaml processed successfully. -./azure/azure_cis_v210_1_1_3.yaml processed successfully. -./azure/azure_monitor_log_alert_sql_firewall_rule.yaml processed successfully. -./azure/azure_cis_v210_3_7.yaml processed successfully. -./azure/azure_cis_v130_9_6.yaml processed successfully. -./azure/azure_cis_v200_4_1_4.yaml processed successfully. -./azure/azure_postgres_db_server_latest_tls_version.yaml processed successfully. -./azure/azure_cis_v140_9_1.yaml processed successfully. -./azure/azure_cis_v210_6_4.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_compute_virtual_machine_scale_set_mandatory.yaml processed successfully. -./azure/azure_compute_vm_uses_azure_resource_manager.yaml processed successfully. -./azure/azure_compute_vm_adaptive_application_controls_enabled.yaml processed successfully. -./azure/azure_cis_v200_4_5_3.yaml processed successfully. -./azure/azure_container_instance_container_group_encrypted_using_cmk.yaml processed successfully. -./azure/azure_storage_account_restrict_network_access.yaml processed successfully. -./azure/azure_cis_v140_4_5.yaml processed successfully. -./azure/azure_storage_account_uses_azure_resource_manager.yaml processed successfully. -./azure/azure_appservice_function_app_latest_tls_version.yaml processed successfully. -./azure/azure_cis_v140_3_7.yaml processed successfully. -./azure/azure_cis_v200_5_2_1.yaml processed successfully. -./azure/azure_cis_v130_5_2_8.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_20.yaml processed successfully. -./azure/azure_cis_v200_2_1_3.yaml processed successfully. -./azure/azure_cis_v140_1_21.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_compute_virtual_machine_mandatory.yaml processed successfully. -./azure/azure_cis_v210_8_5.yaml processed successfully. -./azure/azure_cis_v210_1_6.yaml processed successfully. -./azure/azure_compute_vm_adaptive_network_hardening_recommendation_applied.yaml processed successfully. -./azure/azure_cis_v210_1_11.yaml processed successfully. -./azure/azure_cis_v150_2_3_1.yaml processed successfully. -./azure/azure_hdinsight_cluster_encrypted_at_rest_with_cmk.yaml processed successfully. -./azure/azure_cis_v130_7_7.yaml processed successfully. -./azure/azure_network_watcher_enabled.yaml processed successfully. -./azure/azure_postgres_server_private_link_used.yaml processed successfully. -./azure/azure_cis_v210_2_1_20.yaml processed successfully. -./azure/azure_cis_v140_2_3.yaml processed successfully. -./azure/azure_app_configuration_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v200_4_3_5.yaml processed successfully. -./azure/azure_cis_v150_1_24.yaml processed successfully. -./azure/azure_cis_v130_2_4.yaml processed successfully. -./azure/azure_cis_v200_1_14.yaml processed successfully. -./azure/azure_cis_v210_1_2_6.yaml processed successfully. -./azure/azure_keyvault_vault_recoverable.yaml processed successfully. -./azure/azure_cis_v210_9_1.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_stream_analytics_job_mandatory.yaml processed successfully. -./azure/azure_network_sg_flowlog_enabled.yaml processed successfully. -./azure/azure_cis_v130_6_3.yaml processed successfully. -./azure/azure_cis_v150_5_1_7.yaml processed successfully. -./azure/azure_monitor_log_profile_enabled_for_all_regions.yaml processed successfully. -./azure/azure_cis_v150_9_7.yaml processed successfully. -./azure/azure_cis_v200_6_2.yaml processed successfully. -./azure/azure_healthcare_fhir_uses_private_link.yaml processed successfully. -./azure/azure_monitor_log_alert_create_update_sql_servers_firewall_rule.yaml processed successfully. -./azure/azure_kubernetes_cluster_pods_and_containers_uses_approved_user_and_group_id.yaml processed successfully. -./azure/azure_cis_v140_4_4_1.yaml processed successfully. -./azure/azure_cis_v210_5_2_4.yaml processed successfully. -./azure/azure_cis_v210_2_1_6.yaml processed successfully. -./azure/azure_network_watcher_in_regions_with_virtual_network.yaml processed successfully. -./azure/azure_cis_v140_1_17.yaml processed successfully. -./azure/azure_cis_v210_9_10.yaml processed successfully. -./azure/azure_compute_vm_ssh_key_authentication_linux.yaml processed successfully. -./azure/azure_hdinsight_cluster_encryption_at_host_enabled.yaml processed successfully. -./azure/azure_cis_v140_5_1_2.yaml processed successfully. -./azure/azure_ad_guest_user_reviewed_monthly.yaml processed successfully. -./azure/azure_cis_v140_4_1_2.yaml processed successfully. -./azure/azure_monitor_log_alert_create_update_nsg.yaml processed successfully. -./azure/azure_cis_v130_5_1_1.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_dns.yaml processed successfully. -./azure/azure_cis_v200_7_6.yaml processed successfully. -./azure/azure_cis_v150_8_3.yaml processed successfully. -./azure/azure_securitycenter_email_configured.yaml processed successfully. -./azure/azure_cis_v140_2_11.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_445.yaml processed successfully. -./azure/azure_cis_v200_1_2_3.yaml processed successfully. -./azure/azure_cis_v200_1_22.yaml processed successfully. -./azure/azure_compute_vm_account_with_password_linux.yaml processed successfully. -./azure/azure_cis_v150_1_12.yaml processed successfully. -./azure/azure_compute_vm_endpoint_protection_agent_installed.yaml processed successfully. -./azure/azure_servicebus_premium_namespace_cmk_encrypted.yaml processed successfully. -./azure/azure_cis_v200_3_1.yaml processed successfully. -./azure/azure_compute_vm_network_traffic_data_collection_windows_agent_installed.yaml processed successfully. -./azure/azure_cis_v210_2_1_16.yaml processed successfully. -./azure/azure_cis_v140_3_10.yaml processed successfully. -./azure/azure_cis_v200_2_1_21.yaml processed successfully. -./azure/azure_cis_v130_5_2_4.yaml processed successfully. -./azure/azure_eventgrid_topic_local_auth_enabled.yaml processed successfully. -./azure/azure_cis_v150_2_5.yaml processed successfully. -./azure/azure_synapse_workspace_private_link_used.yaml processed successfully. -./azure/azure_mysql_server_public_network_access_disabled.yaml processed successfully. -./azure/azure_cis_v130_9_11.yaml processed successfully. -./azure/azure_cis_v140_5_2_7.yaml processed successfully. -./azure/azure_cis_v210_4_4_2.yaml processed successfully. -./azure/azure_cis_v200_9_7.yaml processed successfully. -./azure/azure_cis_v150_6_2.yaml processed successfully. -./azure/azure_network_security_group_diagnostic_setting_deployed.yaml processed successfully. -./azure/azure_iam_subscription_owner_more_than_1.yaml processed successfully. -./azure/azure_kubernetes_cluster_https_enabled.yaml processed successfully. -./azure/azure_mssql_managed_instance_encryption_at_rest_using_cmk.yaml processed successfully. -./azure/azure_cis_v130_2_8.yaml processed successfully. -./azure/azure_cis_v150_3_1.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_search_service_mandatory.yaml processed successfully. -./azure/azure_cis_v150_3_15.yaml processed successfully. -./azure/azure_cis_v150_7_6.yaml processed successfully. -./azure/azure_cis_v200_8_3.yaml processed successfully. -./azure/azure_cis_v210_5_1_1.yaml processed successfully. -./azure/azure_cis_v200_1_18.yaml processed successfully. -./azure/azure_application_gateway_waf_uses_specified_mode.yaml processed successfully. -./azure/azure_compute_vm_guest_configuration_with_system_assigned_managed_identity.yaml processed successfully. -./azure/azure_cis_v150_2_2_2.yaml processed successfully. -./azure/azure_cis_v200_8_8.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_lb_mandatory.yaml processed successfully. -./azure/azure_cis_v200_1_13.yaml processed successfully. -./azure/azure_cis_v140_6_3.yaml processed successfully. -./azure/azure_cis_v210_9_6.yaml processed successfully. -./azure/azure_cis_v210_1_2_1.yaml processed successfully. -./azure/azure_keyvault_purge_protection_enabled.yaml processed successfully. -./azure/azure_cis_v130_2_3.yaml processed successfully. -./azure/azure_kubernetes_cluster_add_on_azure_policy_enabled.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_udp_port_445.yaml processed successfully. -./azure/azure_cis_v150_1_23.yaml processed successfully. -./azure/azure_storage_account_soft_delete_enabled.yaml processed successfully. -./azure/azure_cis_v140_4_3_8.yaml processed successfully. -./azure/azure_mssql_managed_instance_vulnerability_assessment_enabled.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_app_service_plan_mandatory.yaml processed successfully. -./azure/azure_cis_v140_2_4.yaml processed successfully. -./azure/azure_monitor_log_alert_delete_nsg.yaml processed successfully. -./azure/azure_search_service_replica_count_3.yaml processed successfully. -./azure/azure_cis_v140_9_11.yaml processed successfully. -./azure/azure_cis_v130_3_10.yaml processed successfully. -./azure/azure_cis_v210_8_2.yaml processed successfully. -./azure/azure_cis_v140_7_7.yaml processed successfully. -./azure/azure_sql_server_auditing_on.yaml processed successfully. -./azure/azure_cis_v210_1_16.yaml processed successfully. -./azure/azure_cis_v150_4_4_3.yaml processed successfully. -./azure/azure_cis_v130_3_7.yaml processed successfully. -./azure/azure_cis_v200_2_1_4.yaml processed successfully. -./azure/azure_cis_v200_5_2_6.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_network_watcher_mandatory.yaml processed successfully. -./azure/azure_appservice_function_app_restrict_public_acces.yaml processed successfully. -./azure/azure_cis_v150_1_19.yaml processed successfully. -./azure/azure_cis_v130_2_11.yaml processed successfully. -./azure/azure_recovery_service_vault_uses_managed_identity.yaml processed successfully. -./azure/azure_cis_v150_4_3_1.yaml processed successfully. -./azure/azure_network_watcher_flow_log_enabled.yaml processed successfully. -./azure/azure_iam_user_with_owner_permission_on_subscription_mfa_enabled.yaml processed successfully. -./azure/azure_cis_v210_6_3.yaml processed successfully. -./azure/azure_cis_v140_9_6.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_compute_snapshot_mandatory.yaml processed successfully. -./azure/azure_appservice_web_app_incoming_client_cert_on.yaml processed successfully. -./azure/azure_postgresql_server_public_network_access_disabled.yaml processed successfully. -./azure/azure_cis_v200_5_1_3.yaml processed successfully. -./azure/azure_cis_v200_2_2_1.yaml processed successfully. -./azure/azure_cis_v130_9_1.yaml processed successfully. -./azure/azure_cis_v150_8_8.yaml processed successfully. -./azure/azure_appservice_ftp_deployment_disabled.yaml processed successfully. -./azure/azure_compute_vm_guest_configuration_installed_windows.yaml processed successfully. -./azure/azure_cis_v200_3_14.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_5432.yaml processed successfully. -./azure/azure_databox_job_unlock_password_encrypted_with_cmk.yaml processed successfully. -./azure/azure_sql_server_and_databases_va_enabled.yaml processed successfully. -./azure/azure_monitor_log_alert_create_update_nsg_rule.yaml processed successfully. -./azure/azure_cis_v210_1_1_4.yaml processed successfully. -./azure/azure_sql_database_transparent_data_encryption_enabled.yaml processed successfully. -./azure/azure_kubernetes_cluster_restrict_public_access.yaml processed successfully. -./azure/azure_cis_v150_2_1_7.yaml processed successfully. -./azure/azure_cis_v150_5_2_5.yaml processed successfully. -./azure/azure_cis_v140_1_1.yaml processed successfully. -./azure/azure_cis_v140_8_2.yaml processed successfully. -./azure/azure_cis_v210_7_7.yaml processed successfully. -./azure/azure_sql_server_va_setting_periodic_scan_enabled.yaml processed successfully. -./azure/azure_container_registry_vulnerabilities_remediated.yaml processed successfully. -./azure/azure_compute_os_and_data_disk_encrypted_with_cmk_and_platform_managed.yaml processed successfully. -./azure/azure_cis_v210_3_11.yaml processed successfully. -./azure/azure_iam_external_user_with_read_permission.yaml processed successfully. -./azure/azure_cis_v130_8_5.yaml processed successfully. -./azure/azure_cis_v130_1_6.yaml processed successfully. -./azure/azure_cis_v130_1_17.yaml processed successfully. -./azure/azure_search_service_logging_enabled.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_compute_image_mandatory.yaml processed successfully. -./azure/azure_cis_v210_5_1_6.yaml processed successfully. -./azure/azure_cis_v200_8_4.yaml processed successfully. -./azure/azure_compute_vm_tcp_udp_access_restricted_internet.yaml processed successfully. -./azure/azure_cis_v150_7_1.yaml processed successfully. -./azure/azure_cis_v200_1_7.yaml processed successfully. -./azure/azure_cis_v210_4_5_1.yaml processed successfully. -./azure/azure_cis_v140_2_8.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_5500.yaml processed successfully. -./azure/azure_synapse_workspace_data_exfiltration_protection_enabled.yaml processed successfully. -./azure/azure_appservice_web_app_diagnostic_logs_enabled.yaml processed successfully. -./azure/azure_cis_v150_3_12.yaml processed successfully. -./azure/azure_network_virtual_network_gateway_no_basic_sku.yaml processed successfully. -./azure/azure_appservice_web_app_slot_use_https.yaml processed successfully. -./azure/azure_keyvault_firewall_enabled.yaml processed successfully. -./azure/azure_cis_v150_3_6.yaml processed successfully. -./azure/azure_cis_v130_1_21.yaml processed successfully. -./azure/azure_datalake_store_account_logging_enabled.yaml processed successfully. -./azure/azure_cis_v150_2_1_12.yaml processed successfully. -./azure/azure_storage_account_geo_redundant_enabled.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_5900.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_eventhub_namespace_mandatory.yaml processed successfully. -./azure/azure_sql_server_azure_ad_authentication_enabled.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_sql_server_mandatory.yaml processed successfully. -./azure/azure_cis_v130_5_2_3.yaml processed successfully. -./azure/azure_cis_v200_2_1_8.yaml processed successfully. -./azure/azure_stream_analytics_job_logging_enabled.yaml processed successfully. -./azure/azure_network_security_group_rdp_access_restricted.yaml processed successfully. -./azure/azure_cis_v200_1_1_1.yaml processed successfully. -./azure/azure_network_subnet_protected_by_firewall.yaml processed successfully. -./azure/azure_cis_v200_3_6.yaml processed successfully. -./azure/azure_cis_v210_2_1_11.yaml processed successfully. -./azure/azure_cis_v150_1_15.yaml processed successfully. -./azure/azure_compute_vm_attached_with_network.yaml processed successfully. -./azure/azure_cis_v210_4_3_7.yaml processed successfully. -./azure/azure_cis_v150_8_4.yaml processed successfully. -./azure/azure_cis_v200_7_1.yaml processed successfully. -./azure/azure_cis_v150_1_7.yaml processed successfully. -./azure/azure_cis_v200_1_2_4.yaml processed successfully. -./azure/azure_iam_external_user_with_write_permission.yaml processed successfully. -./azure/azure_appservice_web_app_use_https.yaml processed successfully. -./azure/azure_cis_v200_1_25.yaml processed successfully. -./azure/azure_compute_vm_system_updates_installed.yaml processed successfully. -./azure/azure_cis_v140_5_1_5.yaml processed successfully. -./azure/azure_servicebus_name_space_private_link_used.yaml processed successfully. -./azure/azure_cis_v150_1_1_2.yaml processed successfully. -./azure/azure_cis_v150_5_2_9.yaml processed successfully. -./azure/azure_iam_external_user_with_owner_role.yaml processed successfully. -./azure/azure_kubernetes_cluster_logging_enabled.yaml processed successfully. -./azure/azure_cis_v210_2_1_1.yaml processed successfully. -./azure/azure_cis_v210_5_2_3.yaml processed successfully. -./azure/azure_mandatory_sql_subscription_resource_group_mandatory.yaml processed successfully. -./azure/azure_cis_v140_1_10.yaml processed successfully. -./azure/azure_monitor_log_analytics_workspace_integrated_with_encrypted_storage_account.yaml processed successfully. -./azure/azure_cis_v210_1_20.yaml processed successfully. -./azure/azure_cis_v210_5_2_10.yaml processed successfully. -./azure/azure_app_configuration_sku_standard.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_redis_cache_mandatory.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_virtual_network_mandatory.yaml processed successfully. -./azure/azure_iam_user_not_allowed_to_create_tenants.yaml processed successfully. -./azure/azure_appservice_web_app_latest_php_version.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_express_route_circuit_mandatory.yaml processed successfully. -./azure/azure_cis_v210_1_21.yaml processed successfully. -./azure/azure_network_security_group_restrict_inbound_icmp_port.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_key_vault_deleted_vault_mandatory.yaml processed successfully. -./azure/azure_cis_v150_9_1.yaml processed successfully. -./azure/azure_cis_v200_6_4.yaml processed successfully. -./azure/azure_keyvault_vault_public_network_access_disabled.yaml processed successfully. -./azure/azure_cis_v210_5_2_2.yaml processed successfully. -./azure/azure_kubernetes_cluster_network_plugin_azure.yaml processed successfully. -./azure/azure_cis_v140_1_11.yaml processed successfully. -./azure/azure_appservice_function_app_latest_python_version.yaml processed successfully. -./azure/azure_cis_v150_1_1_3.yaml processed successfully. -./azure/azure_cis_v150_5_2_8.yaml processed successfully. -./azure/azure_servicebus_namespace_azure_ad_authentication_enabled.yaml processed successfully. -./azure/azure_kubernetes_cluster_pod_use_approved_host_network_and_port_range.yaml processed successfully. -./azure/azure_compute_vm_jit_access_protected.yaml processed successfully. -./azure/azure_cis_v150_8_5.yaml processed successfully. -./azure/azure_compute_vm_monitor_missing_endpoint_protection_in_asc.yaml processed successfully. -./azure/azure_keyvault_managed_hms_logging_enabled.yaml processed successfully. -./azure/azure_compute_vm_restrict_remote_connection_from_accounts_without_password_linux.yaml processed successfully. -./azure/azure_cis_v150_1_6.yaml processed successfully. -./azure/azure_cis_v200_1_2_5.yaml processed successfully. -./azure/azure_cis_v200_1_24.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_cosmosdb.yaml processed successfully. -./azure/azure_iam_subscriptions_with_custom_roles_no_overly_permissive.yaml processed successfully. -./azure/azure_cis_v150_1_14.yaml processed successfully. -./azure/azure_monitor_log_alert_delete_sql_servers_firewall_rule.yaml processed successfully. -./azure/azure_servicebus_namespace_logging_enabled.yaml processed successfully. -./azure/azure_cis_v210_2_1_10.yaml processed successfully. -./azure/azure_cis_v130_5_2_2.yaml processed successfully. -./azure/azure_servicefabric_cluster_active_directory_authentication_enabled.yaml processed successfully. -./azure/azure_cis_v200_2_1_9.yaml processed successfully. -./azure/azure_sql_server_threat_detection_all_enabled.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_iothub_mandatory.yaml processed successfully. -./azure/azure_compute_vm_meet_security_options_requirement_windows.yaml processed successfully. -./azure/azure_storage_account_default_network_access_rule_denied.yaml processed successfully. -./azure/azure_kubernetes_cluster_temp_disks_and_agent_node_pool_cache_encrypted_at_host.yaml processed successfully. -./azure/azure_cis_v140_5_2_1.yaml processed successfully. -./azure/azure_securitycenter_azure_defender_on_for_database.yaml processed successfully. -./azure/azure_compute_vm_meet_system_audit_policies_requirement_windows.yaml processed successfully. -./azure/azure_cis_v200_9_1.yaml processed successfully. -./azure/azure_cis_v150_6_4.yaml processed successfully. -./azure/azure_cis_v150_2_1_13.yaml processed successfully. -./azure/azure_iam_no_custom_role.yaml processed successfully. -./azure/azure_cis_v130_1_20.yaml processed successfully. -./azure/azure_redis_cache_no_basic_sku.yaml processed successfully. -./azure/azure_kubernetes_cluster_os_and_data_disks_encrypted_with_cmk.yaml processed successfully. -./azure/azure_data_factory_public_network_access_disabled.yaml processed successfully. -./azure/azure_keyvault_secret_expiration_set.yaml processed successfully. -./azure/azure_compute_vm_image_builder_uses_private_link.yaml processed successfully. -./azure/azure_cis_v150_3_7.yaml processed successfully. -./azure/azure_stream_analytics_job_encrypted_with_cmk.yaml processed successfully. -./azure/azuread_user_should_have_mfa_enabled_with_azure_subscription_role_assignment.yaml processed successfully. -./azure/azure_cis_v140_2_9.yaml processed successfully. -./azure/azure_appservice_api_app_uses_managed_identity.yaml processed successfully. -./azure/azure_cis_v150_1_2_6.yaml processed successfully. -./azure/azure_cis_v200_8_5.yaml processed successfully. -./azure/azure_container_registry_public_network_access_disabled.yaml processed successfully. -./azure/azure_iam_user_with_write_permission_on_subscription_mfa_enabled.yaml processed successfully. -./azure/azure_compute_vm_meet_firewall_properties_windows.yaml processed successfully. -./azure/azure_compute_vm_scale_set_security_configuration_vulnerabilities_remediated.yaml processed successfully. -./azure/azure_cis_v200_1_6.yaml processed successfully. -./azure/azure_mysql_server_audit_logging_events_connection_set.yaml processed successfully. -./azure/azure_mysql_server_private_link_used.yaml processed successfully. -./azure/azure_appservice_web_app_use_virtual_service_endpoint.yaml processed successfully. -./azure/azure_cis_v210_3_10.yaml processed successfully. -./azure/azure_cis_v130_8_4.yaml processed successfully. -./azure/azure_cis_v130_1_7.yaml processed successfully. -./azure/azure_cis_v130_1_16.yaml processed successfully. -./azure/azure_redis_cache_min_tls_1_2.yaml processed successfully. -./azure/azure_recovery_service_vault_uses_private_link_for_backup.yaml processed successfully. -./azure/azure_cognitive_account_restrict_public_access.yaml processed successfully. -./azure/azure_compute_vm_min_password_length_14_windows.yaml processed successfully. -./azure/azure_cis_v210_7_6.yaml processed successfully. -./azure/azure_cis_v140_8_3.yaml processed successfully. -./azure/azure_iam_user_with_read_permission_on_subscription_mfa_enabled.yaml processed successfully. -./azure/azure_cis_v150_2_1_6.yaml processed successfully. -./azure/azure_appservice_function_app_latest_java_version.yaml processed successfully. -./azure/azure_cis_v150_5_2_4.yaml processed successfully. -./azure/azure_cis_v200_4_4_1.yaml processed successfully. -./azure/azure_kubernetes_instance_rbac_enabled.yaml processed successfully. -./azure/azure_cis_v210_3_1.yaml processed successfully. -./azure/azure_cis_v200_2_1_11.yaml processed successfully. -./azure/azure_cis_v200_5_1_2.yaml processed successfully. -./azure/azure_arc_kubernetes_cluster_azure_defender_extension_installed.yaml processed successfully. -./azure/azure_storage_account_encryption_scopes_encrypted_at_rest_with_cmk.yaml processed successfully. -./azure/azure_cis_v200_4_1_2.yaml processed successfully. -./azure/azure_kubernetes_cluster_upgrade_channel.yaml processed successfully. -./azure/azure_cis_v200_3_15.yaml processed successfully. -./azure/azure_datalake_store_account_encryption_enabled.yaml processed successfully. -./azure/azure_cis_v140_9_7.yaml processed successfully. -./azure/azure_cis_v210_6_2.yaml processed successfully. -./azure/azure_cis_v200_5_2_10.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_key_vault_secret_mandatory.yaml processed successfully. -./azure/azure_cis_v130_4_4.yaml processed successfully. -./azure/azure_cis_v210_10_1.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_kubernetes_cluster_mandatory.yaml processed successfully. -./azure/azure_cis_v130_2_10.yaml processed successfully. -./azure/azure_iam_conditional_access_mfa_enabled.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_recovery_services_vault_mandatory.yaml processed successfully. -./azure/azure_cis_v140_3_1.yaml processed successfully. -./azure/azure_appservice_function_app_authentication_on.yaml processed successfully. -./azure/azure_appservice_function_app_only_https_accessible.yaml processed successfully. -./azure/azure_appservice_web_app_health_check_enabled.yaml processed successfully. -./azure/azure_servicefabric_cluster_protection_level_as_encrypt_and_sign.yaml processed successfully. -./azure/azure_cis_v130_3_6.yaml processed successfully. -./azure/azure_cis_v150_4_4_2.yaml processed successfully. -./azure/azure_cis_v200_2_1_5.yaml processed successfully. -./azure/azure_cis_v200_5_2_7.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_compute_disk_mandatory.yaml processed successfully. -./azure/azure_appservice_api_app_remote_debugging_disabled.yaml processed successfully. -./azure/azure_hpc_cache_encrypted_with_cmk.yaml processed successfully. -./azure/azure_cis_v130_3_11.yaml processed successfully. -./azure/azure_cis_v140_7_6.yaml processed successfully. -./azure/azure_cis_v210_8_3.yaml processed successfully. -./azure/azure_cis_v210_1_17.yaml processed successfully. -./azure/azure_cis_v130_7_1.yaml processed successfully. -./azure/azure_sql_server_atp_enabled.yaml processed successfully. -./azure/azure_postgres_db_server_connection_throttling_on.yaml processed successfully. -./azure/azure_cis_v140_2_5.yaml processed successfully. -./azure/azure_compute_vm_administrators_group_with_no_specified_members_windows.yaml processed successfully. -./azure/azure_cis_v130_2_2.yaml processed successfully. -./azure/azure_redis_cache_in_virtual_network.yaml processed successfully. -./azure/azure_kusto_cluster_encrypted_at_rest_with_cmk.yaml processed successfully. -./azure/azure_cis_v150_1_22.yaml processed successfully. -./azure/azure_mandatory_sql_resource_group_cosmosdb_sql_database_mandatory.yaml processed successfully. -./azure/azure_cis_v200_1_12.yaml processed successfully. -./azure/azure_mysql_db_server_geo_redundant_backup_enabled.yaml processed successfully. -./azure/azure_cis_v210_9_7.yaml processed successfully. -./azure/azure_cis_v140_6_2.yaml processed successfully. -./azure/azure_container_registry_restrict_public_access.yaml processed successfully. -./azure/azure_kubernetes_cluster_service_listen_to_allowed_ports.yaml processed successfully. -./azure/azure_cis_v150_5_1_1.yaml processed successfully. -./azure/azure_cis_v150_2_2_3.yaml processed successfully. -./azure/azure_storage_account_trusted_microsoft_services_enabled.yaml processed successfully. -./azure/azure_kubernetes_cluster_container_with_read_only_root_file_system.yaml processed successfully. -./baseline/azure/storage_account/azure_disable_public_access_to_storage_accounts_with_blob_containers.yaml processed successfully. -./baseline/azure/storage_account/azure_enable_trusted_microsoft_services_for_storage_account_access.yaml processed successfully. -./baseline/azure/storage_account/azure_private_endpoint_in_use.yaml processed successfully. -./baseline/azure/storage_account/azure_enable_blob_storage_lifecycle_management.yaml processed successfully. -./baseline/azure/storage_account/azure_disable_anonymous_access_to_blob_containers.yaml processed successfully. -./baseline/azure/storage_account/azure_enable_logging_for_azure_storage_table_service.yaml processed successfully. -./baseline/azure/storage_account/azure_enable_immutable_blob_storage.yaml processed successfully. -./baseline/azure/storage_account/azure_enable_infrastructure_encryption.yaml processed successfully. -./baseline/azure/storage_account/azure_storage_account_encryption_using_customer_managed_keys.yaml processed successfully. -./baseline/azure/storage_account/azure_enable_soft_delete_for_azure_blob_storage.yaml processed successfully. -./baseline/azure/storage_account/azure_enable_logging_for_azure_storage_queue_service.yaml processed successfully. -./baseline/azure/storage_account/azure_check_for_sufficient_soft_deleted_data_retention_period.yaml processed successfully. -./baseline/azure/storage_account/azure_enable_secure_transfer_in_azure_storage.yaml processed successfully. -./baseline/azure/storage_account/azure_configure_minimum_tls_version.yaml processed successfully. -./baseline/azure/storage_account/azure_use_byok_for_storage_account_encryption.yaml processed successfully. -./baseline/azure/storage_account/azure_check_for_publicly_accessible_web_containers.yaml processed successfully. -./baseline/azure/storage_account/azure_enable_logging_for_azure_storage_blob_service.yaml processed successfully. -./baseline/azure/storage_account/azure_limit_storage_account_access_by_ip_address.yaml processed successfully. -./baseline/azure/storage_account/azure_restrict_default_network_access_for_storage_accounts.yaml processed successfully. -./baseline/azure/monitor/azure_monitor_log_all_activities.yaml processed successfully. -./baseline/azure/recovery_service/azure_recovery_service_vault_not_publicly_accessible_and_not_encrypted.yaml processed successfully. -./baseline/azure/recovery_service/azure_recovery_service_vault_alert_for_job_failures_enabled.yaml processed successfully. -./baseline/azure/KeyVault/azure_set_azure_secret_key_expiration.yaml processed successfully. -./baseline/azure/KeyVault/azure_app_tier_customer_managed_key_in_use.yaml processed successfully. -./baseline/azure/KeyVault/azure_enable_auditevent_logging_for_azure_key_vaults.yaml processed successfully. -./baseline/azure/KeyVault/azure_web_tier_customer_managed_key_in_use.yaml processed successfully. -./baseline/azure/KeyVault/azure_set_encryption_key_expiration.yaml processed successfully. -./baseline/azure/KeyVault/azure_enable_trusted_microsoft_services_for_key_vault_access.yaml processed successfully. -./baseline/azure/KeyVault/azure_check_for_allowed_certificate_key_types.yaml processed successfully. -./baseline/azure/KeyVault/azure_database_tier_customer_managed_key_in_use.yaml processed successfully. -./baseline/azure/KeyVault/azure_enable_ssl_certificate_auto_renewal.yaml processed successfully. -./baseline/azure/KeyVault/azure_enable_certificate_transparency.yaml processed successfully. -./baseline/azure/KeyVault/azure_restrict_default_network_access_for_azure_key_vaults.yaml processed successfully. -./baseline/azure/KeyVault/azure_check_for_azure_key_vault_secrets_expiration_date.yaml processed successfully. -./baseline/azure/KeyVault/azure_check_for_sufficient_certificate_auto_renewal_period.yaml processed successfully. -./baseline/azure/KeyVault/azure_check_for_azure_key_vault_keys_expiration_date.yaml processed successfully. -./baseline/azure/KeyVault/azure_enable_key_vault_recoverability.yaml processed successfully. -./baseline/azure/KeyVault/azure_check_for_key_vault_full_administrator_permissions.yaml processed successfully. -./baseline/azure/KeyVault/azure_check_for_certificate_minimum_key_size.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_accelerated_networking_for_virtual_machines.yaml processed successfully. -./baseline/azure/virtual_machine/azure_disk_encryption_for_boot_disk_volumes.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_backups_for_azure_virtual_machines.yaml processed successfully. -./baseline/azure/virtual_machine/azure_server_side_encryption_for_unattached_disk_using_cmk.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_usage_of_customer_managed_keys_for_virtual_hard_disk_encryption.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_encryption_for_web_tier_disk_volumes.yaml processed successfully. -./baseline/azure/virtual_machine/azure_approved_azure_machine_image_in_use.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_old_virtual_machine_disk_snapshots.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_guest_level_diagnostics_for_virtual_machines.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_usage_of_managed_disk_volumes_for_virtual_machines.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_sufficient_instant_restore_retention_period.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_usage_of_approved_extensions_only.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_installataion_for_latest_os_patches.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_autoscale_notifications.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_sufficient_daily_backup_retention_period.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_performance_diagnostics_for_azure_virtual_machines.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_ssh_authentication_type.yaml processed successfully. -./baseline/azure/virtual_machine/azure_disk_encryption_for_non_boot_disk_volumes.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_unattached_virtual_machine_disk_volumes.yaml processed successfully. -./baseline/azure/virtual_machine/azure_disks_should_use_standard_snapshots.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_virtual_machine_boot_diagnostics.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_unused_load_balancers.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_automatic_os_upgrades.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_zone_redundant_virtual_machine_scale_sets.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_associated_load_balancers.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_virtual_machine_access_using_microsoft_entra_id_authentication.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_instance_termination_notifications_for_virtual_machine_scale_sets.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_system_assigned_managed_identities.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_usage_of_byok_for_disk_volumes_encryption.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_usage_of_endpoint_protection.yaml processed successfully. -./baseline/azure/virtual_machine/azure_server_side_encryption_for_boot_disk_using_cmk.yaml processed successfully. -./baseline/azure/virtual_machine/azure_disk_encryption_for_unattached_disk_volumes.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_just_in_time_access_for_virtual_machines.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_desired_vm_sku_sizes.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_configure_health_monitoring.yaml processed successfully. -./baseline/azure/virtual_machine/azure_server_side_encryption_for_non_boot_disk_using_cmk.yaml processed successfully. -./baseline/azure/virtual_machine/azure_check_for_automatic_instance_repairs.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_ssh_access.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_telnet_access.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_postgresql_database_access.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_smtp_access.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_oracle_database_access.yaml processed successfully. -./baseline/azure/network/azure_review_network_interfaces_with_ip_forwarding_enabled.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_mysql_database_access.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_netbios_access.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_rdp_access.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_mongodb_access.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_udp_access.yaml processed successfully. -./baseline/azure/network/azure_enable_azure_network_watcher.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_mssql_access.yaml processed successfully. -./baseline/azure/network/azure_check_for_unrestricted_rpc_access.yaml processed successfully. -./baseline/azure/network/azure_enable_ddos_standard_protection_for_virtual_networks.yaml processed successfully. -./baseline/azure/aks/azure_secure_access_to_kubernetes_api_server_using_authorized_ip_address_ranges.yaml processed successfully. -./baseline/azure/aks/azure_enable_defender_for_cloud_for_aks_clusters.yaml processed successfully. -./baseline/azure/aks/azure_check_for_kubernetes_version.yaml processed successfully. -./baseline/azure/aks/azure_use_azure_cni_add_on_for_managing_network_resources.yaml processed successfully. -./baseline/azure/aks/azure_use_user_assigned_managed_identities_for_aks_clusters.yaml processed successfully. -./baseline/azure/aks/azure_enable_kubernetes_role_based_access_control.yaml processed successfully. -./baseline/azure/aks/azure_use_microsoft_entra_id_integration_for_aks_clusters.yaml processed successfully. -./baseline/azure/aks/azure_kubernetes_api_version.yaml processed successfully. -./baseline/azure/aks/azure_use_network_contributor_role_for_managing_azure_network_resources.yaml processed successfully. -./baseline/azure/aks/azure_use_system_assigned_managed_identities_for_aks_clusters.yaml processed successfully. -./baseline/azure/cosmosdb/azure_enable_automatic_failover.yaml processed successfully. -./baseline/azure/app_services/azure_disable_plain_ftp_deployment.yaml processed successfully. -./baseline/azure/sql/azure_enable_auditing_for_sql_servers.yaml processed successfully. -./baseline/azure/sql/azure_check_for_unrestricted_sql_database_access.yaml processed successfully. -./baseline/azure/sql/azure_enable_vulnerability_assessment_email_notifications_for_admins_and_subscription_owners.yaml processed successfully. -./baseline/azure/sql/azure_check_for_sufficient_point_in_time_restore_pitr_backup_retention_period.yaml processed successfully. -./baseline/azure/sql/azure_enable_in_transit_encryption_for_mysql_servers.yaml processed successfully. -./baseline/azure/sql/azure_enable_auto_failover_groups.yaml processed successfully. -./baseline/azure/sql/azure_enable_transparent_data_encryption_for_sql_managed_instance_using_customer_managed_keys.yaml processed successfully. -./baseline/azure/sql/azure_enable_all_types_of_threat_detection_on_sql_servers.yaml processed successfully. -./baseline/azure/sql/azure_sql_auditing_retention.yaml processed successfully. -./baseline/azure/sql/azure_enable_vulnerability_assessment_periodic_recurring_scans.yaml processed successfully. -./baseline/azure/sql/azure_enable_automatic_tuning_for_sql_database_servers.yaml processed successfully. -./baseline/azure/sql/azure_configure_emails_for_vulnerability_assessment_scan_reports_and_alerts.yaml processed successfully. -./baseline/azure/sql/azure_check_for_publicly_accessible_sql_servers.yaml processed successfully. -./baseline/azure/sql/azure_use_microsoft_entra_admin_for_sql_authentication.yaml processed successfully. -./baseline/azure/sql/azure_use_byok_for_transparent_data_encryption.yaml processed successfully. -./baseline/azure/sql/azure_enable_vulnerability_assessment_for_microsoft_sql_servers.yaml processed successfully. -./baseline/azure/sql/azure_restrict_default_network_access_for_azure_cosmos_db_accounts.yaml processed successfully. -./baseline/azure/sql/azure_configure_audit_action_group_for_sql_server_auditing.yaml processed successfully. -./baseline/azure/sql/azure_advanced_data_security_for_sql_servers.yaml processed successfully. -./baseline/shared/cost/kaytu_mom_cost_growth_15.yaml processed successfully. -./baseline/shared/cost/kaytu_connection_mom_cost_growth.yaml processed successfully. -./baseline/aws/acm_certificate/aws_acm_certificates_with_wildcard_domain_names.yaml processed successfully. -./baseline/aws/acm_certificate/aws_acm_certificates_renewal_7_days_before_expiration.yaml processed successfully. -./baseline/aws/acm_certificate/aws_acm_certificates_validity.yaml processed successfully. -./baseline/aws/acm_certificate/aws_acm_certificate_expired.yaml processed successfully. -./baseline/aws/load_balancer/aws_elbv2_glb_minimum_number_of_ec2_target_instances.yaml processed successfully. -./baseline/aws/load_balancer/aws_unused_elastic_load_balancers.yaml processed successfully. -./baseline/aws/load_balancer/aws_internet_facing_elbs.yaml processed successfully. -./baseline/aws/load_balancer/aws_elbv2_alb_security_group.yaml processed successfully. -./baseline/aws/load_balancer/aws_enable_amazon_waf_integration_for_application_load_balancers.yaml processed successfully. -./baseline/aws/load_balancer/aws_enable_support_for_grpc_protocol.yaml processed successfully. -./baseline/aws/load_balancer/aws_elbv2_access_log.yaml processed successfully. -./baseline/aws/load_balancer/aws_configure_multiple_availability_zones_for_load_balancers.yaml processed successfully. -./baseline/aws/load_balancer/aws_elbv2_alb_security_policy.yaml processed successfully. -./baseline/aws/load_balancer/aws_elb_access_log.yaml processed successfully. -./baseline/aws/load_balancer/aws_elb_cross_zone_load_balancing_enabled.yaml processed successfully. -./baseline/aws/load_balancer/aws_enable_cross_zone_load_balancing.yaml processed successfully. -./baseline/aws/load_balancer/aws_internet_facing_elbv2s.yaml processed successfully. -./baseline/aws/load_balancer/aws_elbv2_alb_listener_security.yaml processed successfully. -./baseline/aws/load_balancer/aws_unused_application_load_balancers.yaml processed successfully. -./baseline/aws/load_balancer/aws_elbv2_elastic_load_balancing_deletion_protection.yaml processed successfully. -./baseline/aws/load_balancer/aws_enable_http_to_https_redirect_for_application_load_balancers.yaml processed successfully. -./baseline/aws/load_balancer/aws_unused_gateway_load_balancers.yaml processed successfully. -./baseline/aws/load_balancer/aws_configure_http_desync_mitigation_mode_for_application_load_balancers.yaml processed successfully. -./baseline/aws/load_balancer/aws_elb_connection_draining_enabled.yaml processed successfully. -./baseline/aws/load_balancer/aws_enable_deletion_protection.yaml processed successfully. -./baseline/aws/load_balancer/aws_elbv2_nlb_listener_security.yaml processed successfully. -./baseline/aws/load_balancer/aws_elbv2_alb_minimum_number_of_ec2_target_instances.yaml processed successfully. -./baseline/aws/load_balancer/aws_elb_insecure_ssl_protocols.yaml processed successfully. -./baseline/aws/opensearch/aws_encryption_at_rest.yaml processed successfully. -./baseline/aws/opensearch/aws_enable_audit_logs.yaml processed successfully. -./baseline/aws/opensearch/aws_opensearch_version.yaml processed successfully. -./baseline/aws/opensearch/aws_opensearch_domain_in_vpc.yaml processed successfully. -./baseline/aws/opensearch/aws_opensearch_domain_encrypted_with_kms_cmks.yaml processed successfully. -./baseline/aws/opensearch/aws_enable_in_transit_encryption.yaml processed successfully. -./baseline/aws/opensearch/aws_tls_security_policy_version.yaml processed successfully. -./baseline/aws/opensearch/aws_opensearch_slow_logs.yaml processed successfully. -./baseline/aws/opensearch/aws_opensearch_node_to_node_encryption.yaml processed successfully. -./baseline/aws/opensearch/aws_opensearch_zone_awareness_enabled.yaml processed successfully. -./baseline/aws/opensearch/aws_opensearch_dedicated_master_enabled.yaml processed successfully. -./baseline/aws/opensearch/aws_opensearch_domain_exposed.yaml processed successfully. -./baseline/aws/opensearch/aws_opensearch_accessible_only_from_safelisted_ip_addresses.yaml processed successfully. -./baseline/aws/ecr/aws_ecr_repository_exposed.yaml processed successfully. -./baseline/aws/ecr/aws_lifecycle_policy_in_use.yaml processed successfully. -./baseline/aws/ecr/aws_enable_scan_on_push_for_ecr_container_images.yaml processed successfully. -./baseline/aws/ecr/aws_enable_cross_region_replication.yaml processed successfully. -./baseline/aws/dynamoDb/aws_unused_dynamodb_table.yaml processed successfully. -./baseline/aws/ecs/aws_ecs_task_log_driver_in_use.yaml processed successfully. -./baseline/aws/ecs/aws_enable_cloudwatch_container_insights.yaml processed successfully. -./baseline/aws/ecs/aws_check_for_amazon_ecs_service_placement_strategy.yaml processed successfully. -./baseline/aws/ecs/aws_check_for_ecs_container_instance_agent_version.yaml processed successfully. -./baseline/aws/ecs/aws_check_for_fargate_platform_version.yaml processed successfully. -./baseline/aws/fsx/aws_use_kms_customer_master_keys_for_fsx_windows_file_server_file_systems.yaml processed successfully. -./baseline/aws/ebs/aws_use_io2_not_io1.yaml processed successfully. -./baseline/aws/ebs/aws_ebs_encrypted.yaml processed successfully. -./baseline/aws/ebs/aws_ebs_snapshot_encrypted.yaml processed successfully. -./baseline/aws/ebs/aws_ebs_volume_unused.yaml processed successfully. -./baseline/aws/ebs/aws_ebs_public_snapshots.yaml processed successfully. -./baseline/aws/ebs/aws_use_gp3_not_gp2.yaml processed successfully. -./baseline/aws/ebs/aws_ebs_volumes_too_old_snapshots.yaml processed successfully. -./baseline/aws/ebs/aws_ebs_volumes_attached_to_stopped_ec2_instances.yaml processed successfully. -./baseline/aws/ebs/aws_ebs_encrypted_with_kms_customer_master_keys.yaml processed successfully. -./baseline/aws/IAM/aws_ssh_public_keys_rotated_45_days.yaml processed successfully. -./baseline/aws/IAM/aws_iam_user_policies.yaml processed successfully. -./baseline/aws/IAM/aws_root_mfa_enabled.yaml processed successfully. -./baseline/aws/IAM/aws_iam_policies_with_effect_set_to_allow_and_notaction.yaml processed successfully. -./baseline/aws/IAM/aws_iam_users_with_administrative_privileges.yaml processed successfully. -./baseline/aws/IAM/aws_iam_group_with_inline_policies.yaml processed successfully. -./baseline/aws/IAM/aws_iam_access_analyzer_in_use.yaml processed successfully. -./baseline/aws/IAM/aws_mfa_device_deactivated.yaml processed successfully. -./baseline/aws/IAM/aws_inactive_iam_console_user.yaml processed successfully. -./baseline/aws/IAM/aws_iam_users_unauthorized_to_edit_access_policies.yaml processed successfully. -./baseline/aws/IAM/aws_root_account_access_keys_present.yaml processed successfully. -./baseline/aws/IAM/aws_check_for_overly_permissive_iam_group_policies.yaml processed successfully. -./baseline/aws/IAM/aws_enforce_infrastructure_as_code_using_iam_policies.yaml processed successfully. -./baseline/aws/IAM/aws_credentials_last_used.yaml processed successfully. -./baseline/aws/IAM/aws_allow_iam_users_to_change_their_own_password.yaml processed successfully. -./baseline/aws/IAM/aws_check_for_individual_iam_users.yaml processed successfully. -./baseline/aws/IAM/aws_unnecessary_ssh_public_keys.yaml processed successfully. -./baseline/aws/IAM/aws_unnecessary_access_keys.yaml processed successfully. -./baseline/aws/IAM/aws_expired_ssl_tls_certificate.yaml processed successfully. -./baseline/aws/IAM/aws_access_keys_during_initial_iam_user_setup.yaml processed successfully. -./baseline/aws/IAM/aws_iam_user_password_expiry_30_days.yaml processed successfully. -./baseline/aws/IAM/aws_iam_password_policy.yaml processed successfully. -./baseline/aws/IAM/aws_approved_ecs_execute_command_access.yaml processed successfully. -./baseline/aws/IAM/aws_ssl_tls_certificate_expiry_30_days.yaml processed successfully. -./baseline/aws/IAM/aws_unapproved_iam_policy_in_use.yaml processed successfully. -./baseline/aws/IAM/aws_iam_support_role.yaml processed successfully. -./baseline/aws/IAM/aws_enable_mfa_for_iam_users_with_console_password.yaml processed successfully. -./baseline/aws/IAM/aws_ssl_tls_certificate_expiry_x_days.yaml processed successfully. -./baseline/aws/IAM/aws_unused_iam_group.yaml processed successfully. -./baseline/aws/IAM/aws_canary_access_token.yaml processed successfully. -./baseline/aws/IAM/aws_check_for_untrusted_cross_account_iam_roles.yaml processed successfully. -./baseline/aws/IAM/aws_multi_account_centralized_management.yaml processed successfully. -./baseline/aws/IAM/aws_iam_user_with_password_and_access_keys.yaml processed successfully. -./baseline/aws/IAM/aws_root_account_credentials_usage.yaml processed successfully. -./baseline/aws/IAM/aws_iam_groups_with_administrative_privileges.yaml processed successfully. -./baseline/aws/IAM/aws_ec2_purchase_restriction.yaml processed successfully. -./baseline/aws/IAM/aws_pre_heartbleed_server_certificates.yaml processed successfully. -./baseline/aws/IAM/aws_cross_account_access_lacks_external_id_and_mfa.yaml processed successfully. -./baseline/aws/IAM/aws_access_keys_rotated_x_days.yaml processed successfully. -./baseline/aws/IAM/aws_iam_server_certificate_size.yaml processed successfully. -./baseline/aws/IAM/aws_check_for_iam_user_group_membership.yaml processed successfully. -./baseline/aws/IAM/aws_iam_access_analyzer_findings.yaml processed successfully. -./baseline/aws/IAM/aws_valid_iam_identity_providers.yaml processed successfully. -./baseline/aws/IAM/aws_access_keys_rotated_45_days.yaml processed successfully. -./baseline/aws/IAM/aws_iam_user_password_expiry_x_days.yaml processed successfully. -./baseline/aws/IAM/aws_root_account_active_signing_certificates.yaml processed successfully. -./baseline/aws/IAM/aws_check_that_only_safelisted_iam_users_exist.yaml processed successfully. -./baseline/aws/IAM/aws_account_alternate_contacts.yaml processed successfully. -./baseline/aws/IAM/aws_hardware_mfa_for_aws_root_account.yaml processed successfully. -./baseline/aws/IAM/aws_iam_role_policy_too_permissive.yaml processed successfully. -./baseline/aws/IAM/aws_ssh_public_keys_rotated_x_days.yaml processed successfully. -./baseline/aws/IAM/aws_iam_policies_with_full_administrative_privileges.yaml processed successfully. -./baseline/aws/IAM/aws_iam_user_password_expiry_7_days.yaml processed successfully. -./baseline/aws/IAM/aws_attach_policy_to_iam_roles_associated_with_app_tier_ec2_instances.yaml processed successfully. -./baseline/aws/IAM/aws_ssh_public_keys_rotated_90_days.yaml processed successfully. -./baseline/aws/IAM/aws_iam_user_no_policies.yaml processed successfully. -./baseline/aws/eks/aws_enable_envelope_encryption_for_eks_kubernetes_secrets.yaml processed successfully. -./baseline/aws/eks/aws_eks_cluster_endpoint_public_access.yaml processed successfully. -./baseline/aws/eks/aws_enable_cloudtrail_logging_for_kubernetes_api_calls.yaml processed successfully. -./baseline/aws/eks/aws_kubernetes_cluster_version.yaml processed successfully. -./baseline/aws/eks/aws_use_aws_managed_policy_to_manage_networking_resources.yaml processed successfully. -./baseline/aws/eks/aws_kubernetes_cluster_logging.yaml processed successfully. -./baseline/aws/eks/aws_disable_remote_access_to_eks_cluster_node_groups.yaml processed successfully. -./baseline/aws/eks/aws_eks_security_groups.yaml processed successfully. -./baseline/aws/eks/aws_eks_cluster_node_group_iam_role_policies.yaml processed successfully. -./baseline/aws/eks/aws_use_aws_managed_policy_to_access_amazon_ecr_repositories.yaml processed successfully. -./baseline/aws/eks/aws_use_oidc_provider_for_authenticating_kubernetes_api_calls.yaml processed successfully. -./baseline/aws/eks/aws_use_aws_managed_policy_to_manage_aws_resources.yaml processed successfully. -./baseline/aws/vpc/aws_managed_nat_gateway_in_use.yaml processed successfully. -./baseline/aws/vpc/aws_unrestricted_network_acl_outbound_traffic.yaml processed successfully. -./baseline/aws/vpc/aws_vpc_endpoint_cross_account_access.yaml processed successfully. -./baseline/aws/vpc/aws_unrestricted_network_acl_inbound_traffic.yaml processed successfully. -./baseline/aws/vpc/aws_vpc_flow_logs_enabled.yaml processed successfully. -./baseline/aws/vpc/aws_vpc_peering_connections_to_accounts_outside_aws_organization.yaml processed successfully. -./baseline/aws/vpc/aws_unrestricted_inbound_traffic_on_remote_server_administration_ports.yaml processed successfully. -./baseline/aws/vpc/aws_vpc_endpoints_in_use.yaml processed successfully. -./baseline/aws/vpc/aws_vpc_endpoint_exposed.yaml processed successfully. -./baseline/aws/backup/aws_dynamodb_instances_have_backup_withing_48_hours.yaml processed successfully. -./baseline/aws/backup/aws_ec2_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml processed successfully. -./baseline/aws/backup/aws_check_for_protected_amazon_backup_resource_types.yaml processed successfully. -./baseline/aws/backup/aws_efs_files_have_backup_with_lifecyclepolicy_above_35_days.yaml processed successfully. -./baseline/aws/backup/aws_efs_files_have_backup_withing_48_hours.yaml processed successfully. -./baseline/aws/backup/aws_use_kms_customer_master_keys_for_aws_backup.yaml processed successfully. -./baseline/aws/backup/aws_enable_alert_notifications_for_failed_backup_jobs.yaml processed successfully. -./baseline/aws/backup/aws_backup_service_lifecycle_configuration.yaml processed successfully. -./baseline/aws/backup/aws_rds_database_instances_must_have_a_minimum_acceptable_restore_time.yaml processed successfully. -./baseline/aws/backup/aws_configure_aws_backup_vault_access_policy.yaml processed successfully. -./baseline/aws/backup/aws_ebs_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml processed successfully. -./baseline/aws/backup/aws_ec2_instances_have_backup_withing_48_hours.yaml processed successfully. -./baseline/aws/backup/aws_dynamodb_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml processed successfully. -./baseline/aws/backup/aws_rds_database_instances_have_a_minimum_acceptable_backup_policy.yaml processed successfully. -./baseline/aws/backup/aws_ebs_instances_have_backup_withing_rpo_period.yaml processed successfully. -./baseline/aws/rds/aws_rds_default_port.yaml processed successfully. -./baseline/aws/rds/aws_rds_instance_counts.yaml processed successfully. -./baseline/aws/rds/aws_rds_public_snapshots.yaml processed successfully. -./baseline/aws/rds/aws_instance_deletion_protection.yaml processed successfully. -./baseline/aws/rds/aws_rds_desired_instance_type.yaml processed successfully. -./baseline/aws/rds/aws_rds_encrypted_with_kms_customer_master_keys.yaml processed successfully. -./baseline/aws/rds/aws_rotate_ssltls_certificates_for_database_instances.yaml processed successfully. -./baseline/aws/rds/aws_rds_encryption_enabled.yaml processed successfully. -./baseline/aws/rds/aws_aurora_database_cluster_activity_streams.yaml processed successfully. -./baseline/aws/rds/aws_enable_rds_snapshot_encryption.yaml processed successfully. -./baseline/aws/rds/aws_enable_aurora_cluster_copy_tags_to_snapshots.yaml processed successfully. -./baseline/aws/rds/aws_db_instance_generation.yaml processed successfully. -./baseline/aws/rds/aws_aurora_database_instance_accessibility.yaml processed successfully. -./baseline/aws/rds/aws_log_exports.yaml processed successfully. -./baseline/aws/rds/aws_instance_level_events_subscriptions.yaml processed successfully. -./baseline/aws/rds/aws_rds_db_instance_no_public_subnet.yaml processed successfully. -./baseline/aws/rds/aws_rds_multi_az.yaml processed successfully. -./baseline/aws/rds/aws_security_groups_events_subscriptions.yaml processed successfully. -./baseline/aws/rds/aws_backtrack.yaml processed successfully. -./baseline/aws/rds/aws_enable_instance_storage_auto_scaling.yaml processed successfully. -./baseline/aws/rds/aws_enable_serverless_log_exports.yaml processed successfully. -./baseline/aws/rds/aws_rds_publicly_accessible.yaml processed successfully. -./baseline/aws/rds/aws_cluster_deletion_protection.yaml processed successfully. -./baseline/aws/rds/aws_performance_insights.yaml processed successfully. -./baseline/aws/rds/aws_rds_automated_backups_enabled.yaml processed successfully. -./baseline/aws/rds/aws_use_aws_backup_service_in_use_for_amazon_rds.yaml processed successfully. -./baseline/aws/rds/aws_enable_aws_rds_transport_encryption.yaml processed successfully. -./baseline/aws/rds/aws_rds_event_notifications.yaml processed successfully. -./baseline/aws/efs/aws_kms_customer_master_keys_for_efs_encryption.yaml processed successfully. -./baseline/aws/efs/aws_efs_encryption_enabled.yaml processed successfully. -./baseline/aws/ec2/aws_unused_aws_ec2_key_pairs.yaml processed successfully. -./baseline/aws/ec2/aws_ec2_instance_in_vpc.yaml processed successfully. -./baseline/aws/ec2/aws_default_security_group_unrestricted.yaml processed successfully. -./baseline/aws/ec2/aws_ec2_ami_too_old.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_ssh_access.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_oracle_access.yaml processed successfully. -./baseline/aws/ec2/aws_require_imdsv2_for_ec2_instances.yaml processed successfully. -./baseline/aws/ec2/aws_disable_public_ip_address_assignment_for_ec2_instances.yaml processed successfully. -./baseline/aws/ec2/aws_unused_elastic_network_interfaces.yaml processed successfully. -./baseline/aws/ec2/aws_ami_encryption.yaml processed successfully. -./baseline/aws/ec2/aws_ec2_desired_instance_type.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_mongodb_access.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_cifs_access.yaml processed successfully. -./baseline/aws/ec2/aws_security_group_name_prefixed_with_launch_wizard.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_icmp_access.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_opensearch_access.yaml processed successfully. -./baseline/aws/ec2/aws_security_group_port_range.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_netbios_access.yaml processed successfully. -./baseline/aws/ec2/aws_ec2_instance_not_in_public_subnet.yaml processed successfully. -./baseline/aws/ec2/aws_unused_ami.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_mysql_access.yaml processed successfully. -./baseline/aws/ec2/aws_ec2_instances_with_multiple_elastic_network_interfaces.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_mssql_access.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_security_group_ingress_on_uncommon_ports.yaml processed successfully. -./baseline/aws/ec2/aws_ec2_instance_naming_conventions.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_rpc_access.yaml processed successfully. -./baseline/aws/ec2/aws_default_security_groups_in_use.yaml processed successfully. -./baseline/aws/ec2/aws_unrestricted_smtp_access.yaml processed successfully. -./baseline/aws/ec2/aws_ec2_instance_termination_protection.yaml processed successfully. -./baseline/aws/ec2/aws_ec2_instance_too_old.yaml processed successfully. -./baseline/aws/ec2/aws_unassociated_elastic_ip_addresses.yaml processed successfully. -./baseline/aws/ec2/aws_publicly_shared_ami.yaml processed successfully. -./aws/aws_foundational_security_opensearch_1.yaml processed successfully. -./aws/aws_cis_v140_3_9.yaml processed successfully. -./aws/aws_foundational_security_cloudfront_8.yaml processed successfully. -./aws/aws_cis_v200_2_1_2.yaml processed successfully. -./aws/aws_ec2_instance_in_vpc.yaml processed successfully. -./aws/aws_foundational_security_dynamodb_1.yaml processed successfully. -./aws/aws_autoscaling_use_multiple_instance_types_in_multiple_az.yaml processed successfully. -./aws/aws_cis_v130_3_11.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_2_1.yaml processed successfully. -./aws/aws_cis_v300_1_7.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_8.yaml processed successfully. -./aws/aws_ec2_network_interface_unused.yaml processed successfully. -./aws/aws_foundational_security_s3_19.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_write_permission_on_critical_s3_configuration.yaml processed successfully. -./aws/aws_opensearch_domain_audit_logging_enabled.yaml processed successfully. -./aws/aws_redshift_cluster_no_default_admin_name.yaml processed successfully. -./aws/aws_iam_account_password_policy_min_length_14.yaml processed successfully. -./aws/aws_secretsmanager_secret_encrypted_with_kms_cmk.yaml processed successfully. -./aws/aws_mandatory_sql_ebs_volume_mandatory.yaml processed successfully. -./aws/aws_iam_user_console_access_mfa_enabled.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_10.yaml processed successfully. -./aws/aws_cis_v200_5_5.yaml processed successfully. -./aws/aws_es_domain_dedicated_master_nodes_min_3.yaml processed successfully. -./aws/aws_cis_v150_3_3.yaml processed successfully. -./aws/aws_iam_access_analyzer_enabled.yaml processed successfully. -./aws/aws_cis_v200_1_12.yaml processed successfully. -./aws/aws_account_part_of_organizations.yaml processed successfully. -./aws/aws_vpc_security_group_restrict_ingress_redis_port.yaml processed successfully. -./aws/aws_cis_v120_3_14.yaml processed successfully. -./aws/aws_cis_v300_1_21.yaml processed successfully. -./aws/aws_cis_v200_2_4_1.yaml processed successfully. -./aws/aws_lambda_function_dead_letter_queue_configured.yaml processed successfully. -./aws/aws_backup_vault_region_configured.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_cloud_log_tampering_access.yaml processed successfully. -./aws/aws_iam_user_unused_credentials_45.yaml processed successfully. -./aws/aws_cis_v200_1_2.yaml processed successfully. -./aws/aws_foundational_security_ecs_4.yaml processed successfully. -./aws/aws_cis_v200_2_3_3.yaml processed successfully. -./aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_full_packets.yaml processed successfully. -./aws/aws_iam_account_password_policy_strong_min_reuse_24.yaml processed successfully. -./aws/aws_elb_application_lb_waf_enabled.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_11.yaml processed successfully. -./aws/aws_cis_v130_1_16.yaml processed successfully. -./aws/aws_foundational_security_docdb_1.yaml processed successfully. -./aws/aws_kinesis_stream_server_side_encryption_enabled.yaml processed successfully. -./aws/aws_cis_v150_2_1_1.yaml processed successfully. -./aws/aws_cis_v300_3_6.yaml processed successfully. -./aws/aws_s3_bucket_lifecycle_policy_enabled.yaml processed successfully. -./aws/aws_foundational_security_s3_6.yaml processed successfully. -./aws/aws_lambda_function_cloudtrail_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_iam_21.yaml processed successfully. -./aws/aws_ebs_volume_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_cis_v120_1_13.yaml processed successfully. -./aws/aws_foundational_security_redshift_2.yaml processed successfully. -./aws/aws_cis_v150_1_2.yaml processed successfully. -./aws/aws_mandatory_sql_accessanalyzer_analyzer_mandatory.yaml processed successfully. -./aws/aws_vpc_security_group_allows_ingress_authorized_ports.yaml processed successfully. -./aws/aws_athena_workgroup_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_iam_user_group_role_cloudshell_fullaccess_restricted.yaml processed successfully. -./aws/aws_config_enabled_all_regions.yaml processed successfully. -./aws/aws_iam_user_unused_credentials_90.yaml processed successfully. -./aws/aws_foundational_security_redshift_10.yaml processed successfully. -./aws/aws_mandatory_sql_ssm_parameter_mandatory.yaml processed successfully. -./aws/aws_s3_bucket_default_encryption_enabled_kms.yaml processed successfully. -./aws/aws_cis_v150_5_5.yaml processed successfully. -./aws/aws_s3_bucket_event_notifications_enabled.yaml processed successfully. -./aws/aws_cis_v200_3_3.yaml processed successfully. -./aws/aws_ec2_instance_publicly_accessible_iam_profile_attached.yaml processed successfully. -./aws/aws_foundational_security_rds_10.yaml processed successfully. -./aws/aws_cloudfront_distribution_use_secure_cipher.yaml processed successfully. -./aws/aws_cis_v150_1_18.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_1_4.yaml processed successfully. -./aws/aws_cis_v130_3_2.yaml processed successfully. -./aws/aws_foundational_security_elb_2.yaml processed successfully. -./aws/aws_autoscaling_ec2_launch_configuration_no_sensitive_data.yaml processed successfully. -./aws/aws_foundational_security_iam_2.yaml processed successfully. -./aws/aws_cis_v140_3_5.yaml processed successfully. -./aws/aws_cloudformation_stack_output_no_secrets.yaml processed successfully. -./aws/aws_cis_v140_2_1_4.yaml processed successfully. -./aws/aws_foundational_security_cloudfront_4.yaml processed successfully. -./aws/aws_mandatory_sql_codecommit_repository_mandatory.yaml processed successfully. -./aws/aws_foundational_security_es_6.yaml processed successfully. -./aws/aws_ec2_instance_uses_imdsv2.yaml processed successfully. -./aws/aws_mandatory_sql_eventbridge_rule_mandatory.yaml processed successfully. -./aws/aws_mandatory_sql_cloudfront_distribution_mandatory.yaml processed successfully. -./aws/aws_cis_v130_1_20.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_new_group_creation_with_attached_policy_access.yaml processed successfully. -./aws/aws_foundational_security_neptune_3.yaml processed successfully. -./aws/aws_cis_v300_4_14.yaml processed successfully. -./aws/aws_opensearch_domain_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_foundational_security_rds_8.yaml processed successfully. -./aws/aws_cloudtrail_trail_logs_encrypted_with_kms_cmk.yaml processed successfully. -./aws/aws_elb_application_lb_redirect_http_request_to_https.yaml processed successfully. -./aws/aws_cis_v300_2_1_3.yaml processed successfully. -./aws/aws_mandatory_sql_redshift_cluster_mandatory.yaml processed successfully. -./aws/aws_foundational_security_ecs_8.yaml processed successfully. -./aws/aws_foundational_security_codebuild_1.yaml processed successfully. -./aws/aws_foundational_security_sns_2.yaml processed successfully. -./aws/aws_ec2_classic_lb_connection_draining_enabled.yaml processed successfully. -./aws/aws_vpc_in_more_than_one_region.yaml processed successfully. -./aws/aws_cloudtrail_trail_integrated_with_logs.yaml processed successfully. -./aws/aws_sagemaker_endpoint_configuration_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_cloudfront_distribution_custom_origins_encryption_in_transit_enabled.yaml processed successfully. -./aws/aws_foundational_security_elasticbeanstalk_1.yaml processed successfully. -./aws/aws_cis_v140_1_4.yaml processed successfully. -./aws/aws_docdb_cluster_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_redshift_cluster_maintenance_settings_check.yaml processed successfully. -./aws/aws_mandatory_sql_eks_cluster_mandatory.yaml processed successfully. -./aws/aws_opensearch_domain_updated_with_latest_service_software_version.yaml processed successfully. -./aws/aws_rds_db_instance_postgres_not_exposed_to_local_file_read_vulnerability.yaml processed successfully. -./aws/aws_es_domain_error_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_autoscaling_3.yaml processed successfully. -./aws/aws_mandatory_sql_kinesis_firehose_delivery_stream_mandatory.yaml processed successfully. -./aws/aws_cis_v130_1_3.yaml processed successfully. -./aws/aws_cis_compute_service_v100_5_2.yaml processed successfully. -./aws/aws_gatewayv2_stage_access_logging_enabled.yaml processed successfully. -./aws/aws_cis_v140_1_11.yaml processed successfully. -./aws/aws_elasticache_cluster_auto_minor_version_upgrade_enabled.yaml processed successfully. -./aws/aws_s3_bucket_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_elasticache_6.yaml processed successfully. -./aws/aws_cis_v130_5_4.yaml processed successfully. -./aws/aws_iam_policy_no_full_access_to_cloudtrail.yaml processed successfully. -./aws/aws_backup_plan_region_configured.yaml processed successfully. -./aws/aws_cis_v140_2_2_1.yaml processed successfully. -./aws/aws_cis_v300_2_3_2.yaml processed successfully. -./aws/aws_rds_db_cluster_multiple_az_enabled.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_6.yaml processed successfully. -./aws/aws_cis_v300_1_17.yaml processed successfully. -./aws/aws_glue_job_bookmarks_encryption_enabled.yaml processed successfully. -./aws/aws_cis_v140_4_7.yaml processed successfully. -./aws/aws_cis_v150_1_14.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_data_destruction_access.yaml processed successfully. -./aws/aws_mandatory_sql_vpc_network_acl_mandatory.yaml processed successfully. -./aws/aws_foundational_security_waf_1.yaml processed successfully. -./aws/aws_iam_policy_no_star_star.yaml processed successfully. -./aws/aws_cloudfront_distribution_sni_enabled.yaml processed successfully. -./aws/aws_vpc_subnet_auto_assign_public_ip_disabled.yaml processed successfully. -./aws/aws_codebuild_project_environment_privileged_mode_disabled.yaml processed successfully. -./aws/aws_lambda_function_restrict_public_access.yaml processed successfully. -./aws/aws_foundational_security_ecs_12.yaml processed successfully. -./aws/aws_cis_v150_1_15.yaml processed successfully. -./aws/aws_cloudfront_distribution_logging_enabled.yaml processed successfully. -./aws/aws_mandatory_sql_codebuild_project_mandatory.yaml processed successfully. -./aws/aws_vpc_security_group_allows_ingress_to_cassandra_ports.yaml processed successfully. -./aws/aws_efs_access_point_enforce_root_directory.yaml processed successfully. -./aws/aws_cis_v300_1_16.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_7.yaml processed successfully. -./aws/aws_log_metric_filter_iam_policy.yaml processed successfully. -./aws/aws_ecr_repository_prohibit_public_access.yaml processed successfully. -./aws/aws_foundational_security_acm_1.yaml processed successfully. -./aws/aws_log_metric_filter_route_table.yaml processed successfully. -./aws/aws_cis_v120_1_8.yaml processed successfully. -./aws/aws_cis_v300_2_3_3.yaml processed successfully. -./aws/aws_mandatory_sql_kms_key_mandatory.yaml processed successfully. -./aws/aws_redshift_cluster_enhanced_vpc_routing_enabled.yaml processed successfully. -./aws/aws_s3_bucket_restrict_public_read_access.yaml processed successfully. -./aws/aws_ecs_cluster_no_registered_container_instance.yaml processed successfully. -./aws/aws_foundational_security_kms_3.yaml processed successfully. -./aws/aws_elb_application_classic_network_lb_prohibit_public_access.yaml processed successfully. -./aws/aws_foundational_security_elasticache_7.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_passrole_and_lambda_invoke_function_access.yaml processed successfully. -./aws/aws_sns_topic_policy_prohibit_subscription_access.yaml processed successfully. -./aws/aws_emr_cluster_kerberos_enabled.yaml processed successfully. -./aws/aws_cis_v140_5_2.yaml processed successfully. -./aws/aws_cis_v140_1_10.yaml processed successfully. -./aws/aws_foundational_security_autoscaling_2.yaml processed successfully. -./aws/aws_cloudformation_stack_termination_protection_enabled.yaml processed successfully. -./aws/aws_dms_endpoint_ssl_configured.yaml processed successfully. -./aws/aws_s3_bucket_restrict_public_write_access.yaml processed successfully. -./aws/aws_elasticache_replication_group_encryption_in_transit_enabled.yaml processed successfully. -./aws/aws_cis_v130_1_2.yaml processed successfully. -./aws/aws_log_metric_filter_root_login.yaml processed successfully. -./aws/aws_foundational_security_ec2_7.yaml processed successfully. -./aws/aws_mandatory_sql_cloudwatch_alarm_mandatory.yaml processed successfully. -./aws/aws_elasticache_cluster_no_default_subnet_group.yaml processed successfully. -./aws/aws_rds_db_cluster_iam_authentication_enabled.yaml processed successfully. -./aws/aws_elb_application_gateway_network_lb_multiple_az_configured.yaml processed successfully. -./aws/aws_cis_v140_1_5.yaml processed successfully. -./aws/aws_foundational_security_secretsmanager_4.yaml processed successfully. -./aws/aws_ec2_instance_not_use_multiple_enis.yaml processed successfully. -./aws/aws_cis_v150_4_16.yaml processed successfully. -./aws/aws_ec2_instance_attached_ebs_volume_delete_on_termination_enabled.yaml processed successfully. -./aws/aws_elb_network_lb_tls_listener_security_policy_configured.yaml processed successfully. -./aws/aws_neptune_db_cluster_automated_backup_enabled.yaml processed successfully. -./aws/aws_foundational_security_ecs_9.yaml processed successfully. -./aws/aws_foundational_security_rds_9.yaml processed successfully. -./aws/aws_dynamodb_table_encrypted_with_kms.yaml processed successfully. -./aws/aws_api_gateway_method_request_parameter_validated.yaml processed successfully. -./aws/aws_ec2_instance_not_older_than_180_days.yaml processed successfully. -./aws/aws_wafv2_web_acl_rule_attached.yaml processed successfully. -./aws/aws_mandatory_sql_wafv2_ip_set_mandatory.yaml processed successfully. -./aws/aws_foundational_security_rds_27.yaml processed successfully. -./aws/aws_foundational_security_elb_12.yaml processed successfully. -./aws/aws_cis_v300_2_1_2.yaml processed successfully. -./aws/aws_foundational_security_ec2_51.yaml processed successfully. -./aws/aws_directory_service_certificate_expires_90_days.yaml processed successfully. -./aws/aws_vpc_network_acl_unused.yaml processed successfully. -./aws/aws_cis_v130_1_21.yaml processed successfully. -./aws/aws_sagemaker_notebook_instance_in_vpc.yaml processed successfully. -./aws/aws_cis_v300_2_4_1.yaml processed successfully. -./aws/aws_foundational_security_neptune_2.yaml processed successfully. -./aws/aws_foundational_security_fsx_1.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_5.yaml processed successfully. -./aws/aws_elb_classic_lb_cross_zone_load_balancing_enabled.yaml processed successfully. -./aws/aws_foundational_security_es_7.yaml processed successfully. -./aws/aws_opensearch_domain_node_to_node_encryption_enabled.yaml processed successfully. -./aws/aws_redshift_cluster_encryption_in_transit_enabled.yaml processed successfully. -./aws/aws_apigateway_stage_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_iam_3.yaml processed successfully. -./aws/aws_cis_v140_3_4.yaml processed successfully. -./aws/aws_ecs_service_load_balancer_attached.yaml processed successfully. -./aws/aws_foundational_security_cloudfront_5.yaml processed successfully. -./aws/aws_cis_v130_3_3.yaml processed successfully. -./aws/aws_neptune_db_cluster_snapshot_prohibit_public_access.yaml processed successfully. -./aws/aws_foundational_security_dms_1.yaml processed successfully. -./aws/aws_rds_db_instance_backup_retention_period_less_than_7.yaml processed successfully. -./aws/aws_foundational_security_eks_8.yaml processed successfully. -./aws/aws_sns_topic_policy_prohibit_public_access.yaml processed successfully. -./aws/aws_iam_user_in_group.yaml processed successfully. -./aws/aws_cis_v150_1_19.yaml processed successfully. -./aws/aws_rds_db_cluster_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_rds_db_cluster_aurora_postgres_not_exposed_to_local_file_read_vulnerability.yaml processed successfully. -./aws/aws_cis_compute_service_v100_10_1.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_1_5.yaml processed successfully. -./aws/aws_cloudfront_distribution_use_custom_ssl_certificate.yaml processed successfully. -./aws/aws_cis_v150_5_4.yaml processed successfully. -./aws/aws_cis_v200_3_2.yaml processed successfully. -./aws/aws_iam_policy_unused.yaml processed successfully. -./aws/aws_foundational_security_rds_11.yaml processed successfully. -./aws/aws_vpc_gateway_endpoint_restrict_public_access.yaml processed successfully. -./aws/aws_neptune_db_cluster_copy_tags_to_snapshot_enabled.yaml processed successfully. -./aws/aws_acm_certificate_no_wildcard_domain_name.yaml processed successfully. -./aws/aws_cis_v120_1_4.yaml processed successfully. -./aws/aws_foundational_security_ssm_4.yaml processed successfully. -./aws/aws_elb_application_classic_lb_logging_enabled.yaml processed successfully. -./aws/aws_ecr_repository_image_scan_on_push_enabled.yaml processed successfully. -./aws/aws_cis_v120_1_12.yaml processed successfully. -./aws/aws_foundational_security_redshift_3.yaml processed successfully. -./aws/aws_cis_v150_1_3.yaml processed successfully. -./aws/aws_glacier_vault_restrict_public_access.yaml processed successfully. -./aws/aws_mandatory_sql_ec2_classic_load_balancer_mandatory.yaml processed successfully. -./aws/aws_ec2_instance_no_amazon_key_pair.yaml processed successfully. -./aws/aws_efs_file_system_enforces_ssl.yaml processed successfully. -./aws/aws_codebuild_project_source_repo_oauth_configured.yaml processed successfully. -./aws/aws_ecs_task_definition_logging_enabled.yaml processed successfully. -./aws/aws_eks_cluster_with_latest_kubernetes_version.yaml processed successfully. -./aws/aws_foundational_security_networkfirewall_6.yaml processed successfully. -./aws/aws_ec2_stopped_instance_30_days.yaml processed successfully. -./aws/aws_kms_cmk_rotation_enabled.yaml processed successfully. -./aws/aws_ec2_ami_restrict_public_access.yaml processed successfully. -./aws/aws_mandatory_sql_inspector_assessment_template_mandatory.yaml processed successfully. -./aws/aws_fsx_file_system_copy_tags_to_backup_and_volume_enabled.yaml processed successfully. -./aws/aws_cloudfront_distribution_default_root_object_configured.yaml processed successfully. -./aws/aws_sns_topic_policy_prohibit_publishing_access.yaml processed successfully. -./aws/aws_organizational_tag_policies_enabled.yaml processed successfully. -./aws/aws_vpc_security_group_restrict_ingress_rdp_all.yaml processed successfully. -./aws/aws_mandatory_sql_wafv2_web_acl_mandatory.yaml processed successfully. -./aws/aws_cis_v200_2_3_2.yaml processed successfully. -./aws/aws_cloudwatch_log_group_retention_period_365.yaml processed successfully. -./aws/aws_es_domain_audit_logging_enabled.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_10.yaml processed successfully. -./aws/aws_cis_v130_1_17.yaml processed successfully. -./aws/aws_kms_key_not_pending_deletion.yaml processed successfully. -./aws/aws_elb_classic_lb_with_inbound_rule.yaml processed successfully. -./aws/aws_cis_v200_1_3.yaml processed successfully. -./aws/aws_foundational_security_ecs_5.yaml processed successfully. -./aws/aws_cis_v200_1_13.yaml processed successfully. -./aws/aws_acm_certificate_no_failed_certificate.yaml processed successfully. -./aws/aws_vpc_security_group_allows_ingress_to_memcached_port.yaml processed successfully. -./aws/aws_cis_v300_1_20.yaml processed successfully. -./aws/aws_foundational_security_account_1.yaml processed successfully. -./aws/aws_elb_listener_use_secure_ssl_cipher.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_11.yaml processed successfully. -./aws/aws_cis_v200_5_4.yaml processed successfully. -./aws/aws_foundational_security_sfn_1.yaml processed successfully. -./aws/aws_dms_replication_instance_not_publicly_accessible.yaml processed successfully. -./aws/aws_s3_bucket_policy_restricts_cross_account_permission_changes.yaml processed successfully. -./aws/aws_cis_v150_3_2.yaml processed successfully. -./aws/aws_elb_application_network_lb_use_listeners.yaml processed successfully. -./aws/aws_route53_domain_privacy_protection_enabled.yaml processed successfully. -./aws/aws_foundational_security_rds_5.yaml processed successfully. -./aws/aws_log_metric_filter_disable_or_delete_cmk.yaml processed successfully. -./aws/aws_cis_v120_3_5.yaml processed successfully. -./aws/aws_foundational_security_ecr_1.yaml processed successfully. -./aws/aws_cis_v300_1_6.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_9.yaml processed successfully. -./aws/aws_secretsmanager_secret_unused_90_day.yaml processed successfully. -./aws/aws_cis_v150_2_3_1.yaml processed successfully. -./aws/aws_api_gatewayv2_route_authorization_type_configured.yaml processed successfully. -./aws/aws_networkfirewall_stateless_rule_group_not_empty.yaml processed successfully. -./aws/aws_cis_v130_3_10.yaml processed successfully. -./aws/aws_mandatory_sql_rds_db_parameter_group_mandatory.yaml processed successfully. -./aws/aws_cis_v200_2_1_3.yaml processed successfully. -./aws/aws_docdb_cluster_instance_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_kms_key_decryption_restricted_in_iam_inline_policy.yaml processed successfully. -./aws/aws_foundational_security_waf_10.yaml processed successfully. -./aws/aws_rds_db_instance_events_subscription.yaml processed successfully. -./aws/aws_cis_v140_3_8.yaml processed successfully. -./aws/aws_cis_v140_3_10.yaml processed successfully. -./aws/aws_cis_v130_3_4.yaml processed successfully. -./aws/aws_autoscaling_launch_config_hop_limit.yaml processed successfully. -./aws/aws_cloudfront_distribution_waf_enabled.yaml processed successfully. -./aws/aws_lambda_function_use_latest_runtime.yaml processed successfully. -./aws/aws_foundational_security_dms_6.yaml processed successfully. -./aws/aws_appstream_fleet_idle_disconnect_timeout_600_seconds.yaml processed successfully. -./aws/aws_cis_v130_2_1_1.yaml processed successfully. -./aws/aws_foundational_security_ec2_17.yaml processed successfully. -./aws/aws_foundational_security_elb_4.yaml processed successfully. -./aws/aws_sns_topic_encrypted_at_rest.yaml processed successfully. -./aws/aws_cloudtrail_trail_enabled.yaml processed successfully. -./aws/aws_cis_v140_2_1_2.yaml processed successfully. -./aws/aws_cis_v140_3_3.yaml processed successfully. -./aws/aws_foundational_security_iam_4.yaml processed successfully. -./aws/aws_cloudformation_stack_notifications_enabled.yaml processed successfully. -./aws/aws_foundational_security_s3_13.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_2.yaml processed successfully. -./aws/aws_foundational_security_config_1.yaml processed successfully. -./aws/aws_mandatory_sql_elastic_beanstalk_application_mandatory.yaml processed successfully. -./aws/aws_s3_bucket_enforces_ssl.yaml processed successfully. -./aws/aws_cis_v140_4_14.yaml processed successfully. -./aws/aws_rds_db_instance_multiple_az_enabled.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_management_level_access.yaml processed successfully. -./aws/aws_vpc_security_group_restrict_ingress_kibana_port.yaml processed successfully. -./aws/aws_dax_cluster_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_foundational_security_sagemaker_3.yaml processed successfully. -./aws/aws_rds_db_instance_in_vpc.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_privilege_escalation_risk_access.yaml processed successfully. -./aws/aws_foundational_security_neptune_5.yaml processed successfully. -./aws/aws_foundational_security_emr_2.yaml processed successfully. -./aws/aws_cis_v300_4_12.yaml processed successfully. -./aws/aws_cis_v150_3_9.yaml processed successfully. -./aws/aws_cis_compute_service_v100_6_1.yaml processed successfully. -./aws/aws_foundational_security_rds_20.yaml processed successfully. -./aws/aws_emr_account_public_access_blocked.yaml processed successfully. -./aws/aws_s3_bucket_protected_by_macie.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_6.yaml processed successfully. -./aws/aws_rds_db_security_group_events_subscription.yaml processed successfully. -./aws/aws_cis_v200_1_8.yaml processed successfully. -./aws/aws_cis_v200_1_18.yaml processed successfully. -./aws/aws_foundational_security_secretsmanager_3.yaml processed successfully. -./aws/aws_cis_v140_1_2.yaml processed successfully. -./aws/aws_foundational_security_autoscaling_5.yaml processed successfully. -./aws/aws_acm_certificate_transparency_logging_enabled.yaml processed successfully. -./aws/aws_es_domain_internal_user_database_enabled.yaml processed successfully. -./aws/aws_foundational_security_apigateway_1.yaml processed successfully. -./aws/aws_ecr_repository_lifecycle_policy_configured.yaml processed successfully. -./aws/aws_cis_v130_1_5.yaml processed successfully. -./aws/aws_foundational_security_cloudformation_1.yaml processed successfully. -./aws/aws_efs_file_system_encrypted_with_cmk.yaml processed successfully. -./aws/aws_eks_cluster_control_plane_audit_logging_enabled.yaml processed successfully. -./aws/aws_route53_domain_expires_30_days.yaml processed successfully. -./aws/aws_vpc_security_group_restrict_ingress_ssh_all.yaml processed successfully. -./aws/aws_cis_v140_1_17.yaml processed successfully. -./aws/aws_cis_v130_5_2.yaml processed successfully. -./aws/aws_redshift_cluster_kms_enabled.yaml processed successfully. -./aws/aws_iam_users_with_console_access_are_requried_to_have_MFA.yaml processed successfully. -./aws/aws_cis_v120_1_19.yaml processed successfully. -./aws/aws_foundational_security_redshift_8.yaml processed successfully. -./aws/aws_cis_v150_1_8.yaml processed successfully. -./aws/aws_cis_v300_1_11.yaml processed successfully. -./aws/aws_rds_db_cluster_deletion_protection_enabled.yaml processed successfully. -./aws/aws_ssm_managed_instance_compliance_association_compliant.yaml processed successfully. -./aws/aws_cloudtrail_security_trail_enabled.yaml processed successfully. -./aws/aws_cis_v150_1_12.yaml processed successfully. -./aws/aws_rds_db_instance_backup_enabled.yaml processed successfully. -./aws/aws_foundational_security_waf_7.yaml processed successfully. -./aws/aws_iam_user_with_administrator_access_mfa_enabled.yaml processed successfully. -./aws/aws_iam_managed_policy_attached_to_role.yaml processed successfully. -./aws/aws_securityhub_enabled.yaml processed successfully. -./aws/aws_cloudtrail_s3_data_events_enabled.yaml processed successfully. -./aws/aws_log_metric_filter_network_acl.yaml processed successfully. -./aws/aws_cis_v200_3_9.yaml processed successfully. -./aws/aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled.yaml processed successfully. -./aws/aws_ec2_transit_gateway_auto_cross_account_attachment_disabled.yaml processed successfully. -./aws/aws_foundational_security_opensearch_7.yaml processed successfully. -./aws/aws_cloudtrail_multi_region_read_write_enabled.yaml processed successfully. -./aws/aws_cis_v120_2_6.yaml processed successfully. -./aws/aws_log_metric_filter_unauthorized_api.yaml processed successfully. -./aws/aws_foundational_security_iam_8.yaml processed successfully. -./aws/aws_mandatory_sql_route53_domain_mandatory.yaml processed successfully. -./aws/aws_rds_db_instance_ca_certificate_expires_7_days.yaml processed successfully. -./aws/aws_vpc_configured_to_use_vpc_endpoints.yaml processed successfully. -./aws/aws_s3_bucket_mfa_delete_enabled.yaml processed successfully. -./aws/aws_cis_v130_4_13.yaml processed successfully. -./aws/aws_cis_v300_5_6.yaml processed successfully. -./aws/aws_cis_v130_3_8.yaml processed successfully. -./aws/aws_cis_v140_1_21.yaml processed successfully. -./aws/aws_autoscaling_group_multiple_az_configured.yaml processed successfully. -./aws/aws_cis_v200_2_1_4.yaml processed successfully. -./aws/aws_rds_db_instance_cloudwatch_logs_enabled.yaml processed successfully. -./aws/aws_rds_db_cluster_aurora_mysql_audit_logging_enabled.yaml processed successfully. -./aws/aws_cis_v300_1_1.yaml processed successfully. -./aws/aws_foundational_security_rds_2.yaml processed successfully. -./aws/aws_mandatory_sql_vpc_vpn_connection_mandatory.yaml processed successfully. -./aws/aws_kinesis_stream_encrypted_with_kms_cmk.yaml processed successfully. -./aws/aws_cloudfront_distribution_origin_access_identity_enabled.yaml processed successfully. -./aws/aws_guardduty_enabled.yaml processed successfully. -./aws/aws_cis_v150_3_5.yaml processed successfully. -./aws/aws_eks_cluster_endpoint_restrict_public_access.yaml processed successfully. -./aws/aws_cis_v200_5_3.yaml processed successfully. -./aws/aws_vpc_security_group_restricted_common_ports.yaml processed successfully. -./aws/aws_cis_v200_1_14.yaml processed successfully. -./aws/aws_cis_v120_3_12.yaml processed successfully. -./aws/aws_foundational_security_ecs_2.yaml processed successfully. -./aws/aws_cis_v200_1_4.yaml processed successfully. -./aws/aws_sagemaker_model_in_vpc.yaml processed successfully. -./aws/aws_iam_support_role.yaml processed successfully. -./aws/aws_foundational_security_autoscaling_9.yaml processed successfully. -./aws/aws_cis_v130_1_10.yaml processed successfully. -./aws/aws_foundational_security_route53_2.yaml processed successfully. -./aws/aws_ebs_snapshot_encryption_enabled.yaml processed successfully. -./aws/aws_iam_policy_no_full_access_to_kms.yaml processed successfully. -./aws/aws_ec2_launch_template_not_publicly_accessible.yaml processed successfully. -./aws/aws_foundational_security_cloudtrail_1.yaml processed successfully. -./aws/aws_sagemaker_training_job_in_vpc.yaml processed successfully. -./aws/aws_appstream_fleet_max_user_duration_36000_seconds.yaml processed successfully. -./aws/aws_networkfirewall_firewall_deletion_protection_enabled.yaml processed successfully. -./aws/aws_cis_v150_4_7.yaml processed successfully. -./aws/aws_dms_replication_instance_automatic_minor_version_upgrade_enabled.yaml processed successfully. -./aws/aws_vpc_security_group_restrict_ingress_common_ports_all.yaml processed successfully. -./aws/aws_efs_file_system_restrict_public_access.yaml processed successfully. -./aws/aws_emr_cluster_local_disk_encrypted_with_cmk.yaml processed successfully. -./aws/aws_elastic_beanstalk_environment_logs_to_cloudwatch.yaml processed successfully. -./aws/aws_cis_v150_1_4.yaml processed successfully. -./aws/aws_dynamodb_table_point_in_time_recovery_enabled.yaml processed successfully. -./aws/aws_cis_v120_1_15.yaml processed successfully. -./aws/aws_foundational_security_redshift_4.yaml processed successfully. -./aws/aws_cis_v200_2_2_1.yaml processed successfully. -./aws/aws_s3_bucket_acls_should_prohibit_user_access.yaml processed successfully. -./aws/aws_ebs_volume_unused.yaml processed successfully. -./aws/aws_foundational_security_ssm_3.yaml processed successfully. -./aws/aws_es_domain_node_to_node_encryption_enabled.yaml processed successfully. -./aws/aws_cis_v120_1_3.yaml processed successfully. -./aws/aws_foundational_security_efs_1.yaml processed successfully. -./aws/aws_cis_v200_3_5.yaml processed successfully. -./aws/aws_cis_v150_5_3.yaml processed successfully. -./aws/aws_ebs_attached_volume_encryption_enabled.yaml processed successfully. -./aws/aws_foundational_security_rds_16.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_1_2.yaml processed successfully. -./aws/aws_ec2_stopped_instance_90_days.yaml processed successfully. -./aws/aws_lambda_function_encryption_enabled.yaml processed successfully. -./aws/aws_sqs_queue_encrypted_at_rest.yaml processed successfully. -./aws/aws_iam_user_access_keys_and_password_at_setup.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_1_3.yaml processed successfully. -./aws/aws_rds_db_cluster_events_subscription.yaml processed successfully. -./aws/aws_cis_v200_3_4.yaml processed successfully. -./aws/aws_cis_v150_5_2.yaml processed successfully. -./aws/aws_foundational_security_rds_17.yaml processed successfully. -./aws/aws_s3_bucket_versioning_and_lifecycle_policy_enabled.yaml processed successfully. -./aws/aws_log_metric_filter_cloudtrail_configuration.yaml processed successfully. -./aws/aws_foundational_security_ssm_2.yaml processed successfully. -./aws/aws_cis_v120_1_2.yaml processed successfully. -./aws/aws_ebs_volume_in_backup_plan.yaml processed successfully. -./aws/aws_api_gateway_rest_api_public_endpoint_with_authorizer.yaml processed successfully. -./aws/aws_cis_v150_1_5.yaml processed successfully. -./aws/aws_fsx_file_system_protected_by_backup_plan.yaml processed successfully. -./aws/aws_directory_service_directory_sns_notifications_enabled.yaml processed successfully. -./aws/aws_iam_root_last_used.yaml processed successfully. -./aws/aws_codebuild_project_artifact_encryption_enabled.yaml processed successfully. -./aws/aws_foundational_security_ec2_20.yaml processed successfully. -./aws/aws_foundational_security_s3_1.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_12.yaml processed successfully. -./aws/aws_cis_v120_4_1.yaml processed successfully. -./aws/aws_sfn_state_machine_logging_enabled.yaml processed successfully. -./aws/aws_s3_bucket_policy_restrict_public_access.yaml processed successfully. -./aws/aws_route53_domain_auto_renew_enabled.yaml processed successfully. -./aws/aws_es_domain_in_vpc.yaml processed successfully. -./aws/aws_cis_v130_1_11.yaml processed successfully. -./aws/aws_cis_v130_1_8.yaml processed successfully. -./aws/aws_rds_db_cluster_automatic_minor_version_upgrade_enabled.yaml processed successfully. -./aws/aws_vpc_security_group_allows_ingress_to_oracle_ports.yaml processed successfully. -./aws/aws_drs_job_enabled.yaml processed successfully. -./aws/aws_foundational_security_ecs_3.yaml processed successfully. -./aws/aws_cis_v200_1_5.yaml processed successfully. -./aws/aws_cis_v200_1_15.yaml processed successfully. -./aws/aws_cloudtrail_s3_logging_enabled.yaml processed successfully. -./aws/aws_cis_v120_3_13.yaml processed successfully. -./aws/aws_mandatory_sql_wafv2_rule_group_mandatory.yaml processed successfully. -./aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_fragmented_packets.yaml processed successfully. -./aws/aws_cis_v150_3_4.yaml processed successfully. -./aws/aws_elasticache_redis_cluster_automatic_backup_retention_15_days.yaml processed successfully. -./aws/aws_cis_v200_5_2.yaml processed successfully. -./aws/aws_foundational_security_rds_3.yaml processed successfully. -./aws/aws_es_domain_logs_to_cloudwatch.yaml processed successfully. -./aws/aws_rds_db_instance_connections_encryption_enabled.yaml processed successfully. -./aws/aws_apigateway_rest_api_stage_use_ssl_certificate.yaml processed successfully. -./aws/aws_docdb_cluster_instance_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_neptune_8.yaml processed successfully. -./aws/aws_foundational_security_cloudfront_12.yaml processed successfully. -./aws/aws_cis_v200_4_6.yaml processed successfully. -./aws/aws_cis_v140_1_20.yaml processed successfully. -./aws/aws_foundational_security_elb_9.yaml processed successfully. -./aws/aws_foundational_security_dynamodb_6.yaml processed successfully. -./aws/aws_foundational_security_opensearch_6.yaml processed successfully. -./aws/aws_cis_v120_2_7.yaml processed successfully. -./aws/aws_mandatory_sql_efs_file_system_mandatory.yaml processed successfully. -./aws/aws_eks_cluster_no_multiple_security_groups.yaml processed successfully. -./aws/aws_vpc_security_group_remote_administration.yaml processed successfully. -./aws/aws_codebuild_project_plaintext_env_variables_no_sensitive_aws_values.yaml processed successfully. -./aws/aws_cis_v200_3_8.yaml processed successfully. -./aws/aws_ec2_client_vpn_endpoint_client_connection_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_eks_2.yaml processed successfully. -./aws/aws_cis_v150_1_13.yaml processed successfully. -./aws/aws_log_metric_filter_network_gateway.yaml processed successfully. -./aws/aws_foundational_security_waf_6.yaml processed successfully. -./aws/aws_dynamodb_table_protected_by_backup_plan.yaml processed successfully. -./aws/aws_cis_v120_1_18.yaml processed successfully. -./aws/aws_foundational_security_redshift_9.yaml processed successfully. -./aws/aws_networkfirewall_firewall_logging_enabled.yaml processed successfully. -./aws/aws_cis_v150_1_9.yaml processed successfully. -./aws/aws_cis_v300_1_10.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_1.yaml processed successfully. -./aws/aws_iam_server_certificate_not_expired.yaml processed successfully. -./aws/aws_iam_user_console_access_unused_45.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_destruction_kms_access.yaml processed successfully. -./aws/aws_mandatory_sql_sagemaker_model_mandatory.yaml processed successfully. -./aws/aws_foundational_security_elasticache_1.yaml processed successfully. -./aws/aws_rds_db_cluster_aurora_backtracking_enabled.yaml processed successfully. -./aws/aws_apigateway_rest_api_authorizers_configured.yaml processed successfully. -./aws/aws_mandatory_sql_vpc_security_group_mandatory.yaml processed successfully. -./aws/aws_mandatory_sql_lambda_function_mandatory.yaml processed successfully. -./aws/aws_cis_v140_1_16.yaml processed successfully. -./aws/aws_cis_v140_5_4.yaml processed successfully. -./aws/aws_autoscaling_group_propagate_tags_to_ec2_instance_enabled.yaml processed successfully. -./aws/aws_sagemaker_notebook_instance_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_appstream_fleet_default_internet_access_disabled.yaml processed successfully. -./aws/aws_foundational_security_autoscaling_4.yaml processed successfully. -./aws/aws_cis_v130_1_4.yaml processed successfully. -./aws/aws_rds_db_instance_deletion_protection_enabled.yaml processed successfully. -./aws/aws_rds_db_instance_in_backup_plan.yaml processed successfully. -./aws/aws_ebs_snapshot_not_publicly_restorable.yaml processed successfully. -./aws/aws_elb_classic_lb_no_registered_instance.yaml processed successfully. -./aws/aws_sagemaker_training_job_inter_container_traffic_encryption_enabled.yaml processed successfully. -./aws/aws_foundational_security_ec2_1.yaml processed successfully. -./aws/aws_iam_user_no_inline_attached_policies.yaml processed successfully. -./aws/aws_foundational_security_opensearch_10.yaml processed successfully. -./aws/aws_elb_application_lb_desync_mitigation_mode.yaml processed successfully. -./aws/aws_cis_v140_1_3.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_destruction_rds_access.yaml processed successfully. -./aws/aws_cis_v300_2_2_1.yaml processed successfully. -./aws/aws_foundational_security_secretsmanager_2.yaml processed successfully. -./aws/aws_cis_v200_1_19.yaml processed successfully. -./aws/aws_cis_v120_1_22.yaml processed successfully. -./aws/aws_opensearch_domain_in_vpc.yaml processed successfully. -./aws/aws_cis_v150_4_10.yaml processed successfully. -./aws/aws_s3_bucket_not_accessible_to_all_authenticated_user.yaml processed successfully. -./aws/aws_mandatory_sql_cloudtrail_trail_mandatory.yaml processed successfully. -./aws/aws_opensearch_domain_data_node_fault_tolerance.yaml processed successfully. -./aws/aws_foundational_security_rds_21.yaml processed successfully. -./aws/aws_eks_cluster_secrets_encrypted.yaml processed successfully. -./aws/aws_foundational_security_elb_14.yaml processed successfully. -./aws/aws_vpc_security_group_remote_administration_ipv4.yaml processed successfully. -./aws/aws_msk_cluster_encryption_in_transit_with_tls_enabled.yaml processed successfully. -./aws/aws_mandatory_sql_eks_addon_mandatory.yaml processed successfully. -./aws/aws_mandatory_sql_elastic_beanstalk_environment_mandatory.yaml processed successfully. -./aws/aws_foundational_security_kinesis_1.yaml processed successfully. -./aws/aws_s3_bucket_cross_region_replication_enabled.yaml processed successfully. -./aws/aws_redshift_cluster_encryption_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_lambda_1.yaml processed successfully. -./aws/aws_cis_v150_3_8.yaml processed successfully. -./aws/aws_cloudformation_stack_drift_detection_check.yaml processed successfully. -./aws/aws_appsync_graphql_api_field_level_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_sagemaker_2.yaml processed successfully. -./aws/aws_mandatory_sql_iam_server_certificate_mandatory.yaml processed successfully. -./aws/aws_foundational_security_neptune_4.yaml processed successfully. -./aws/aws_ecs_task_definition_no_host_pid_mode.yaml processed successfully. -./aws/aws_dynamodb_table_encryption_enabled.yaml processed successfully. -./aws/aws_vpc_flow_logs_enabled.yaml processed successfully. -./aws/aws_eventbridge_custom_bus_resource_based_policy_attached.yaml processed successfully. -./aws/aws_elasticache_cluster_no_public_subnet.yaml processed successfully. -./aws/aws_iam_role_no_administrator_access_policy_attached.yaml processed successfully. -./aws/aws_foundational_security_s3_12.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_3.yaml processed successfully. -./aws/aws_rds_db_instance_prohibit_public_access.yaml processed successfully. -./aws/aws_docdb_cluster_deletion_protection_enabled.yaml processed successfully. -./aws/aws_foundational_security_es_1.yaml processed successfully. -./aws/aws_apigateway_stage_cache_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_cis_v140_2_1_3.yaml processed successfully. -./aws/aws_cis_v140_3_2.yaml processed successfully. -./aws/aws_foundational_security_iam_5.yaml processed successfully. -./aws/aws_foundational_security_cloudfront_3.yaml processed successfully. -./aws/aws_cis_v140_3_11.yaml processed successfully. -./aws/aws_cis_v130_3_5.yaml processed successfully. -./aws/aws_rds_db_cluster_copy_tags_to_snapshot_enabled.yaml processed successfully. -./aws/aws_foundational_security_ec2_16.yaml processed successfully. -./aws/aws_mandatory_sql_ec2_instance_mandatory.yaml processed successfully. -./aws/aws_cloudfront_distribution_configured_with_origin_failover.yaml processed successfully. -./aws/aws_foundational_security_rds_18.yaml processed successfully. -./aws/aws_sagemaker_training_job_network_isolation_enabled.yaml processed successfully. -./aws/aws_cis_v150_1_10.yaml processed successfully. -./aws/aws_foundational_security_eks_1.yaml processed successfully. -./aws/aws_cis_v200_1_20.yaml processed successfully. -./aws/aws_ecr_repository_tag_immutability_enabled.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_2.yaml processed successfully. -./aws/aws_rds_db_parameter_group_events_subscription.yaml processed successfully. -./aws/aws_cloudtrail_bucket_not_public.yaml processed successfully. -./aws/aws_foundational_security_elasticache_2.yaml processed successfully. -./aws/aws_iam_role_unused_60.yaml processed successfully. -./aws/aws_cis_v140_1_15.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_security_group_write_access.yaml processed successfully. -./aws/aws_rds_db_instance_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_apigateway_3.yaml processed successfully. -./aws/aws_sso_users_with_permission_assignments_are_required_to_have_MFA_on_AzureAD.yaml processed successfully. -./aws/aws_cis_v130_1_7.yaml processed successfully. -./aws/aws_lambda_function_tracing_enabled.yaml processed successfully. -./aws/aws_ecs_cluster_container_instance_agent_connected.yaml processed successfully. -./aws/aws_cloudtrail_trail_bucket_mfa_enabled.yaml processed successfully. -./aws/aws_neptune_db_cluster_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_cis_v140_2_3_1.yaml processed successfully. -./aws/aws_s3_bucket_static_website_hosting_disabled.yaml processed successfully. -./aws/aws_waf_regional_web_acl_rule_attached.yaml processed successfully. -./aws/aws_mandatory_sql_rds_db_cluster_parameter_group_mandatory.yaml processed successfully. -./aws/aws_foundational_security_ec2_2.yaml processed successfully. -./aws/aws_cis_v120_1_21.yaml processed successfully. -./aws/aws_mandatory_sql_dms_replication_instance_mandatory.yaml processed successfully. -./aws/aws_vpc_endpoint_service_acceptance_required_enabled.yaml processed successfully. -./aws/aws_foundational_security_secretsmanager_1.yaml processed successfully. -./aws/aws_mandatory_sql_ecs_service_mandatory.yaml processed successfully. -./aws/aws_cloudfront_distribution_no_non_existent_s3_origin.yaml processed successfully. -./aws/aws_iam_root_user_no_access_keys.yaml processed successfully. -./aws/aws_foundational_security_codebuild_5.yaml processed successfully. -./aws/aws_iam_user_access_key_age_90.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_4.yaml processed successfully. -./aws/aws_api_gatewayv2_route_authorizer_configured.yaml processed successfully. -./aws/aws_rds_db_instance_protected_by_backup_plan.yaml processed successfully. -./aws/aws_vpc_route_table_restrict_public_access_to_igw.yaml processed successfully. -./aws/aws_foundational_security_rds_22.yaml processed successfully. -./aws/aws_foundational_security_lambda_2.yaml processed successfully. -./aws/aws_cis_compute_service_v100_6_3.yaml processed successfully. -./aws/aws_vpc_network_acl_remote_administration.yaml processed successfully. -./aws/aws_s3_public_access_block_account.yaml processed successfully. -./aws/aws_redshift_cluster_no_default_database_name.yaml processed successfully. -./aws/aws_foundational_security_sagemaker_1.yaml processed successfully. -./aws/aws_foundational_security_neptune_7.yaml processed successfully. -./aws/aws_ec2_instance_termination_protection_enabled.yaml processed successfully. -./aws/aws_foundational_security_rds_34.yaml processed successfully. -./aws/aws_ec2_instance_user_data_no_secrets.yaml processed successfully. -./aws/aws_foundational_security_es_2.yaml processed successfully. -./aws/aws_mandatory_sql_rds_db_cluster_mandatory.yaml processed successfully. -./aws/aws_foundational_security_s3_11.yaml processed successfully. -./aws/aws_neptune_db_cluster_snapshot_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_cloudfront_distribution_geo_restrictions_enabled.yaml processed successfully. -./aws/aws_dynamodb_table_deletion_protection_enabled.yaml processed successfully. -./aws/aws_cis_v120_2_8.yaml processed successfully. -./aws/aws_foundational_security_elb_6.yaml processed successfully. -./aws/aws_rds_db_instance_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_foundational_security_ec2_15.yaml processed successfully. -./aws/aws_vpc_security_group_allows_ingress_to_mongodb_ports.yaml processed successfully. -./aws/aws_s3_bucket_versioning_enabled.yaml processed successfully. -./aws/aws_iam_policy_all_attached_no_star_star.yaml processed successfully. -./aws/aws_cis_v130_3_6.yaml processed successfully. -./aws/aws_autoscaling_group_with_lb_use_health_check.yaml processed successfully. -./aws/aws_dynamodb_table_auto_scaling_enabled.yaml processed successfully. -./aws/aws_codebuild_project_with_user_controlled_buildspec.yaml processed successfully. -./aws/aws_neptune_db_cluster_iam_authentication_enabled.yaml processed successfully. -./aws/aws_foundational_security_rds_14.yaml processed successfully. -./aws/aws_acm_certificate_not_expired.yaml processed successfully. -./aws/aws_lightsail_instance_ipv6_networking_disabled.yaml processed successfully. -./aws/aws_vpc_default_security_group_restricts_all_traffic.yaml processed successfully. -./aws/aws_cis_v130_4_8.yaml processed successfully. -./aws/aws_foundational_security_efs_3.yaml processed successfully. -./aws/aws_cis_v200_3_7.yaml processed successfully. -./aws/aws_mandatory_sql_rds_db_subnet_group_mandatory.yaml processed successfully. -./aws/aws_mandatory_sql_config_rule_mandatory.yaml processed successfully. -./aws/aws_iam_root_user_mfa_enabled.yaml processed successfully. -./aws/aws_foundational_security_ssm_1.yaml processed successfully. -./aws/aws_cis_v120_1_1.yaml processed successfully. -./aws/aws_waf_rule_group_rule_attached.yaml processed successfully. -./aws/aws_cis_v200_3_11.yaml processed successfully. -./aws/aws_foundational_security_redshift_6.yaml processed successfully. -./aws/aws_neptune_db_cluster_deletion_protection_enabled.yaml processed successfully. -./aws/aws_cis_v120_1_17.yaml processed successfully. -./aws/aws_ecs_cluster_container_insights_enabled.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_11.yaml processed successfully. -./aws/aws_cis_v140_1_19.yaml processed successfully. -./aws/aws_cis_v120_4_2.yaml processed successfully. -./aws/aws_foundational_security_networkfirewall_3.yaml processed successfully. -./aws/aws_log_group_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_ecs_task_definition_container_non_privileged.yaml processed successfully. -./aws/aws_es_domain_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_foundational_security_ec2_23.yaml processed successfully. -./aws/aws_cis_v300_3_2.yaml processed successfully. -./aws/aws_cis_v150_4_5.yaml processed successfully. -./aws/aws_mandatory_sql_ecs_container_instance_mandatory.yaml processed successfully. -./aws/aws_foundational_security_appsync_2.yaml processed successfully. -./aws/aws_iam_account_password_policy_one_symbol.yaml processed successfully. -./aws/aws_mandatory_sql_directory_service_directory_mandatory.yaml processed successfully. -./aws/aws_iam_account_password_policy_one_lowercase_letter.yaml processed successfully. -./aws/aws_foundational_security_docdb_5.yaml processed successfully. -./aws/aws_vpc_security_group_restrict_ingress_kafka_port.yaml processed successfully. -./aws/aws_cis_v130_1_12.yaml processed successfully. -./aws/aws_elb_tls_listener_protocol_version.yaml processed successfully. -./aws/aws_cloudwatch_alarm_action_enabled_check.yaml processed successfully. -./aws/aws_mandatory_sql_dax_cluster_mandatory.yaml processed successfully. -./aws/aws_cloudtrail_multi_region_trail_enabled.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_8.yaml processed successfully. -./aws/aws_iam_user_one_active_key.yaml processed successfully. -./aws/aws_waf_regional_rule_group_rule_attached.yaml processed successfully. -./aws/aws_rds_db_instance_iam_authentication_enabled.yaml processed successfully. -./aws/aws_log_metric_filter_vpc.yaml processed successfully. -./aws/aws_vpc_security_group_restrict_ingress_tcp_udp_all.yaml processed successfully. -./aws/aws_mandatory_sql_sagemaker_notebook_instance_mandatory.yaml processed successfully. -./aws/aws_mandatory_sql_dynamodb_table_mandatory.yaml processed successfully. -./aws/aws_sagemaker_training_job_volume_and_data_encryption_enabled.yaml processed successfully. -./aws/aws_iam_role_should_not_have_trust_to_cognito_full_access.yaml processed successfully. -./aws/aws_wafv2_rule_group_logging_enabled.yaml processed successfully. -./aws/aws_cis_v200_1_16.yaml processed successfully. -./aws/aws_mandatory_sql_iam_user_mandatory.yaml processed successfully. -./aws/aws_cis_v150_3_7.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_14.yaml processed successfully. -./aws/aws_es_domain_cognito_authentication_enabled.yaml processed successfully. -./aws/aws_secretsmanager_secret_last_used_1_day.yaml processed successfully. -./aws/aws_log_metric_filter_security_group.yaml processed successfully. -./aws/aws_iam_group_not_empty.yaml processed successfully. -./aws/aws_cis_v300_1_3.yaml processed successfully. -./aws/aws_iam_users_with_api_keys_should_have_keys_rotated_every_x_days.yaml processed successfully. -./aws/aws_backup_recovery_point_min_retention_35_days.yaml processed successfully. -./aws/aws_foundational_security_dms_8.yaml processed successfully. -./aws/aws_foundational_security_ec2_19.yaml processed successfully. -./aws/aws_ec2_instance_ssm_managed.yaml processed successfully. -./aws/aws_sagemaker_notebook_instance_direct_internet_access_disabled.yaml processed successfully. -./aws/aws_es_domain_encrypted_using_tls_1_2.yaml processed successfully. -./aws/aws_redshift_cluster_automatic_upgrade_major_versions_enabled.yaml processed successfully. -./aws/aws_foundational_security_opensearch_5.yaml processed successfully. -./aws/aws_eks_cluster_endpoint_public_access_restricted.yaml processed successfully. -./aws/aws_cis_v120_2_4.yaml processed successfully. -./aws/aws_iam_custom_policy_unattached_no_star_star.yaml processed successfully. -./aws/aws_route53_zone_query_logging_enabled.yaml processed successfully. -./aws/aws_apigateway_rest_api_endpoint_restrict_public_access.yaml processed successfully. -./aws/aws_ec2_instance_detailed_monitoring_enabled.yaml processed successfully. -./aws/aws_s3_bucket_default_encryption_enabled.yaml processed successfully. -./aws/aws_foundational_security_opensearch_4.yaml processed successfully. -./aws/aws_cis_v120_2_5.yaml processed successfully. -./aws/aws_foundational_security_dms_9.yaml processed successfully. -./aws/aws_foundational_security_ec2_18.yaml processed successfully. -./aws/aws_foundational_security_sqs_1.yaml processed successfully. -./aws/aws_elastic_beanstalk_enhanced_health_reporting_enabled.yaml processed successfully. -./aws/aws_ssm_managed_instance_compliance_patch_compliant.yaml processed successfully. -./aws/aws_foundational_security_cloudfront_10.yaml processed successfully. -./aws/aws_mandatory_sql_ec2_network_load_balancer_mandatory.yaml processed successfully. -./aws/aws_rds_db_snapshot_encrypted_at_rest.yaml processed successfully. -./aws/aws_cis_v300_5_5.yaml processed successfully. -./aws/aws_sagemaker_model_network_isolation_enabled.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_2_4.yaml processed successfully. -./aws/aws_autoscaling_group_no_suspended_process.yaml processed successfully. -./aws/aws_rds_db_instance_and_cluster_no_default_port.yaml processed successfully. -./aws/aws_mandatory_sql_rds_db_cluster_snapshot_mandatory.yaml processed successfully. -./aws/aws_cis_v300_1_2.yaml processed successfully. -./aws/aws_iam_inline_policy_no_administrative_privileges.yaml processed successfully. -./aws/aws_ssm_document_prohibit_public_access.yaml processed successfully. -./aws/aws_appstream_fleet_session_disconnect_timeout_300_seconds.yaml processed successfully. -./aws/aws_opensearch_domain_cognito_authentication_enabled_for_kibana.yaml processed successfully. -./aws/aws_cis_v150_3_6.yaml processed successfully. -./aws/aws_mandatory_sql_secretsmanager_secret_mandatory.yaml processed successfully. -./aws/aws_cis_v120_3_11.yaml processed successfully. -./aws/aws_neptune_db_cluster_audit_logging_enabled.yaml processed successfully. -./aws/aws_cis_v200_1_17.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_9.yaml processed successfully. -./aws/aws_elb_application_lb_drop_http_headers.yaml processed successfully. -./aws/aws_ssm_parameter_encryption_enabled.yaml processed successfully. -./aws/aws_cis_v200_1_7.yaml processed successfully. -./aws/aws_foundational_security_ecs_1.yaml processed successfully. -./aws/aws_cis_v150_2_2_1.yaml processed successfully. -./aws/aws_ebs_volume_protected_by_backup_plan.yaml processed successfully. -./aws/aws_iam_user_access_key_unused_45.yaml processed successfully. -./aws/aws_cis_v130_1_13.yaml processed successfully. -./aws/aws_guardduty_finding_archived.yaml processed successfully. -./aws/aws_cloudtrail_trail_insight_selectors_and_logging_enabled.yaml processed successfully. -./aws/aws_ec2_instance_no_launch_wizard_security_group.yaml processed successfully. -./aws/aws_foundational_security_docdb_4.yaml processed successfully. -./aws/aws_cis_v300_3_3.yaml processed successfully. -./aws/aws_cis_v150_2_1_4.yaml processed successfully. -./aws/aws_elasticache_replication_group_auto_failover_enabled.yaml processed successfully. -./aws/aws_foundational_security_cloudtrail_2.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_10.yaml processed successfully. -./aws/aws_foundational_security_networkfirewall_2.yaml processed successfully. -./aws/aws_cis_v140_1_18.yaml processed successfully. -./aws/aws_mandatory_sql_rds_db_instance_mandatory.yaml processed successfully. -./aws/aws_cis_compute_service_v100_11_1.yaml processed successfully. -./aws/aws_cis_v200_3_10.yaml processed successfully. -./aws/aws_foundational_security_redshift_7.yaml processed successfully. -./aws/aws_cis_v120_1_16.yaml processed successfully. -./aws/aws_cis_v150_1_7.yaml processed successfully. -./aws/aws_log_metric_filter_console_login_mfa.yaml processed successfully. -./aws/aws_cloudwatch_alarm_action_enabled.yaml processed successfully. -./aws/aws_ebs_volume_snapshot_exists.yaml processed successfully. -./aws/aws_cloudtrail_multi_region_trail_integrated_with_logs.yaml processed successfully. -./aws/aws_foundational_security_rds_15.yaml processed successfully. -./aws/aws_log_metric_filter_organization.yaml processed successfully. -./aws/aws_foundational_security_efs_2.yaml processed successfully. -./aws/aws_cis_v200_3_6.yaml processed successfully. -./aws/aws_foundational_security_waf_8.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_1_1.yaml processed successfully. -./aws/aws_foundational_security_elb_7.yaml processed successfully. -./aws/aws_root_accounts_needs_to_have_mfa.yaml processed successfully. -./aws/aws_cis_v130_2_1_2.yaml processed successfully. -./aws/aws_cis_v130_3_7.yaml processed successfully. -./aws/aws_foundational_security_cloudfront_1.yaml processed successfully. -./aws/aws_mandatory_sql_wafv2_regex_pattern_set_mandatory.yaml processed successfully. -./aws/aws_cis_v120_2_9.yaml processed successfully. -./aws/aws_foundational_security_opensearch_8.yaml processed successfully. -./aws/aws_iam_security_audit_role.yaml processed successfully. -./aws/aws_iam_policy_custom_no_assume_role.yaml processed successfully. -./aws/aws_cis_v140_2_1_1.yaml processed successfully. -./aws/aws_acm_certificate_no_pending_validation_certificate.yaml processed successfully. -./aws/aws_foundational_security_es_3.yaml processed successfully. -./aws/aws_foundational_security_s3_10.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_1.yaml processed successfully. -./aws/aws_foundational_security_neptune_6.yaml processed successfully. -./aws/aws_foundational_security_rds_35.yaml processed successfully. -./aws/aws_codebuild_project_logging_enabled.yaml processed successfully. -./aws/aws_mandatory_sql_ec2_gateway_load_balancer_mandatory.yaml processed successfully. -./aws/aws_cis_v300_4_11.yaml processed successfully. -./aws/aws_cis_compute_service_v100_6_2.yaml processed successfully. -./aws/aws_elb_classic_lb_multiple_az_configured.yaml processed successfully. -./aws/aws_foundational_security_emr_1.yaml processed successfully. -./aws/aws_vpc_security_group_remote_administration_ipv6.yaml processed successfully. -./aws/aws_foundational_security_codebuild_4.yaml processed successfully. -./aws/aws_vpc_security_group_associated_to_eni.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_5.yaml processed successfully. -./aws/aws_mandatory_sql_vpc_nat_gateway_mandatory.yaml processed successfully. -./aws/aws_opensearch_domain_logs_to_cloudwatch.yaml processed successfully. -./aws/aws_cloudfront_distribution_no_deprecated_ssl_protocol.yaml processed successfully. -./aws/aws_cis_v120_1_20.yaml processed successfully. -./aws/aws_cloudformation_stack_rollback_enabled.yaml processed successfully. -./aws/aws_vpc_security_group_unused.yaml processed successfully. -./aws/aws_iam_account_password_policy_one_number.yaml processed successfully. -./aws/aws_cis_v140_1_1.yaml processed successfully. -./aws/aws_foundational_security_ec2_3.yaml processed successfully. -./aws/aws_backup_recovery_point_manual_deletion_disabled.yaml processed successfully. -./aws/aws_foundational_security_apigateway_2.yaml processed successfully. -./aws/aws_vpc_peering_connection_no_cross_account_access.yaml processed successfully. -./aws/aws_foundational_security_autoscaling_6.yaml processed successfully. -./aws/aws_ec2_ebs_default_encryption_enabled.yaml processed successfully. -./aws/aws_vpc_peering_connection_route_table_least_privilege.yaml processed successfully. -./aws/aws_cis_v140_1_14.yaml processed successfully. -./aws/aws_rds_db_instance_no_default_admin_name.yaml processed successfully. -./aws/aws_ecs_task_definition_no_root_user.yaml processed successfully. -./aws/aws_foundational_security_elasticache_3.yaml processed successfully. -./aws/aws_cis_v150_4_8.yaml processed successfully. -./aws/aws_rds_db_snapshot_prohibit_public_access.yaml processed successfully. -./aws/aws_apigateway_stage_use_waf_web_acl.yaml processed successfully. -./aws/aws_autoscaling_group_uses_ec2_launch_template.yaml processed successfully. -./aws/aws_networkfirewall_firewall_in_vpc.yaml processed successfully. -./aws/aws_cis_v200_1_21.yaml processed successfully. -./aws/aws_guardduty_no_high_severity_findings.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_3.yaml processed successfully. -./aws/aws_cis_v300_1_12.yaml processed successfully. -./aws/aws_iam_account_password_policy_reuse_24.yaml processed successfully. -./aws/aws_foundational_security_waf_4.yaml processed successfully. -./aws/aws_cis_v150_1_11.yaml processed successfully. -./aws/aws_vpc_not_in_use.yaml processed successfully. -./aws/aws_ec2_instance_virtualization_type_no_paravirtual.yaml processed successfully. -./aws/aws_foundational_security_rds_19.yaml processed successfully. -./aws/aws_kms_cmk_policy_prohibit_public_access.yaml processed successfully. -./aws/aws_directory_service_directory_snapshots_limit_2.yaml processed successfully. -./aws/aws_waf_web_acl_logging_enabled.yaml processed successfully. -./aws/aws_elb_classic_lb_with_outbound_rule.yaml processed successfully. -./aws/aws_foundational_security_rds_12.yaml processed successfully. -./aws/aws_s3_public_access_block_bucket_account.yaml processed successfully. -./aws/aws_efs_file_system_protected_by_backup_plan.yaml processed successfully. -./aws/aws_cloudfront_distribution_latest_tls_version.yaml processed successfully. -./aws/aws_apigateway_rest_api_stage_xray_tracing_enabled.yaml processed successfully. -./aws/aws_elb_classic_lb_use_tls_https_listeners.yaml processed successfully. -./aws/aws_acmpca_root_certificate_authority_disabled.yaml processed successfully. -./aws/aws_elb_classic_lb_desync_mitigation_mode.yaml processed successfully. -./aws/aws_elasticache_replication_group_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_8.yaml processed successfully. -./aws/aws_cis_v300_1_19.yaml processed successfully. -./aws/aws_cis_v120_1_11.yaml processed successfully. -./aws/aws_kms_cmk_unused.yaml processed successfully. -./aws/aws_vpc_vpn_tunnel_up.yaml processed successfully. -./aws/aws_mandatory_sql_s3_bucket_mandatory.yaml processed successfully. -./aws/aws_ecs_cluster_no_active_services_count.yaml processed successfully. -./aws/aws_cis_v120_4_4.yaml processed successfully. -./aws/aws_foundational_security_networkfirewall_5.yaml processed successfully. -./aws/aws_ec2_instance_ebs_optimized.yaml processed successfully. -./aws/aws_ec2_instance_protected_by_backup_plan.yaml processed successfully. -./aws/aws_cis_v150_4_3.yaml processed successfully. -./aws/aws_cis_v300_3_4.yaml processed successfully. -./aws/aws_sns_topic_notification_delivery_status_enabled.yaml processed successfully. -./aws/aws_foundational_security_cloudtrail_5.yaml processed successfully. -./aws/aws_mandatory_sql_ec2_application_load_balancer_mandatory.yaml processed successfully. -./aws/aws_cis_v150_2_1_3.yaml processed successfully. -./aws/aws_backup_recovery_point_encryption_enabled.yaml processed successfully. -./aws/aws_route53_domain_not_expired.yaml processed successfully. -./aws/aws_mandatory_sql_elasticache_cluster_mandatory.yaml processed successfully. -./aws/aws_foundational_security_ec2_8.yaml processed successfully. -./aws/aws_cis_v130_1_14.yaml processed successfully. -./aws/aws_foundational_security_apigateway_9.yaml processed successfully. -./aws/aws_cis_v200_2_3_1.yaml processed successfully. -./aws/aws_glue_connection_ssl_enabled.yaml processed successfully. -./aws/aws_iam_policy_custom_attached_no_star_star.yaml processed successfully. -./aws/aws_codebuild_project_build_greater_then_90_days.yaml processed successfully. -./aws/aws_rds_db_cluster_aurora_protected_by_backup_plan.yaml processed successfully. -./aws/aws_cis_v200_1_10.yaml processed successfully. -./aws/aws_s3_public_access_block_bucket.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_12.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_elastic_ip_hijacking_access.yaml processed successfully. -./aws/aws_backup_plan_min_retention_35_days.yaml processed successfully. -./aws/aws_es_domain_data_nodes_min_3.yaml processed successfully. -./aws/aws_mandatory_sql_ecr_repository_mandatory.yaml processed successfully. -./aws/aws_foundational_security_es_8.yaml processed successfully. -./aws/aws_elb_application_lb_with_outbound_rule.yaml processed successfully. -./aws/aws_cis_v150_2_3_2.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_attached_with_credentials_exposure_access.yaml processed successfully. -./aws/aws_elb_application_network_lb_use_ssl_certificate.yaml processed successfully. -./aws/aws_foundational_security_ecr_2.yaml processed successfully. -./aws/aws_cis_v300_1_5.yaml processed successfully. -./aws/aws_mandatory_sql_sagemaker_endpoint_configuration_mandatory.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_2_3.yaml processed successfully. -./aws/aws_ebs_attached_volume_delete_on_termination_enabled.yaml processed successfully. -./aws/aws_iam_account_password_policy_strong_min_length_8.yaml processed successfully. -./aws/aws_efs_file_system_encrypt_data_at_rest.yaml processed successfully. -./aws/aws_foundational_security_dynamodb_3.yaml processed successfully. -./aws/aws_networkfirewall_firewall_policy_rule_group_not_empty.yaml processed successfully. -./aws/aws_mandatory_sql_guardduty_detector_mandatory.yaml processed successfully. -./aws/aws_cis_v200_4_3.yaml processed successfully. -./aws/aws_cis_v300_5_2.yaml processed successfully. -./aws/aws_lambda_function_concurrent_execution_limit_configured.yaml processed successfully. -./aws/aws_foundational_security_opensearch_3.yaml processed successfully. -./aws/aws_waf_web_acl_rule_attached.yaml processed successfully. -./aws/aws_cis_v120_2_2.yaml processed successfully. -./aws/aws_foundational_security_backup_1.yaml processed successfully. -./aws/aws_mandatory_sql_elasticsearch_domain_mandatory.yaml processed successfully. -./aws/aws_foundational_security_waf_3.yaml processed successfully. -./aws/aws_mandatory_sql_codepipeline_pipeline_mandatory.yaml processed successfully. -./aws/aws_cis_v140_4_5.yaml processed successfully. -./aws/aws_cis_v150_1_16.yaml processed successfully. -./aws/aws_mandatory_sql_rds_db_snapshot_mandatory.yaml processed successfully. -./aws/aws_sagemaker_notebook_instance_root_access_disabled.yaml processed successfully. -./aws/aws_foundational_security_acm_2.yaml processed successfully. -./aws/aws_cis_v300_1_15.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_4.yaml processed successfully. -./aws/aws_rds_db_cluster_no_default_admin_name.yaml processed successfully. -./aws/aws_efs_file_system_in_backup_plan.yaml processed successfully. -./aws/aws_cis_v300_3_8.yaml processed successfully. -./aws/aws_foundational_security_elasticache_4.yaml processed successfully. -./aws/aws_kms_key_decryption_restricted_in_iam_customer_managed_policy.yaml processed successfully. -./aws/aws_emr_cluster_encryption_at_rest_with_sse_kms.yaml processed successfully. -./aws/aws_s3_bucket_object_lock_enabled.yaml processed successfully. -./aws/aws_cloudfront_distribution_field_level_encryption_enabled.yaml processed successfully. -./aws/aws_rds_db_instance_copy_tags_to_snapshot_enabled.yaml processed successfully. -./aws/aws_cis_v140_5_1.yaml processed successfully. -./aws/aws_foundational_security_networkfirewall_9.yaml processed successfully. -./aws/aws_cis_v140_1_13.yaml processed successfully. -./aws/aws_wafv2_web_acl_logging_enabled.yaml processed successfully. -./aws/aws_waf_regional_rule_condition_attached.yaml processed successfully. -./aws/aws_elastic_beanstalk_environment_managed_updates_enabled.yaml processed successfully. -./aws/aws_foundational_security_s3_8.yaml processed successfully. -./aws/aws_foundational_security_apigateway_5.yaml processed successfully. -./aws/aws_cis_v130_1_1.yaml processed successfully. -./aws/aws_sagemaker_notebook_instance_encrypted_with_kms_cmk.yaml processed successfully. -./aws/aws_cis_v130_1_18.yaml processed successfully. -./aws/aws_foundational_security_autoscaling_1.yaml processed successfully. -./aws/aws_dms_certificate_not_expired.yaml processed successfully. -./aws/aws_foundational_security_elasticbeanstalk_3.yaml processed successfully. -./aws/aws_foundational_security_ec2_4.yaml processed successfully. -./aws/aws_iam_account_password_policy_one_uppercase_letter.yaml processed successfully. -./aws/aws_cloudfront_distribution_encryption_in_transit_enabled.yaml processed successfully. -./aws/aws_foundational_security_codebuild_3.yaml processed successfully. -./aws/aws_mandatory_sql_cloudwatch_log_group_mandatory.yaml processed successfully. -./aws/aws_route53_domain_transfer_lock_enabled.yaml processed successfully. -./aws/aws_cloudwatch_cross_account_sharing.yaml processed successfully. -./aws/aws_foundational_security_pca_1.yaml processed successfully. -./aws/aws_redshift_cluster_automatic_snapshots_min_7_days.yaml processed successfully. -./aws/aws_secretsmanager_secret_rotated_as_scheduled.yaml processed successfully. -./aws/aws_cis_v300_2_1_1.yaml processed successfully. -./aws/aws_foundational_security_rds_24.yaml processed successfully. -./aws/aws_elb_application_lb_deletion_protection_enabled.yaml processed successfully. -./aws/aws_log_metric_filter_console_authentication_failure.yaml processed successfully. -./aws/aws_api_gateway_method_authorization_type_configured.yaml processed successfully. -./aws/aws_iam_policy_inline_no_blocked_kms_actions.yaml processed successfully. -./aws/aws_log_metric_filter_config_configuration.yaml processed successfully. -./aws/aws_cis_v150_3_11.yaml processed successfully. -./aws/aws_redshift_cluster_audit_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_neptune_1.yaml processed successfully. -./aws/aws_workspaces_workspace_volume_encryption_enabled.yaml processed successfully. -./aws/aws_mandatory_sql_rds_db_option_group_mandatory.yaml processed successfully. -./aws/aws_emr_cluster_master_nodes_no_public_ip.yaml processed successfully. -./aws/aws_autoscaling_launch_config_public_ip_disabled.yaml processed successfully. -./aws/aws_cis_v130_1_22.yaml processed successfully. -./aws/aws_foundational_security_es_4.yaml processed successfully. -./aws/aws_lambda_function_cloudwatch_insights_enabled.yaml processed successfully. -./aws/aws_dynamodb_table_in_backup_plan.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_6.yaml processed successfully. -./aws/aws_dms_replication_task_source_database_logging_enabled.yaml processed successfully. -./aws/aws_foundational_security_cloudfront_6.yaml processed successfully. -./aws/aws_iam_user_mfa_enabled.yaml processed successfully. -./aws/aws_cis_v140_3_7.yaml processed successfully. -./aws/aws_lambda_function_in_vpc.yaml processed successfully. -./aws/aws_foundational_security_elb_1.yaml processed successfully. -./aws/aws_mandatory_sql_vpc_eip_mandatory.yaml processed successfully. -./aws/aws_cloudtrail_s3_object_read_events_audit_enabled.yaml processed successfully. -./aws/aws_iam_all_policy_no_service_wild_card.yaml processed successfully. -./aws/aws_foundational_security_cloudfront_7.yaml processed successfully. -./aws/aws_foundational_security_athena_1.yaml processed successfully. -./aws/aws_cis_v140_3_6.yaml processed successfully. -./aws/aws_foundational_security_iam_1.yaml processed successfully. -./aws/aws_foundational_security_es_5.yaml processed successfully. -./aws/aws_route53_domain_expires_7_days.yaml processed successfully. -./aws/aws_cis_v300_1_8.yaml processed successfully. -./aws/aws_sqs_queue_dead_letter_queue_configured.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_7.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_org_write_access.yaml processed successfully. -./aws/aws_cis_compute_service_v100_6_4.yaml processed successfully. -./aws/aws_cis_v150_3_10.yaml processed successfully. -./aws/aws_foundational_security_elb_10.yaml processed successfully. -./aws/aws_codebuild_project_s3_logs_encryption_enabled.yaml processed successfully. -./aws/aws_foundational_security_rds_25.yaml processed successfully. -./aws/aws_secretsmanager_secret_automatic_rotation_enabled.yaml processed successfully. -./aws/aws_waf_web_acl_resource_associated.yaml processed successfully. -./aws/aws_neptune_db_cluster_no_public_subnet.yaml processed successfully. -./aws/aws_lambda_function_variables_no_sensitive_data.yaml processed successfully. -./aws/aws_foundational_security_codebuild_2.yaml processed successfully. -./aws/aws_ec2_instance_not_publicly_accessible.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_3.yaml processed successfully. -./aws/aws_mandatory_sql_vpc_mandatory.yaml processed successfully. -./aws/aws_foundational_security_eventbridge_3.yaml processed successfully. -./aws/aws_cis_v150_4_14.yaml processed successfully. -./aws/aws_iam_policy_custom_no_permissive_role_assumption.yaml processed successfully. -./aws/aws_foundational_security_sns_1.yaml processed successfully. -./aws/aws_cis_v140_1_7.yaml processed successfully. -./aws/aws_opensearch_domain_internal_user_database_disabled.yaml processed successfully. -./aws/aws_foundational_security_apigateway_4.yaml processed successfully. -./aws/aws_cis_compute_service_v100_5_1.yaml processed successfully. -./aws/aws_ecs_service_not_publicly_accessible.yaml processed successfully. -./aws/aws_cis_v130_1_19.yaml processed successfully. -./aws/aws_ecs_cluster_encryption_at_rest_enabled.yaml processed successfully. -./aws/aws_sqs_queue_policy_prohibit_public_access.yaml processed successfully. -./aws/aws_ecs_task_definition_container_readonly_root_filesystem.yaml processed successfully. -./aws/aws_cis_v140_1_12.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_alter_critical_s3_permissions_configuration.yaml processed successfully. -./aws/aws_iam_root_user_hardware_mfa_enabled.yaml processed successfully. -./aws/aws_foundational_security_s3_9.yaml processed successfully. -./aws/aws_cis_v300_3_9.yaml processed successfully. -./aws/aws_foundational_security_elasticache_5.yaml processed successfully. -./aws/aws_ec2_instance_iam_profile_attached.yaml processed successfully. -./aws/aws_account_alternate_contact_security_registered.yaml processed successfully. -./aws/aws_acm_certificate_expires_30_days.yaml processed successfully. -./aws/aws_foundational_security_kms_1.yaml processed successfully. -./aws/aws_cis_v300_2_3_1.yaml processed successfully. -./aws/aws_mandatory_sql_ec2_reserved_instance_mandatory.yaml processed successfully. -./aws/aws_elasticache_replication_group_redis_auth_enabled.yaml processed successfully. -./aws/aws_autoscaling_launch_config_requires_imdsv2.yaml processed successfully. -./aws/aws_cis_v130_2_2_1.yaml processed successfully. -./aws/aws_glue_data_catalog_encryption_settings_metadata_encryption_enabled.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_5.yaml processed successfully. -./aws/aws_glue_data_catalog_encryption_settings_password_encryption_enabled.yaml processed successfully. -./aws/aws_cis_v300_1_14.yaml processed successfully. -./aws/aws_foundational_security_waf_2.yaml processed successfully. -./aws/aws_vpc_igw_attached_to_authorized_vpc.yaml processed successfully. -./aws/aws_cis_v150_1_17.yaml processed successfully. -./aws/aws_ec2_ami_ebs_encryption_enabled.yaml processed successfully. -./aws/aws_athena_workgroup_enforce_configuration_enabled.yaml processed successfully. -./aws/aws_foundational_security_ecs_10.yaml processed successfully. -./aws/aws_lambda_function_cors_configuration.yaml processed successfully. -./aws/aws_cis_v130_4_3.yaml processed successfully. -./aws/aws_iam_group_user_role_no_inline_policies.yaml processed successfully. -./aws/aws_dlm_ebs_snapshot_lifecycle_policy_enabled.yaml processed successfully. -./aws/aws_sns_topic_policy_prohibit_cross_account_access.yaml processed successfully. -./aws/aws_foundational_security_msk_1.yaml processed successfully. -./aws/aws_rds_db_instance_automatic_minor_version_upgrade_enabled.yaml processed successfully. -./aws/aws_opensearch_domain_https_required.yaml processed successfully. -./aws/aws_foundational_security_opensearch_2.yaml processed successfully. -./aws/aws_config_configuration_recorder_no_failed_deliver_logs.yaml processed successfully. -./aws/aws_cis_v120_2_3.yaml processed successfully. -./aws/aws_ecs_task_definition_container_environment_no_secret.yaml processed successfully. -./aws/aws_foundational_security_waf_12.yaml processed successfully. -./aws/aws_elb_classic_lb_use_ssl_certificate.yaml processed successfully. -./aws/aws_foundational_security_dynamodb_2.yaml processed successfully. -./aws/aws_cis_v200_2_1_1.yaml processed successfully. -./aws/aws_cis_v300_5_3.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_with_write_level_access.yaml processed successfully. -./aws/aws_secretsmanager_secret_last_changed_90_day.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_2_2.yaml processed successfully. -./aws/aws_vpc_eip_associated.yaml processed successfully. -./aws/aws_ecs_service_fargate_using_latest_platform_version.yaml processed successfully. -./aws/aws_ec2_ami_not_older_than_90_days.yaml processed successfully. -./aws/aws_cis_v150_2_3_3.yaml processed successfully. -./aws/aws_eks_cluster_no_default_vpc.yaml processed successfully. -./aws/aws_foundational_security_ecr_3.yaml processed successfully. -./aws/aws_cis_v300_1_4.yaml processed successfully. -./aws/aws_cloudtrail_s3_object_write_events_audit_enabled.yaml processed successfully. -./aws/aws_foundational_security_rds_7.yaml processed successfully. -./aws/aws_cis_v150_1_21.yaml processed successfully. -./aws/aws_cis_v200_5_6.yaml processed successfully. -./aws/aws_acm_certificate_rsa_key_length_2048_bits_or_greater.yaml processed successfully. -./aws/aws_cis_compute_service_v100_2_13.yaml processed successfully. -./aws/aws_mandatory_sql_iam_role_mandatory.yaml processed successfully. -./aws/aws_mq_broker_restrict_public_access.yaml processed successfully. -./aws/aws_mandatory_sql_ebs_snapshot_mandatory.yaml processed successfully. -./aws/aws_lambda_function_multiple_az_configured.yaml processed successfully. -./aws/aws_cis_v200_1_11.yaml processed successfully. -./aws/aws_emr_cluster_security_configuration_enabled.yaml processed successfully. -./aws/aws_cloudtrail_trail_validation_enabled.yaml processed successfully. -./aws/aws_cis_v200_1_1.yaml processed successfully. -./aws/aws_waf_rule_condition_attached.yaml processed successfully. -./aws/aws_mandatory_sql_route53_resolver_endpoint_mandatory.yaml processed successfully. -./aws/aws_docdb_cluster_backup_retention_period_7_days.yaml processed successfully. -./aws/aws_opensearch_domain_fine_grained_access_enabled.yaml processed successfully. -./aws/aws_cis_v130_1_15.yaml processed successfully. -./aws/aws_ec2_instance_no_iam_role_with_new_role_creation_with_attached_policy_access.yaml processed successfully. -./aws/aws_cis_compute_service_v100_3_12.yaml processed successfully. -./aws/aws_sqs_queue_encrypted_with_kms_cmk.yaml processed successfully. -./aws/aws_foundational_security_apigateway_8.yaml processed successfully. -./aws/aws_secretsmanager_secret_automatic_rotation_lambda_enabled.yaml processed successfully. -./aws/aws_ecs_task_definition_user_for_host_mode_check.yaml processed successfully. -./aws/aws_foundational_security_ec2_9.yaml processed successfully. -./aws/aws_foundational_security_docdb_2.yaml processed successfully. -./aws/aws_iam_policy_custom_no_blocked_kms_actions.yaml processed successfully. -./aws/aws_cis_v300_3_5.yaml processed successfully. -./aws/aws_log_metric_filter_bucket_policy.yaml processed successfully. -./aws/aws_foundational_security_cloudtrail_4.yaml processed successfully. -./aws/aws_cis_v150_2_1_2.yaml processed successfully. -./aws/aws_foundational_security_networkfirewall_4.yaml processed successfully. -./aws/aws_foundational_security_s3_5.yaml processed successfully. -./aws/aws_foundational_security_ec2_24.yaml processed successfully. -./aws/aws_rds_db_instance_and_cluster_enhanced_monitoring_enabled.yaml processed successfully. -./aws/aws_cis_v150_2_4_1.yaml processed successfully. -./aws/aws_cis_v150_1_1.yaml processed successfully. -./aws/aws_cis_v300_1_18.yaml processed successfully. -./aws/aws_cis_compute_service_v100_4_9.yaml processed successfully. -./aws/aws_s3_access_point_restrict_public_access.yaml processed successfully. -./aws/aws_foundational_security_redshift_1.yaml processed successfully. -./aws/aws_iam_user_no_policies.yaml processed successfully. -./aws/aws_vpc_security_group_not_uses_launch_wizard_sg.yaml processed successfully. -./aws/aws_efs_access_point_enforce_user_identity.yaml processed successfully. -./aws/aws_mandatory_sql_api_gateway_stage_mandatory.yaml processed successfully. -./aws/aws_foundational_security_rds_13.yaml processed successfully. -./aws/aws_foundational_security_efs_4.yaml processed successfully. -./aws/aws_redshift_cluster_prohibit_public_access.yaml processed successfully. -./aws/aws_lambda_function_restrict_public_url.yaml processed successfully. -./aws/aws_cis_v200_4_12.yaml processed successfully. -./aws/aws_mandatory_sql_sagemaker_training_job_mandatory.yaml processed successfully. -./aws/aws_cis_v140_4_8.yaml processed successfully. -./aws/aws_elasticache_replication_group_encryption_at_rest_enabled_with_kms_cmk.yaml processed successfully. -./aws/aws_cloudtrail_trail_enabled_account.yaml processed successfully. -./pending/azure/azure_cis_v200_4_1_1.yaml processed successfully. -./pending/azure/azure_cis_v150_4_3_3.yaml processed successfully. -./pending/azure/azure_cis_v130_3_5.yaml processed successfully. -./pending/azure/azure_cis_v200_4_2_4.yaml processed successfully. -./pending/azure/azure_cis_v210_1_3.yaml processed successfully. -./pending/azure/azure_cis_v200_1_11.yaml processed successfully. -./pending/azure/azure_cis_v130_5_1_4.yaml processed successfully. -./pending/azure/azure_cis_v210_4_3_5.yaml processed successfully. -./pending/azure/azure_cis_v200_9_10.yaml processed successfully. -./pending/azure/azure_cis_v130_4_2_1.yaml processed successfully. -./pending/azure/azure_cis_v140_4_2_2.yaml processed successfully. -./pending/azure/azure_cis_v140_4_3_6.yaml processed successfully. -./pending/azure/azure_cis_v210_9_9.yaml processed successfully. -./pending/azure/azure_cis_v200_8_7.yaml processed successfully. -./pending/azure/azure_cis_v130_4_3_4.yaml processed successfully. -./pending/azure/azure_cis_v150_6_6.yaml processed successfully. -./pending/azure/azure_cis_v140_4_2_3.yaml processed successfully. -./pending/azure/azure_cis_v210_4_3_4.yaml processed successfully. -./pending/azure/azure_cis_v150_8_7.yaml processed successfully. -./pending/azure/azure_cis_v200_6_6.yaml processed successfully. -./pending/azure/azure_cis_v150_9_3.yaml processed successfully. -./pending/azure/azure_cis_v150_4_1_3.yaml processed successfully. -./pending/azure/azure_cis_v200_4_2_5.yaml processed successfully. -./pending/azure/azure_cis_v150_4_3_2.yaml processed successfully. -./pending/azure/azure_cis_v200_4_4_3.yaml processed successfully. -./pending/azure/azure_cis_v140_4_1_1.yaml processed successfully. -./pending/azure/azure_cis_v210_4_3_3.yaml processed successfully. -./pending/azure/azure_cis_v140_4_2_4.yaml processed successfully. -./pending/azure/azure_mariadb_server_private_link_used.yaml processed successfully. -./pending/azure/azure_cis_v130_4_3_3.yaml processed successfully. -./pending/azure/azure_cis_v150_4_2_1.yaml processed successfully. -./pending/azure/azure_cis_v200_4_4_4.yaml processed successfully. -./pending/azure/azure_cis_v210_2_1_9.yaml processed successfully. -./pending/azure/azure_cis_v150_4_3_5.yaml processed successfully. -./pending/azure/azure_cis_v140_4_6.yaml processed successfully. -./pending/azure/azure_cis_v200_4_2_2.yaml processed successfully. -./pending/azure/azure_cis_v200_4_3_6.yaml processed successfully. -./pending/azure/azure_cis_v150_5_1_4.yaml processed successfully. -./pending/azure/azure_cis_v150_9_10.yaml processed successfully. -./pending/azure/azure_cis_v210_8_7.yaml processed successfully. -./pending/azure/azure_cis_v200_4_2_3.yaml processed successfully. -./pending/azure/azure_cis_v140_3_5.yaml processed successfully. -./pending/azure/azure_iot_hub_private_link_used.yaml processed successfully. -./pending/azure/azure_cis_v150_4_3_4.yaml processed successfully. -./pending/azure/azure_cis_v200_4_1_6.yaml processed successfully. -./pending/azure/azure_application_insights_linked_to_log_analytics_workspace.yaml processed successfully. -./pending/azure/azure_cis_v210_4_1_3.yaml processed successfully. -./pending/azure/azure_cis_v140_4_2_5.yaml processed successfully. -./pending/azure/azure_cis_v210_4_3_2.yaml processed successfully. -./pending/azure/azure_cis_v130_4_1_3.yaml processed successfully. -./pending/azure/azure_cis_v140_1_8.yaml processed successfully. -./pending/azure/azure_cis_v140_4_3_2.yaml processed successfully. -./pending/azure/azure_cis_v130_9_10.yaml processed successfully. -./pending/azure/azure_cis_v210_4_4_3.yaml processed successfully. -./pending/azure/azure_cis_v130_4_2_5.yaml processed successfully. -./pending/azure/azure_cis_v150_1_13.yaml processed successfully. -./pending/azure/azure_cis_v140_4_1_3.yaml processed successfully. -./pending/azure/azure_cis_v150_4_1_6.yaml processed successfully. -./pending/azure/azure_cis_v140_6_5.yaml processed successfully. -./pending/azure/azure_cis_v200_4_3_4.yaml processed successfully. -./pending/azure/azure_cis_v210_6_5.yaml processed successfully. -./pending/azure/azure_cis_v200_4_1_5.yaml processed successfully. -./pending/azure/azure_cis_v150_4_2_3.yaml processed successfully. -./pending/azure/azure_cis_v210_3_17.yaml processed successfully. -./pending/azure/azure_cis_v140_1_6.yaml processed successfully. -./pending/azure/azure_cis_v150_4_2_2.yaml processed successfully. -./pending/azure/azure_cis_v200_5_1_4.yaml processed successfully. -./pending/azure/azure_cis_v200_3_13.yaml processed successfully. -./pending/azure/azure_cis_v150_4_3_6.yaml processed successfully. -./pending/azure/azure_monitor_logs_storage_container_insights_activity_logs_encrypted_with_byok.yaml processed successfully. -./pending/azure/azure_cis_v150_4_4_4.yaml processed successfully. -./pending/azure/azure_cis_v200_4_2_1.yaml processed successfully. -./pending/azure/azure_storage_account_queues_logging_enabled.yaml processed successfully. -./pending/azure/azure_cis_v140_6_4.yaml processed successfully. -./pending/azure/azure_cis_v130_4_1_1.yaml processed successfully. -./pending/azure/azure_cis_v130_4_2_4.yaml processed successfully. -./pending/azure/azure_cis_v140_4_3_3.yaml processed successfully. -./pending/azure/azure_storage_account_containing_vhd_os_disk_cmk_encrypted.yaml processed successfully. -./pending/azure/azure_cis_v210_4_1_1.yaml processed successfully. -./pending/azure/azure_cis_v130_6_4.yaml processed successfully. -./pending/azure/azure_cis_v200_4_3_2.yaml processed successfully. -./pending/azure/azure_monitor_logs_storage_container_insights_operational_logs_encrypted_with_byok.yaml processed successfully. -./pending/azure/azure_cis_v130_4_5.yaml processed successfully. -./pending/azure/azure_cis_v200_4_1_3.yaml processed successfully. -./pending/azure/azure_cis_v200_2_1_10.yaml processed successfully. -./pending/azure/azure_cis_v150_4_2_5.yaml processed successfully. -./pending/azure/azure_cis_v210_4_1_6.yaml processed successfully. -./pending/azure/azure_cis_v140_4_3_4.yaml processed successfully. -./pending/azure/azure_cis_v130_4_3_7.yaml processed successfully. -./pending/azure/azure_cis_v150_6_5.yaml processed successfully. -./pending/azure/azure_cis_v130_4_2_3.yaml processed successfully. -./pending/azure/azure_cis_v200_6_5.yaml processed successfully. -./pending/azure/azure_cis_v140_5_1_4.yaml processed successfully. -./pending/azure/azure_cis_v210_4_3_6.yaml processed successfully. -./pending/azure/azure_cis_v200_3_7.yaml processed successfully. -./pending/azure/azure_cis_v130_4_2_2.yaml processed successfully. -./pending/azure/azure_cis_v210_4_4_4.yaml processed successfully. -./pending/azure/azure_cis_v140_4_2_1.yaml processed successfully. -./pending/azure/azure_cis_v130_4_3_6.yaml processed successfully. -./pending/azure/azure_cis_v150_3_13.yaml processed successfully. -./pending/azure/azure_cis_v140_4_3_5.yaml processed successfully. -./pending/azure/azure_cis_v150_4_2_4.yaml processed successfully. -./pending/azure/azure_cis_v150_1_18.yaml processed successfully. -./pending/azure/azure_appservice_web_app_worker_more_than_one.yaml processed successfully. -./pending/azure/azure_compute_windows_vm_secure_boot_enabled.yaml processed successfully. -./pending/azure/azure_cis_v140_9_10.yaml processed successfully. -./pending/azure/azure_cis_v200_4_3_3.yaml processed successfully. -./pending/azure/azure_postgres_db_server_log_duration_on.yaml processed successfully. -./pending/azure/azure_cis_v150_4_1_1.yaml processed successfully. -./pending/azure/azure_cis_v130_6_5.yaml processed successfully. -./pending/aws/aws_cis_v200_4_1.yaml processed successfully. -./pending/aws/aws_cis_v130_4_15.yaml processed successfully. -./pending/aws/aws_foundational_security_rds_4.yaml processed successfully. -./pending/aws/aws_cis_v120_3_4.yaml processed successfully. -./pending/aws/aws_emr_cluster_encryption_at_rest_enabled.yaml processed successfully. -./pending/aws/aws_cis_v300_4_4.yaml processed successfully. -./pending/aws/aws_ec2_instance_no_iam_role_with_defense_evasion_impact_of_aws_security_services_access.yaml processed successfully. -./pending/aws/aws_redshift_cluster_encrypted_with_cmk.yaml processed successfully. -./pending/aws/aws_cis_v140_1_8.yaml processed successfully. -./pending/aws/aws_iam_password_policy_expire_90.yaml processed successfully. -./pending/aws/aws_cis_v150_4_1.yaml processed successfully. -./pending/aws/aws_cis_v120_1_5.yaml processed successfully. -./pending/aws/aws_lightsail_instance_ssh_rdp_http_ports_disabled.yaml processed successfully. -./pending/aws/aws_cis_v200_4_11.yaml processed successfully. -./pending/aws/aws_cis_compute_service_v100_3_4.yaml processed successfully. -./pending/aws/aws_cis_v140_4_12.yaml processed successfully. -./pending/aws/aws_cis_v300_4_8.yaml processed successfully. -./pending/aws/aws_foundational_security_elb_13.yaml processed successfully. -./pending/aws/aws_cis_v120_3_8.yaml processed successfully. -./pending/aws/aws_s3_bucket_object_logging_enabled.yaml processed successfully. -./pending/aws/aws_foundational_security_ec2_6.yaml processed successfully. -./pending/aws/aws_cis_v140_5_3.yaml processed successfully. -./pending/aws/aws_foundational_security_kms_2.yaml processed successfully. -./pending/aws/aws_cis_v120_1_9.yaml processed successfully. -./pending/aws/aws_cis_v130_4_1.yaml processed successfully. -./pending/aws/aws_codedeploy_deployment_group_lambda_allatonce_traffic_shift_disabled.yaml processed successfully. -./pending/aws/aws_cis_v140_4_6.yaml processed successfully. -./pending/aws/aws_glue_dev_endpoint_cloudwatch_logs_encryption_enabled.yaml processed successfully. -./pending/aws/aws_cis_v120_3_9.yaml processed successfully. -./pending/aws/aws_cis_v300_4_15.yaml processed successfully. -./pending/aws/aws_cis_v300_4_9.yaml processed successfully. -./pending/aws/aws_cis_v140_4_13.yaml processed successfully. -./pending/aws/aws_cis_v140_2_1_5.yaml processed successfully. -./pending/aws/aws_foundational_security_elb_3.yaml processed successfully. -./pending/aws/aws_foundational_security_ec2_10.yaml processed successfully. -./pending/aws/aws_cis_v200_4_10.yaml processed successfully. -./pending/aws/aws_cis_v300_3_7.yaml processed successfully. -./pending/aws/aws_cis_v140_1_9.yaml processed successfully. -./pending/aws/aws_cis_v300_4_5.yaml processed successfully. -./pending/aws/aws_cis_v130_4_14.yaml processed successfully. -./pending/aws/aws_cis_v300_5_1.yaml processed successfully. -./pending/aws/aws_cis_v120_2_1.yaml processed successfully. -./pending/aws/aws_foundational_security_cloudfront_9.yaml processed successfully. -./pending/aws/aws_emr_cluster_local_disk_encryption_enabled.yaml processed successfully. -./pending/aws/aws_cis_v150_4_11.yaml processed successfully. -./pending/aws/aws_docdb_cluster_snapshot_restrict_public_access.yaml processed successfully. -./pending/aws/aws_cis_v200_1_22.yaml processed successfully. -./pending/aws/aws_cis_v140_4_1.yaml processed successfully. -./pending/aws/aws_cis_v130_4_6.yaml processed successfully. -./pending/aws/aws_iam_role_cross_account_read_only_access_policy.yaml processed successfully. -./pending/aws/aws_ec2_instance_no_high_level_finding_in_inspector_scan.yaml processed successfully. -./pending/aws/aws_foundational_security_cloudfront_13.yaml processed successfully. -./pending/aws/aws_cis_v200_4_7.yaml processed successfully. -./pending/aws/aws_foundational_security_guardduty_1.yaml processed successfully. -./pending/aws/aws_cis_v120_3_2.yaml processed successfully. -./pending/aws/aws_cis_v300_4_2.yaml processed successfully. -./pending/aws/aws_rds_db_cluster_encrypted_with_cmk.yaml processed successfully. -./pending/aws/aws_cis_v130_1_9.yaml processed successfully. -./pending/aws/aws_foundational_security_ec2_21.yaml processed successfully. -./pending/aws/aws_cis_v200_4_16.yaml processed successfully. -./pending/aws/aws_dms_replication_task_target_database_logging_enabled.yaml processed successfully. -./pending/aws/aws_cis_v120_1_14.yaml processed successfully. -./pending/aws/aws_cis_v150_4_6.yaml processed successfully. -./pending/aws/aws_glue_dev_endpoint_s3_encryption_enabled.yaml processed successfully. -./pending/aws/aws_cis_v300_3_1.yaml processed successfully. -./pending/aws/aws_lightsail_instance_rdp_restricted_ip.yaml processed successfully. -./pending/aws/aws_cis_v300_4_3.yaml processed successfully. -./pending/aws/aws_iam_access_analyzer_enabled_without_findings.yaml processed successfully. -./pending/aws/aws_emr_cluster_encryption_at_rest_with_cse_cmk.yaml processed successfully. -./pending/aws/aws_cis_v120_3_3.yaml processed successfully. -./pending/aws/aws_cis_v130_4_12.yaml processed successfully. -./pending/aws/aws_cis_v130_3_9.yaml processed successfully. -./pending/aws/aws_cis_v130_4_7.yaml processed successfully. -./pending/aws/aws_cis_v130_5_3.yaml processed successfully. -./pending/aws/aws_rds_db_instance_no_public_subnet.yaml processed successfully. -./pending/aws/aws_vpc_subnet_multi_az_enabled.yaml processed successfully. -./pending/aws/aws_cis_compute_service_v100_2_7.yaml processed successfully. -./pending/aws/aws_cis_v200_1_9.yaml processed successfully. -./pending/aws/aws_cis_v300_2_1_4.yaml processed successfully. -./pending/aws/aws_cis_v300_4_13.yaml processed successfully. -./pending/aws/aws_cis_v140_4_15.yaml processed successfully. -./pending/aws/aws_foundational_security_dms_7.yaml processed successfully. -./pending/aws/aws_foundational_security_elb_5.yaml processed successfully. -./pending/aws/aws_cis_v130_4_4.yaml processed successfully. -./pending/aws/aws_cis_v140_4_3.yaml processed successfully. -./pending/aws/aws_cis_v300_1_13.yaml processed successfully. -./pending/aws/aws_cis_v150_4_9.yaml processed successfully. -./pending/aws/aws_ec2_instance_no_iam_role_with_new_user_creation_with_attached_policy_access.yaml processed successfully. -./pending/aws/aws_cis_v150_4_13.yaml processed successfully. -./pending/aws/aws_cis_v300_4_10.yaml processed successfully. -./pending/aws/aws_foundational_security_iam_6.yaml processed successfully. -./pending/aws/aws_cis_v140_3_1.yaml processed successfully. -./pending/aws/aws_cis_v200_4_9.yaml processed successfully. -./pending/aws/aws_cis_v200_4_15.yaml processed successfully. -./pending/aws/aws_cis_v150_5_1.yaml processed successfully. -./pending/aws/aws_guardduty_centrally_configured.yaml processed successfully. -./pending/aws/aws_elb_application_lb_listener_certificate_expire_7_days.yaml processed successfully. -./pending/aws/aws_cis_v150_1_6.yaml processed successfully. -./pending/aws/aws_emr_cluster_encryption_in_transit_enabled.yaml processed successfully. -./pending/aws/aws_foundational_security_s3_2.yaml processed successfully. -./pending/aws/aws_cis_v150_2_1_5.yaml processed successfully. -./pending/aws/aws_cis_v200_1_6.yaml processed successfully. -./pending/aws/aws_cis_v120_3_10.yaml processed successfully. -./pending/aws/aws_cis_v200_5_1.yaml processed successfully. -./pending/aws/aws_cis_v130_4_11.yaml processed successfully. -./pending/aws/aws_cis_v200_4_5.yaml processed successfully. -./pending/aws/aws_cis_v300_5_4.yaml processed successfully. -./pending/aws/aws_vpc_subnet_public_and_private.yaml processed successfully. -./pending/aws/aws_cis_v130_4_10.yaml processed successfully. -./pending/aws/aws_cis_v200_4_4.yaml processed successfully. -./pending/aws/aws_cis_v120_3_1.yaml processed successfully. -./pending/aws/aws_foundational_security_rds_1.yaml processed successfully. -./pending/aws/aws_cis_v300_4_1.yaml processed successfully. -./pending/aws/aws_cis_v150_4_4.yaml processed successfully. -./pending/aws/aws_elb_application_lb_listener_certificate_expire_30_days.yaml processed successfully. -./pending/aws/aws_cis_v120_4_3.yaml processed successfully. -./pending/aws/aws_foundational_security_s3_3.yaml processed successfully. -./pending/aws/aws_cis_v130_4_9.yaml processed successfully. -./pending/aws/aws_cis_v200_4_14.yaml processed successfully. -./pending/aws/aws_glue_dev_endpoint_job_bookmarks_encryption_enabled.yaml processed successfully. -./pending/aws/aws_cis_v200_4_8.yaml processed successfully. -./pending/aws/aws_foundational_security_iam_7.yaml processed successfully. -./pending/aws/aws_foundational_security_rds_23.yaml processed successfully. -./pending/aws/aws_cis_v150_4_12.yaml processed successfully. -./pending/aws/aws_cis_v130_1_6.yaml processed successfully. -./pending/aws/aws_cis_v130_5_1.yaml processed successfully. -./pending/aws/aws_cis_v140_4_2.yaml processed successfully. -./pending/aws/aws_cis_v130_4_5.yaml processed successfully. -./pending/aws/aws_cis_v200_4_13.yaml processed successfully. -./pending/aws/aws_cis_v140_4_9.yaml processed successfully. -./pending/aws/aws_cis_v200_3_1.yaml processed successfully. -./pending/aws/aws_cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled.yaml processed successfully. -./pending/aws/aws_ec2_instance_no_iam_role_with_database_management_write_access.yaml processed successfully. -./pending/aws/aws_cis_v120_1_7.yaml processed successfully. -./pending/aws/aws_foundational_security_ec2_25.yaml processed successfully. -./pending/aws/aws_foundational_security_docdb_3.yaml processed successfully. -./pending/aws/aws_cis_v150_1_20.yaml processed successfully. -./pending/aws/aws_cis_v150_3_1.yaml processed successfully. -./pending/aws/aws_cis_v300_4_6.yaml processed successfully. -./pending/aws/aws_cis_v120_3_6.yaml processed successfully. -./pending/aws/aws_foundational_security_rds_6.yaml processed successfully. -./pending/aws/aws_cis_v130_4_2.yaml processed successfully. -./pending/aws/aws_backup_report_plan_configured.yaml processed successfully. -./pending/aws/aws_ec2_instance_no_iam_role_with_write_access_to_resource_based_policies.yaml processed successfully. -./pending/aws/aws_ecs_cluster_instance_in_vpc.yaml processed successfully. -./pending/aws/aws_cis_v140_1_6.yaml processed successfully. -./pending/aws/aws_cis_v150_4_15.yaml processed successfully. -./pending/aws/aws_cis_v300_4_16.yaml processed successfully. -./pending/aws/aws_cis_v140_4_10.yaml processed successfully. -./pending/aws/aws_cis_v300_1_9.yaml processed successfully. -./pending/aws/aws_lightsail_instance_ssh_restricted_ip.yaml processed successfully. -./pending/aws/aws_cis_v130_3_1.yaml processed successfully. -./pending/aws/aws_glue_job_cloudwatch_logs_encryption_enabled.yaml processed successfully. -./pending/aws/aws_cis_v140_4_11.yaml processed successfully. -./pending/aws/aws_foundational_security_lambda_5.yaml processed successfully. -./pending/aws/aws_cis_v140_4_4.yaml processed successfully. -./pending/aws/aws_glue_job_s3_encryption_enabled.yaml processed successfully. -./pending/aws/aws_cis_v200_4_2.yaml processed successfully. -./pending/aws/aws_iam_user_hardware_mfa_enabled.yaml processed successfully. -./pending/aws/aws_cis_v120_3_7.yaml processed successfully. -./pending/aws/aws_cis_v300_4_7.yaml processed successfully. -./pending/aws/aws_cis_v300_1_22.yaml processed successfully. -./pending/aws/aws_cis_v150_4_2.yaml processed successfully. -./pending/aws/aws_cis_v120_1_10.yaml processed successfully. -./pending/aws/aws_cis_v120_1_6.yaml processed successfully. diff --git a/compliance/controls/rename_integration_type_name.sh b/compliance/controls/rename_integration_type_name.sh deleted file mode 100755 index 32e80de79..000000000 --- a/compliance/controls/rename_integration_type_name.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -# Description: -# This script traverses all subdirectories to find YAML files containing the 'Integration_Type_Name' key -# and renames the key to 'IntegrationTypeName' while preserving its values. - -# Define the root directory (current directory) -ROOT_DIR="." - -# Create or clear the log files -> renamed_files.log -> error_files.log -> error_messages.log - -# Find all .yaml and .yml files -find "$ROOT_DIR" -type f \( -iname "*.yaml" -o -iname "*.yml" \) -print0 | while IFS= read -r -d '' file; do - # Check if the file contains the 'Integration_Type_Name:' key - if grep -q '^Integration_Type_Name:' "$file"; then - echo "Processing: $file" - - # Apply the yq transformation to rename the key - if yq eval -i ' - .IntegrationTypeName = .Integration_Type_Name | - del(.Integration_Type_Name) - ' "$file"; then - echo "$file renamed successfully." >> renamed_files.log - else - echo "Error renaming $file" >> error_files.log - # Capture detailed error messages - yq eval -i ' - .IntegrationTypeName = .Integration_Type_Name | - del(.Integration_Type_Name) - ' "$file" 2>> error_messages.log - fi - fi -done - -echo "Bulk renaming completed. Check 'renamed_files.log' for details." -echo "Any errors are logged in 'error_files.log' and 'error_messages.log'." diff --git a/compliance/controls/renamed_files.log b/compliance/controls/renamed_files.log deleted file mode 100644 index 01a2cf2f6..000000000 --- a/compliance/controls/renamed_files.log +++ /dev/null @@ -1,2846 +0,0 @@ -./azure/azure_cis_v130_1_4.yaml renamed successfully. -./azure/azure_cis_v130_1_15.yaml renamed successfully. -./azure/azure_cis_v210_3_13.yaml renamed successfully. -./azure/azure_monitor_log_profile_retention_365_days.yaml renamed successfully. -./azure/azure_cis_v210_7_5.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_4333.yaml renamed successfully. -./azure/azure_cis_v140_1_3.yaml renamed successfully. -./azure/azure_log_analytics_workspace_block_log_ingestion_and_querying_from_public.yaml renamed successfully. -./azure/azure_synapse_workspace_encryption_at_rest_using_cmk.yaml renamed successfully. -./azure/azure_cis_v150_2_1_5.yaml renamed successfully. -./azure/azure_cis_v150_5_2_7.yaml renamed successfully. -./azure/azure_cis_v200_4_4_2.yaml renamed successfully. -./azure/azure_cis_v130_5_3.yaml renamed successfully. -./azure/azure_iam_subscription_owner_max_3.yaml renamed successfully. -./azure/azure_monitor_logs_storage_container_not_public_accessible.yaml renamed successfully. -./azure/azure_keyvault_with_rbac_secret_expiration_set.yaml renamed successfully. -./azure/azure_data_factory_uses_git_repository.yaml renamed successfully. -./azure/azure_cis_v200_2_1_12.yaml renamed successfully. -./azure/azure_cis_v210_3_2.yaml renamed successfully. -./azure/azure_monitor_log_alert_delete_public_ip_address.yaml renamed successfully. -./azure/azure_cis_v130_9_3.yaml renamed successfully. -./azure/azure_cis_v150_1_9.yaml renamed successfully. -./azure/azure_cis_v200_5_1_1.yaml renamed successfully. -./azure/azure_network_interface_ip_forwarding_disabled.yaml renamed successfully. -./azure/azure_securitycenter_security_alerts_to_owner_enabled.yaml renamed successfully. -./azure/azure_cis_v140_9_4.yaml renamed successfully. -./azure/azure_cis_v210_6_1.yaml renamed successfully. -./azure/azure_postgres_sql_ssl_enabled.yaml renamed successfully. -./azure/azure_keyvault_with_non_rbac_key_expiration_set.yaml renamed successfully. -./azure/azure_cis_v200_3_8.yaml renamed successfully. -./azure/azure_appservice_api_app_cors_no_star.yaml renamed successfully. -./azure/azure_cis_v130_2_13.yaml renamed successfully. -./azure/azure_container_registry_use_virtual_service_endpoint.yaml renamed successfully. -./azure/azure_log_profile_enabled_for_all_subscription.yaml renamed successfully. -./azure/azure_cis_v210_5_4.yaml renamed successfully. -./azure/azure_cis_v140_3_2.yaml renamed successfully. -./azure/azure_storage_sync_private_link_used.yaml renamed successfully. -./azure/azure_cis_v150_4_4_1.yaml renamed successfully. -./azure/azure_sql_server_transparent_data_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v200_2_1_6.yaml renamed successfully. -./azure/azure_cis_v200_5_2_4.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_25.yaml renamed successfully. -./azure/azure_kubernetes_cluster_node_restrict_public_access.yaml renamed successfully. -./azure/azure_storage_account_tables_logging_enabled.yaml renamed successfully. -./azure/azure_iot_hub_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_cis_v210_1_14.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_app_service_web_app_mandatory.yaml renamed successfully. -./azure/azure_cis_v140_7_5.yaml renamed successfully. -./azure/azure_compute_vm_scale_set_system_updates_installed.yaml renamed successfully. -./azure/azure_cognitive_service_local_auth_disabled.yaml renamed successfully. -./azure/azure_mysql_server_audit_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v130_7_2.yaml renamed successfully. -./azure/azure_compute_vm_disaster_recovery_enabled.yaml renamed successfully. -./azure/azure_cis_v140_2_6.yaml renamed successfully. -./azure/azure_kubernetes_cluster_http_application_routing_disabled.yaml renamed successfully. -./azure/azure_appservice_api_app_use_https.yaml renamed successfully. -./azure/azure_monitor_log_alert_create_update_public_ip_address.yaml renamed successfully. -./azure/azure_cis_v150_1_21.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_postgresql_server_mandatory.yaml renamed successfully. -./azure/azure_cis_v130_2_1.yaml renamed successfully. -./azure/azure_cis_v150_3_8.yaml renamed successfully. -./azure/azure_cosmosdb_account_uses_aad_and_rbac.yaml renamed successfully. -./azure/azure_appservice_plan_minimum_sku.yaml renamed successfully. -./azure/azure_cis_v210_1_2_3.yaml renamed successfully. -./azure/azure_cis_v210_9_4.yaml renamed successfully. -./azure/azure_cis_v140_6_1.yaml renamed successfully. -./azure/azure_databox_edge_device_double_encryption_enabled.yaml renamed successfully. -./azure/azure_kubernetes_cluster_container_use_allowed_images.yaml renamed successfully. -./azure/azure_cis_v150_4_1_2.yaml renamed successfully. -./azure/azure_cis_v130_6_6.yaml renamed successfully. -./azure/azure_cis_v200_1_9.yaml renamed successfully. -./azure/azure_cis_v150_5_1_2.yaml renamed successfully. -./azure/azure_kubernetes_cluster_container_use_allowed_capabilities.yaml renamed successfully. -./azure/azure_kubernetes_cluster_key_vault_secret_rotation_enabled.yaml renamed successfully. -./azure/azure_cis_v210_7_9.yaml renamed successfully. -./azure/azure_compute_vm_remote_access_restricted_all_ports.yaml renamed successfully. -./azure/azure_keyvault_vault_private_link_used.yaml renamed successfully. -./azure/azure_cis_v150_9_2.yaml renamed successfully. -./azure/azure_cis_v200_6_7.yaml renamed successfully. -./azure/azure_cis_v130_1_19.yaml renamed successfully. -./azure/azure_cis_v130_1_8.yaml renamed successfully. -./azure/azure_cis_v210_1_22.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_log_alert_mandatory.yaml renamed successfully. -./azure/azure_compute_vm_max_password_age_70_days_windows.yaml renamed successfully. -./azure/azure_cis_v140_1_12.yaml renamed successfully. -./azure/azure_appservice_authentication_enabled.yaml renamed successfully. -./azure/azure_cis_v210_2_1_3.yaml renamed successfully. -./azure/azure_cis_v210_5_2_1.yaml renamed successfully. -./azure/azure_container_registry_trust_policy_enabled.yaml renamed successfully. -./azure/azure_cis_v150_2_1_9.yaml renamed successfully. -./azure/azure_search_service_uses_private_link.yaml renamed successfully. -./azure/azure_mysql_server_encrypted_at_rest_using_cmk.yaml renamed successfully. -./azure/azure_appservice_function_app_cors_no_star.yaml renamed successfully. -./azure/azure_cis_v140_9_8.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_app_service_environment_mandatory.yaml renamed successfully. -./azure/azure_cis_v200_1_2_6.yaml renamed successfully. -./azure/azure_cis_v140_2_14.yaml renamed successfully. -./azure/azure_cis_v150_1_5.yaml renamed successfully. -./azure/azure_cis_v200_7_3.yaml renamed successfully. -./azure/azure_cis_v150_8_6.yaml renamed successfully. -./azure/azure_signalr_service_private_link_used.yaml renamed successfully. -./azure/azure_network_security_group_not_configured_gateway_subnets.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_data_factory_mandatory.yaml renamed successfully. -./azure/azure_cis_v150_1_17.yaml renamed successfully. -./azure/azure_batch_account_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_apimanagement_service_with_virtual_network.yaml renamed successfully. -./azure/azure_cis_v210_2_1_13.yaml renamed successfully. -./azure/azure_search_service_public_network_access_disabled.yaml renamed successfully. -./azure/azure_cis_v200_3_4.yaml renamed successfully. -./azure/azure_sql_server_auditing_storage_account_destination_retention_90_days.yaml renamed successfully. -./azure/azure_cis_v200_1_1_3.yaml renamed successfully. -./azure/azure_cis_v200_5_2_8.yaml renamed successfully. -./azure/azure_cis_v130_5_2_1.yaml renamed successfully. -./azure/azure_cis_v130_3_9.yaml renamed successfully. -./azure/azure_cis_v140_5_2_2.yaml renamed successfully. -./azure/azure_cis_v150_2_1_10.yaml renamed successfully. -./azure/azure_cis_v200_9_2.yaml renamed successfully. -./azure/azure_synapse_workspace_vulnerability_assessment_enabled.yaml renamed successfully. -./azure/azure_cis_v210_1_18.yaml renamed successfully. -./azure/azure_cis_v150_10_1.yaml renamed successfully. -./azure/azure_cis_v130_1_23.yaml renamed successfully. -./azure/azure_sql_server_va_setting_scan_reports_configured.yaml renamed successfully. -./azure/azure_cis_v150_3_4.yaml renamed successfully. -./azure/azure_cis_v130_4_3_5.yaml renamed successfully. -./azure/azure_cis_v150_3_10.yaml renamed successfully. -./azure/azure_container_registry_admin_user_disabled.yaml renamed successfully. -./azure/azure_cis_v210_4_5_3.yaml renamed successfully. -./azure/azure_compute_vm_scale_set_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v200_1_5.yaml renamed successfully. -./azure/azure_cosmosdb_account_key_based_metadata_write_access_disabled.yaml renamed successfully. -./azure/azure_cis_v150_7_3.yaml renamed successfully. -./azure/azure_appservice_web_app_ftps_enabled.yaml renamed successfully. -./azure/azure_cis_v200_8_6.yaml renamed successfully. -./azure/azure_compute_vm_scale_set_endpoint_protection_solution_installed.yaml renamed successfully. -./azure/azure_cis_v150_1_2_5.yaml renamed successfully. -./azure/azure_cis_v210_9_8.yaml renamed successfully. -./azure/azure_compute_unattached_disk_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_cis_v210_5_1_4.yaml renamed successfully. -./azure/azure_cis_v210_4_1_4.yaml renamed successfully. -./azure/azure_postgresql_server_infrastructure_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v210_5_1_5.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_mssql_elasticpool_mandatory.yaml renamed successfully. -./azure/azure_cis_v210_4_1_5.yaml renamed successfully. -./azure/azure_cis_v200_1_4.yaml renamed successfully. -./azure/azure_kubernetes_cluster_container_cpu_and_memory_resource_limit.yaml renamed successfully. -./azure/azure_cis_v150_7_2.yaml renamed successfully. -./azure/azure_appservice_web_app_register_with_active_directory_enabled.yaml renamed successfully. -./azure/azure_cis_v150_1_2_4.yaml renamed successfully. -./azure/azure_kubernetes_cluster_max_pod_50.yaml renamed successfully. -./azure/azure_cis_v210_4_5_2.yaml renamed successfully. -./azure/azure_cis_v140_4_3_7.yaml renamed successfully. -./azure/azure_cis_v150_3_5.yaml renamed successfully. -./azure/azure_cis_v150_3_11.yaml renamed successfully. -./azure/azure_cis_v150_5_2_10.yaml renamed successfully. -./azure/azure_monitor_log_cluster_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_cis_v210_1_19.yaml renamed successfully. -./azure/azure_appservice_function_app_uses_managed_identity.yaml renamed successfully. -./azure/azure_network_security_group_subnet_associated.yaml renamed successfully. -./azure/azure_cis_v130_1_22.yaml renamed successfully. -./azure/azure_cis_v150_2_1_11.yaml renamed successfully. -./azure/azure_kubernetes_cluster_container_host_process_id_not_shared.yaml renamed successfully. -./azure/azure_appservice_web_app_cors_no_star.yaml renamed successfully. -./azure/azure_cis_v200_9_3.yaml renamed successfully. -./azure/azure_apimanagement_service_client_certificate_enabled.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_data_lake_store_mandatory.yaml renamed successfully. -./azure/azure_cis_v140_5_2_3.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_udp_port_1434.yaml renamed successfully. -./azure/azure_cis_v200_1_1_2.yaml renamed successfully. -./azure/azure_compute_vm_scale_set_automatic_upgrade_enabled.yaml renamed successfully. -./azure/azure_cis_v200_5_2_9.yaml renamed successfully. -./azure/azure_cis_v130_3_8.yaml renamed successfully. -./azure/azure_cis_v200_9_11.yaml renamed successfully. -./azure/azure_cis_v210_2_1_12.yaml renamed successfully. -./azure/azure_cis_v200_3_5.yaml renamed successfully. -./azure/azure_cis_v150_5_3.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_53.yaml renamed successfully. -./azure/azure_cis_v150_1_16.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_resource_manager.yaml renamed successfully. -./azure/azure_cis_v140_2_15.yaml renamed successfully. -./azure/azure_cis_v130_5_1_5.yaml renamed successfully. -./azure/azure_cis_v150_1_4.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_udp_port_53.yaml renamed successfully. -./azure/azure_cis_v200_7_2.yaml renamed successfully. -./azure/azure_compute_vm_non_internet_facing_protected_with_nsg.yaml renamed successfully. -./azure/azure_cognitive_account_public_network_access_disabled.yaml renamed successfully. -./azure/azure_cis_v140_9_9.yaml renamed successfully. -./azure/azure_monitor_logs_storage_container_encryptes_with_byok.yaml renamed successfully. -./azure/azure_securitycenter_mcas_integration.yaml renamed successfully. -./azure/azure_cis_v150_2_1_8.yaml renamed successfully. -./azure/azure_cis_v150_1_1_1.yaml renamed successfully. -./azure/azure_network_sg_flowlog_retention_period_greater_than_90.yaml renamed successfully. -./azure/azure_cis_v140_1_13.yaml renamed successfully. -./azure/azure_eventhub_namespace_use_virtual_service_endpoint.yaml renamed successfully. -./azure/azure_kubernetes_cluster_pod_host_path_volume_use_allowed_host_path.yaml renamed successfully. -./azure/azure_cis_v210_2_1_2.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_virtual_network_gateway_mandatory.yaml renamed successfully. -./azure/azure_cis_v130_1_18.yaml renamed successfully. -./azure/azure_cis_v130_1_9.yaml renamed successfully. -./azure/azure_cis_v210_1_23.yaml renamed successfully. -./azure/azure_log_analytics_workspace_block_non_azure_ingestion.yaml renamed successfully. -./azure/azure_kubernetes_cluster_container_privilege_escalation_restricted.yaml renamed successfully. -./azure/azure_cis_v210_7_8.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_cosmosdb_mongo_database_mandatory.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_data_lake_analytics_account_mandatory.yaml renamed successfully. -./azure/azure_appservice_api_app_latest_tls_version.yaml renamed successfully. -./azure/azure_appservice_api_app_client_certificates_on.yaml renamed successfully. -./azure/azure_appservice_function_app_ftps_enabled.yaml renamed successfully. -./azure/azure_appservice_web_app_latest_java_version.yaml renamed successfully. -./azure/azure_storage_account_infrastructure_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v150_5_1_3.yaml renamed successfully. -./azure/azure_cis_v200_1_8.yaml renamed successfully. -./azure/azure_cis_v150_2_2_1.yaml renamed successfully. -./azure/azure_cis_v210_1_2_2.yaml renamed successfully. -./azure/azure_cis_v210_9_5.yaml renamed successfully. -./azure/azure_cis_v200_1_10.yaml renamed successfully. -./azure/azure_cis_v150_1_20.yaml renamed successfully. -./azure/azure_cis_v130_4_3_8.yaml renamed successfully. -./azure/azure_cis_v200_4_3_1.yaml renamed successfully. -./azure/azure_cis_v150_3_9.yaml renamed successfully. -./azure/azure_cis_v200_5_3_1.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_application_security_group_mandatory.yaml renamed successfully. -./azure/azure_logic_app_integration_service_environment_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_135.yaml renamed successfully. -./azure/azure_cis_v140_2_7.yaml renamed successfully. -./azure/azure_kubernetes_cluster_authorized_ip_range_defined.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_appservice.yaml renamed successfully. -./azure/azure_compute_vm_scale_set_boot_diagnostics_enabled.yaml renamed successfully. -./azure/azure_logic_app_workflow_logging_enabled.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_storage_account_mandatory.yaml renamed successfully. -./azure/azure_cis_v130_7_3.yaml renamed successfully. -./azure/azure_container_registry_quarantine_policy_enabled.yaml renamed successfully. -./azure/azure_cis_v210_1_15.yaml renamed successfully. -./azure/azure_storage_account_queue_services_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v210_8_1.yaml renamed successfully. -./azure/azure_cis_v140_7_4.yaml renamed successfully. -./azure/azure_cis_v130_3_4.yaml renamed successfully. -./azure/azure_cosmosdb_use_virtual_service_endpoint.yaml renamed successfully. -./azure/azure_cis_v200_2_1_7.yaml renamed successfully. -./azure/azure_cis_v200_5_2_5.yaml renamed successfully. -./azure/azure_cis_v140_3_3.yaml renamed successfully. -./azure/azure_monitor_log_alert_delete_policy_assignment.yaml renamed successfully. -./azure/azure_cis_v210_4_3_8.yaml renamed successfully. -./azure/azure_cis_v130_2_12.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_1433.yaml renamed successfully. -./azure/azure_compute_vm_administrators_group_with_extra_accounts_windows.yaml renamed successfully. -./azure/azure_cis_v200_3_9.yaml renamed successfully. -./azure/azure_securitycenter_notify_alerts_configured.yaml renamed successfully. -./azure/azure_cis_v140_9_5.yaml renamed successfully. -./azure/azure_keyvault_certificate_validity_12_months.yaml renamed successfully. -./azure/azure_cis_v130_9_2.yaml renamed successfully. -./azure/azure_cis_v150_1_8.yaml renamed successfully. -./azure/azure_cis_v200_2_1_13.yaml renamed successfully. -./azure/azure_cis_v210_3_3.yaml renamed successfully. -./azure/azure_appservice_api_app_ftps_enabled.yaml renamed successfully. -./azure/azure_storage_account_blob_containers_public_access_private.yaml renamed successfully. -./azure/azure_iam_deprecated_account.yaml renamed successfully. -./azure/azure_appservice_web_app_remote_debugging_disabled.yaml renamed successfully. -./azure/azure_cis_v150_2_1_4.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_log_profile_mandatory.yaml renamed successfully. -./azure/azure_cis_v150_5_2_6.yaml renamed successfully. -./azure/azure_cognitive_account_private_link_used.yaml renamed successfully. -./azure/azure_cis_v140_8_1.yaml renamed successfully. -./azure/azure_cis_v210_7_4.yaml renamed successfully. -./azure/azure_keyvault_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v140_1_2.yaml renamed successfully. -./azure/azure_container_instance_container_group_identity_provider_enabled.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_storage.yaml renamed successfully. -./azure/azure_cis_v130_1_5.yaml renamed successfully. -./azure/azure_cis_v130_1_14.yaml renamed successfully. -./azure/azure_sql_server_tde_protector_cmk_encrypted.yaml renamed successfully. -./azure/azure_keyvault_rbac_enabled.yaml renamed successfully. -./azure/azure_cis_v210_3_12.yaml renamed successfully. -./azure/azure_sql_database_vulnerability_findings_resolved.yaml renamed successfully. -./azure/azure_cis_v140_1_9.yaml renamed successfully. -./azure/azure_network_security_group_remote_access_restricted.yaml renamed successfully. -./azure/azure_kubernetes_cluster_sku_standard.yaml renamed successfully. -./azure/azure_storage_account_use_virtual_service_endpoint.yaml renamed successfully. -./azure/azure_keyvault_with_non_rbac_secret_expiration_set.yaml renamed successfully. -./azure/azure_mariadb_server_public_network_access_disabled.yaml renamed successfully. -./azure/azure_cis_v150_9_4.yaml renamed successfully. -./azure/azure_cis_v200_6_1.yaml renamed successfully. -./azure/azure_hdinsight_cluster_encryption_in_transit_enabled.yaml renamed successfully. -./azure/azure_cis_v210_1_24.yaml renamed successfully. -./azure/azure_search_service_uses_sku_supporting_private_link.yaml renamed successfully. -./azure/azure_cis_v200_2_1_18.yaml renamed successfully. -./azure/azure_keyvault_managed_hms_purge_protection_enabled.yaml renamed successfully. -./azure/azure_cis_v210_3_8.yaml renamed successfully. -./azure/azure_cis_v140_1_14.yaml renamed successfully. -./azure/azure_cis_v140_4_4_2.yaml renamed successfully. -./azure/azure_cis_v210_5_2_7.yaml renamed successfully. -./azure/azure_cis_v210_2_1_5.yaml renamed successfully. -./azure/azure_kubernetes_cluster_container_use_allowed_apparmor_profile.yaml renamed successfully. -./azure/azure_postgres_db_server_log_checkpoints_on.yaml renamed successfully. -./azure/azure_authorize_access_to_security_functions_and_information.yaml renamed successfully. -./azure/azure_healthcare_fhir_azure_api_encrypted_at_rest_with_cmk.yaml renamed successfully. -./azure/azure_network_watcher_flow_log_traffic_analytics_enabled.yaml renamed successfully. -./azure/azure_cis_v140_5_1_1.yaml renamed successfully. -./azure/azure_compute_vm_malware_agent_automatic_upgrade_enabled.yaml renamed successfully. -./azure/azure_cis_v140_2_12.yaml renamed successfully. -./azure/azure_appservice_function_app_client_certificates_on.yaml renamed successfully. -./azure/azure_cis_v200_1_21.yaml renamed successfully. -./azure/azure_compute_vm_meet_security_option_audit_requirement_windows.yaml renamed successfully. -./azure/azure_cis_v130_4_1_2.yaml renamed successfully. -./azure/azure_cis_v130_9_9.yaml renamed successfully. -./azure/azure_cis_v200_7_5.yaml renamed successfully. -./azure/azure_audit_diagnostic_setting.yaml renamed successfully. -./azure/azure_cis_v130_5_1_2.yaml renamed successfully. -./azure/azure_cis_v150_1_3.yaml renamed successfully. -./azure/azure_cosmosdb_account_encryption_at_rest_using_cmk.yaml renamed successfully. -./azure/azure_cis_v150_1_11.yaml renamed successfully. -./azure/azure_compute_vm_administrators_group_with_specified_members_windows.yaml renamed successfully. -./azure/azure_kusto_cluster_disk_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v210_2_1_15.yaml renamed successfully. -./azure/azure_keyvault_key_expiration_set.yaml renamed successfully. -./azure/azure_sql_db_active_directory_admin_configured.yaml renamed successfully. -./azure/azure_cis_v200_3_2.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_mssql_managed_instance_mandatory.yaml renamed successfully. -./azure/azure_cis_v200_2_1_22.yaml renamed successfully. -./azure/azure_cis_v130_5_2_7.yaml renamed successfully. -./azure/azure_cis_v150_2_6.yaml renamed successfully. -./azure/azure_network_lb_no_basic_sku.yaml renamed successfully. -./azure/azure_cis_v140_5_2_4.yaml renamed successfully. -./azure/azure_cis_v210_4_4_1.yaml renamed successfully. -./azure/azure_cis_v140_3_8.yaml renamed successfully. -./azure/azuread_spn_with_more_than_one_active_client_secret_created_x_days_ago.yaml renamed successfully. -./azure/azure_application_gateway_waf_enabled.yaml renamed successfully. -./azure/azure_compute_vm_log_analytics_agent_installed_windows.yaml renamed successfully. -./azure/azure_cis_v200_9_4.yaml renamed successfully. -./azure/azure_cis_v150_6_1.yaml renamed successfully. -./azure/azure_compute_vm_scale_set_uses_managed_disks.yaml renamed successfully. -./azure/azure_container_registry_geo_replication_enabled.yaml renamed successfully. -./azure/azure_cis_v210_1_9.yaml renamed successfully. -./azure/azure_eventhub_namespace_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v200_5_4.yaml renamed successfully. -./azure/azure_compute_disk_access_uses_private_link.yaml renamed successfully. -./azure/azure_cis_v150_3_2.yaml renamed successfully. -./azure/azure_cosmosdb_account_with_firewall_rules.yaml renamed successfully. -./azure/azure_machine_learning_workspace_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_compute_vm_windows_defender_exploit_guard_enabled.yaml renamed successfully. -./azure/azure_postgres_db_server_log_retention_days_3.yaml renamed successfully. -./azure/azure_cis_v150_7_5.yaml renamed successfully. -./azure/azure_redis_cache_uses_private_link.yaml renamed successfully. -./azure/azure_cis_v200_1_3.yaml renamed successfully. -./azure/azure_databox_job_double_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v150_1_2_3.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_app_service_function_app_mandatory.yaml renamed successfully. -./azure/azure_compute_vm_restrict_previous_24_passwords_resuse_windows.yaml renamed successfully. -./azure/azure_eventgrid_domain_private_link_used.yaml renamed successfully. -./azure/azure_cis_v210_4_1_2.yaml renamed successfully. -./azure/azure_compute_vm_vulnerability_assessment_solution_enabled.yaml renamed successfully. -./azure/azure_securitycenter_additional_email_configured.yaml renamed successfully. -./azure/azure_cis_v210_5_1_2.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_mysql_server_mandatory.yaml renamed successfully. -./azure/azure_cis_v130_8_1.yaml renamed successfully. -./azure/azure_cis_v150_9_8.yaml renamed successfully. -./azure/azure_cis_v130_1_2.yaml renamed successfully. -./azure/azure_cis_v130_1_13.yaml renamed successfully. -./azure/azure_cis_v210_3_15.yaml renamed successfully. -./azure/azure_storage_account_encryption_at_rest_using_cmk.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_compute_availability_set_mandatory.yaml renamed successfully. -./azure/azure_compute_vm_password_complexity_setting_enabled_windows.yaml renamed successfully. -./azure/azure_cis_v140_1_5.yaml renamed successfully. -./azure/azure_cis_v210_7_3.yaml renamed successfully. -./azure/azure_cis_v140_8_6.yaml renamed successfully. -./azure/azure_monitor_application_insights_configured.yaml renamed successfully. -./azure/azure_frontdoor_waf_enabled.yaml renamed successfully. -./azure/azure_appservice_web_app_latest_dotnet_framework_version.yaml renamed successfully. -./azure/azure_cis_v150_5_2_1.yaml renamed successfully. -./azure/azure_cis_v150_2_1_3.yaml renamed successfully. -./azure/azure_appservice_web_app_latest_http_version.yaml renamed successfully. -./azure/azure_cis_v140_1_18.yaml renamed successfully. -./azure/azure_cis_v210_3_4.yaml renamed successfully. -./azure/azure_cis_v200_10_1.yaml renamed successfully. -./azure/azure_cis_v200_2_1_14.yaml renamed successfully. -./azure/azure_cis_v200_3_10.yaml renamed successfully. -./azure/azure_cis_v200_5_1_7.yaml renamed successfully. -./azure/azure_cis_v130_9_5.yaml renamed successfully. -./azure/azure_appservice_web_app_http_logs_enabled.yaml renamed successfully. -./azure/azure_cis_v140_9_2.yaml renamed successfully. -./azure/azure_cis_v210_6_7.yaml renamed successfully. -./azure/azure_mariadb_server_geo_redundant_backup_enabled.yaml renamed successfully. -./azure/azure_kubernetes_cluster_network_policy_enabled.yaml renamed successfully. -./azure/azure_postgres_db_server_log_connections_on.yaml renamed successfully. -./azure/azure_compute_vm_secure_communication_protocols_configured.yaml renamed successfully. -./azure/azure_compute_vm_min_password_age_1_day_windows.yaml renamed successfully. -./azure/azure_cis_v210_2_1_19.yaml renamed successfully. -./azure/azure_cis_v130_2_15.yaml renamed successfully. -./azure/azure_sql_database_allow_internet_access.yaml renamed successfully. -./azure/azure_cis_v140_5_2_8.yaml renamed successfully. -./azure/azure_cis_v140_3_4.yaml renamed successfully. -./azure/azure_cis_v140_1_22.yaml renamed successfully. -./azure/azure_cis_v130_3_3.yaml renamed successfully. -./azure/azure_cis_v200_5_2_2.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_23.yaml renamed successfully. -./azure/azure_appservice_web_app_uses_managed_identity.yaml renamed successfully. -./azure/azure_cis_v210_1_12.yaml renamed successfully. -./azure/azure_iam_user_no_built_in_contributor_role.yaml renamed successfully. -./azure/azure_monitor_log_profile_enabled_for_all_categories.yaml renamed successfully. -./azure/azure_cis_v210_1_5.yaml renamed successfully. -./azure/azure_cis_v140_7_3.yaml renamed successfully. -./azure/azure_cis_v210_8_6.yaml renamed successfully. -./azure/azure_compute_vm_meet_security_option_requirement_windows.yaml renamed successfully. -./azure/azure_cis_v200_9_8.yaml renamed successfully. -./azure/azure_cis_v130_7_4.yaml renamed successfully. -./azure/azure_cis_v150_2_3_2.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_mariadb_server_mandatory.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_keyvault.yaml renamed successfully. -./azure/azure_compute_vm_meet_security_options_network_access_requirement_windows.yaml renamed successfully. -./azure/azure_monitor_logs_storage_container_insights_operational_logs_not_public_accessible.yaml renamed successfully. -./azure/azure_automation_account_variable_encryption_enabled.yaml renamed successfully. -./azure/azure_sql_server_va_setting_reports_notify_admins.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_containerregistry.yaml renamed successfully. -./azure/azure_compute_vm_with_no_specified_certificates_in_trusted_root_windows.yaml renamed successfully. -./azure/azure_app_service_environment_internal_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v130_2_7.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_servicebus_namespace_mandatory.yaml renamed successfully. -./azure/azure_network_security_group_https_access_restricted.yaml renamed successfully. -./azure/azure_cis_v210_9_2.yaml renamed successfully. -./azure/azure_cis_v210_1_2_5.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_sqldb.yaml renamed successfully. -./azure/azure_cis_v200_1_17.yaml renamed successfully. -./azure/azure_cis_v150_4_1_4.yaml renamed successfully. -./azure/azure_compute_vm_utilizing_managed_disk.yaml renamed successfully. -./azure/azure_cis_v150_5_1_5.yaml renamed successfully. -./azure/azure_compute_vm_network_traffic_data_collection_linux_agent_installed.yaml renamed successfully. -./azure/azure_cis_v150_9_11.yaml renamed successfully. -./azure/azure_cis_v130_6_1.yaml renamed successfully. -./azure/azure_cis_v150_4_1_5.yaml renamed successfully. -./azure/azure_monitor_log_alert_create_policy_assignment.yaml renamed successfully. -./azure/azure_cis_v140_6_6.yaml renamed successfully. -./azure/azure_cis_v210_9_3.yaml renamed successfully. -./azure/azure_eventhub_namespace_private_link_used.yaml renamed successfully. -./azure/azure_cis_v210_1_2_4.yaml renamed successfully. -./azure/azure_cis_v200_1_16.yaml renamed successfully. -./azure/azure_cis_v150_4_5_2.yaml renamed successfully. -./azure/azure_cis_v130_2_6.yaml renamed successfully. -./azure/azure_sql_db_public_network_access_disabled.yaml renamed successfully. -./azure/azure_network_public_ip_no_basic_sku.yaml renamed successfully. -./azure/azure_cis_v200_4_3_7.yaml renamed successfully. -./azure/azure_data_factory_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_cis_v140_2_1.yaml renamed successfully. -./azure/azure_cognitive_account_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_firewall_mandatory.yaml renamed successfully. -./azure/azure_eventgrid_topic_identity_provider_enabled.yaml renamed successfully. -./azure/azure_cis_v210_2_1_22.yaml renamed successfully. -./azure/azure_storage_account_blob_service_logging_enabled.yaml renamed successfully. -./azure/azure_signalr_service_no_free_tier_sku.yaml renamed successfully. -./azure/azure_cis_v200_9_9.yaml renamed successfully. -./azure/azure_cis_v130_7_5.yaml renamed successfully. -./azure/azure_batch_account_identity_provider_enabled.yaml renamed successfully. -./azure/azure_cis_v150_2_3_3.yaml renamed successfully. -./azure/azure_cis_v210_1_13.yaml renamed successfully. -./azure/azure_kubernetes_cluster_addon_azure_policy_enabled.yaml renamed successfully. -./azure/azure_network_bastion_host_min_1.yaml renamed successfully. -./azure/azure_cis_v210_1_4.yaml renamed successfully. -./azure/azure_cis_v140_7_2.yaml renamed successfully. -./azure/azure_compute_vm_passwords_stored_using_reversible_encryption_windows.yaml renamed successfully. -./azure/azure_servicebus_namespace_no_overly_permissive_network_access.yaml renamed successfully. -./azure/azure_cis_v130_3_2.yaml renamed successfully. -./azure/azure_cis_v200_5_2_3.yaml renamed successfully. -./azure/azure_cis_v200_2_1_1.yaml renamed successfully. -./azure/azure_storage_account_min_tls_1_2.yaml renamed successfully. -./azure/azure_cis_v140_5_2_9.yaml renamed successfully. -./azure/azure_recovery_service_vault_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_cis_v130_2_14.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_cosmosdb_account_mandatory.yaml renamed successfully. -./azure/azure_network_ddos_enabled.yaml renamed successfully. -./azure/azure_cis_v210_2_1_18.yaml renamed successfully. -./azure/azure_appservice_web_app_failed_request_tracing_enabled.yaml renamed successfully. -./azure/azure_cis_v200_4_5_1.yaml renamed successfully. -./azure/azure_sql_server_uses_private_link.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_udp_port_138.yaml renamed successfully. -./azure/azure_cis_v210_6_6.yaml renamed successfully. -./azure/azure_cis_v140_9_3.yaml renamed successfully. -./azure/azure_appservice_web_app_client_certificates_on.yaml renamed successfully. -./azure/azure_cis_v200_3_11.yaml renamed successfully. -./azure/azure_kubernetes_cluster_privilege_containers_restricted.yaml renamed successfully. -./azure/azure_cis_v200_5_1_6.yaml renamed successfully. -./azure/azure_cis_v150_2_4_1.yaml renamed successfully. -./azure/azure_cis_v130_9_4.yaml renamed successfully. -./azure/azure_iam_user_not_allowed_to_create_security_group.yaml renamed successfully. -./azure/azure_compute_vm_container_security_configurations_vulnerabilities_remediated.yaml renamed successfully. -./azure/azure_cis_v210_1_1_1.yaml renamed successfully. -./azure/azure_cis_v140_1_19.yaml renamed successfully. -./azure/azure_cis_v210_3_5.yaml renamed successfully. -./azure/azure_cis_v140_5_3.yaml renamed successfully. -./azure/azure_cis_v200_2_1_15.yaml renamed successfully. -./azure/azure_cis_v210_2_1_8.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_network_interface_mandatory.yaml renamed successfully. -./azure/azure_cis_v150_2_1_2.yaml renamed successfully. -./azure/azure_monitor_diagnostic_settings_captures_proper_categories.yaml renamed successfully. -./azure/azure_cis_v140_1_4.yaml renamed successfully. -./azure/azure_cis_v140_8_7.yaml renamed successfully. -./azure/azure_cis_v210_7_2.yaml renamed successfully. -./azure/azure_compute_vm_and_sacle_set_encryption_at_host_enabled.yaml renamed successfully. -./azure/azure_cis_v150_9_9.yaml renamed successfully. -./azure/azure_appservice_function_app_remote_debugging_disabled.yaml renamed successfully. -./azure/azure_cis_v130_1_3.yaml renamed successfully. -./azure/azure_cis_v130_1_12.yaml renamed successfully. -./azure/azure_mysql_ssl_enabled.yaml renamed successfully. -./azure/azure_cis_v210_3_14.yaml renamed successfully. -./azure/azure_network_security_group_outbound_access_restricted.yaml renamed successfully. -./azure/azure_compute_vm_temp_disks_cache_and_data_flows_encrypted.yaml renamed successfully. -./azure/azure_mysql_server_infrastructure_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v210_2_2_1.yaml renamed successfully. -./azure/azure_cis_v210_5_1_3.yaml renamed successfully. -./azure/azure_mysql_server_min_tls_1_2.yaml renamed successfully. -./azure/azure_cis_v200_8_1.yaml renamed successfully. -./azure/azure_cis_v150_7_4.yaml renamed successfully. -./azure/azure_eventgrid_domain_restrict_public_access.yaml renamed successfully. -./azure/azure_compute_vm_log_analytics_agent_installed.yaml renamed successfully. -./azure/azure_cis_v150_1_2_2.yaml renamed successfully. -./azure/azure_securitycenter_automatic_provisioning_monitoring_agent_on.yaml renamed successfully. -./azure/azure_servicebus_use_virtual_service_endpoint.yaml renamed successfully. -./azure/azure_postgres_db_server_log_disconnections_on.yaml renamed successfully. -./azure/azure_cis_v140_4_3_1.yaml renamed successfully. -./azure/azure_monitor_log_alert_create_update_security_solution.yaml renamed successfully. -./azure/azure_cis_v130_4_3_2.yaml renamed successfully. -./azure/azure_cis_v150_3_3.yaml renamed successfully. -./azure/azure_container_registry_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_cosmosdb_account_uses_private_link.yaml renamed successfully. -./azure/azure_kusto_cluster_sku_with_sla.yaml renamed successfully. -./azure/azure_cis_v210_1_8.yaml renamed successfully. -./azure/azure_network_security_group_udp_service_restricted.yaml renamed successfully. -./azure/azure_application_insights_block_log_ingestion_and_querying_from_public.yaml renamed successfully. -./azure/azure_data_factory_uses_private_link.yaml renamed successfully. -./azure/azure_cis_v200_9_5.yaml renamed successfully. -./azure/azure_cis_v140_5_2_5.yaml renamed successfully. -./azure/azure_kubernetes_cluster_upgraded_with_non_vulnerable_version.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_3306.yaml renamed successfully. -./azure/azure_cis_v140_3_9.yaml renamed successfully. -./azure/azure_sql_database_long_term_geo_redundant_backup_enabled.yaml renamed successfully. -./azure/azure_compute_vm_guest_configuration_installed.yaml renamed successfully. -./azure/azure_cis_v200_1_1_4.yaml renamed successfully. -./azure/azure_cis_v130_5_2_6.yaml renamed successfully. -./azure/azure_cis_v140_3_12.yaml renamed successfully. -./azure/azure_cis_v210_2_1_14.yaml renamed successfully. -./azure/azure_storage_account_uses_private_link.yaml renamed successfully. -./azure/azure_appservice_web_app_latest_tls_version.yaml renamed successfully. -./azure/azure_iam_no_custom_subscription_owner_roles_created.yaml renamed successfully. -./azure/azure_compute_vm_security_configuration_vulnerabilities_remediated.yaml renamed successfully. -./azure/azure_mariadb_server_ssl_enabled.yaml renamed successfully. -./azure/azure_cis_v150_4_3_8.yaml renamed successfully. -./azure/azure_cis_v200_3_3.yaml renamed successfully. -./azure/azure_compute_vm_guest_configuration_with_no_managed_identity.yaml renamed successfully. -./azure/azure_iam_user_not_allowed_to_register_application.yaml renamed successfully. -./azure/azure_cis_v150_1_10.yaml renamed successfully. -./azure/azure_recovery_service_vault_uses_private_link.yaml renamed successfully. -./azure/azure_cis_v140_2_13.yaml renamed successfully. -./azure/azure_cis_v200_1_2_1.yaml renamed successfully. -./azure/azure_cis_v200_1_20.yaml renamed successfully. -./azure/azure_cis_v130_9_8.yaml renamed successfully. -./azure/azure_datalake_analytics_account_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v150_8_1.yaml renamed successfully. -./azure/azure_cis_v200_7_4.yaml renamed successfully. -./azure/azure_cis_v130_5_1_3.yaml renamed successfully. -./azure/azure_batch_account_logging_enabled.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_batch_account_mandatory.yaml renamed successfully. -./azure/azure_compute_vm_scale_set_ssh_key_authentication_linux.yaml renamed successfully. -./azure/azure_monitor_log_alert_delete_security_solution.yaml renamed successfully. -./azure/azure_compute_vm_meet_security_baseline_requirements_windows.yaml renamed successfully. -./azure/azure_cis_v200_2_1_19.yaml renamed successfully. -./azure/azure_cis_v210_3_9.yaml renamed successfully. -./azure/azure_cis_v140_1_15.yaml renamed successfully. -./azure/azure_cis_v210_5_2_6.yaml renamed successfully. -./azure/azure_cis_v210_2_1_4.yaml renamed successfully. -./azure/azure_cis_v150_9_5.yaml renamed successfully. -./azure/azure_compute_disk_unattached_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_key_vault_mandatory.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_logic_app_workflow_mandatory.yaml renamed successfully. -./azure/azure_cis_v210_1_25.yaml renamed successfully. -./azure/azure_compute_vm_password_file_permissions_0644_linux.yaml renamed successfully. -./azure/azure_storage_account_block_public_access.yaml renamed successfully. -./azure/azure_arc_compute_machine_windows_log_analytics_agent_installed.yaml renamed successfully. -./azure/azure_cis_v200_1_19.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_containers.yaml renamed successfully. -./azure/azure_redis_cache_ssl_enabled.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_container_registry_mandatory.yaml renamed successfully. -./azure/azure_cis_v150_1_2_1.yaml renamed successfully. -./azure/azure_cis_v200_8_2.yaml renamed successfully. -./azure/azure_securitycenter_container_image_scan_enabled.yaml renamed successfully. -./azure/azure_compute_vm_guest_configuration_with_user_and_system_assigned_managed_identity.yaml renamed successfully. -./azure/azure_machine_learning_workspace_private_link_used.yaml renamed successfully. -./azure/azure_cis_v130_2_9.yaml renamed successfully. -./azure/azure_cis_v150_3_14.yaml renamed successfully. -./azure/azure_cis_v130_4_3_1.yaml renamed successfully. -./azure/azure_cis_v200_4_3_8.yaml renamed successfully. -./azure/azure_cis_v210_8_8.yaml renamed successfully. -./azure/azure_compute_vm_malware_agent_installed.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_key_vault_key_mandatory.yaml renamed successfully. -./azure/azure_cis_v150_6_3.yaml renamed successfully. -./azure/azure_cis_v200_9_6.yaml renamed successfully. -./azure/azure_container_instance_container_group_in_virtual_network.yaml renamed successfully. -./azure/azure_cis_v140_5_2_6.yaml renamed successfully. -./azure/azure_iot_hub_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v140_3_11.yaml renamed successfully. -./azure/azure_cis_v200_2_1_20.yaml renamed successfully. -./azure/azure_cis_v130_5_2_5.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_route_table_mandatory.yaml renamed successfully. -./azure/azure_automation_account_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_network_security_group_mandatory.yaml renamed successfully. -./azure/azure_cis_v210_2_1_17.yaml renamed successfully. -./azure/azure_eventhub_namespace_cmk_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v210_5_3_1.yaml renamed successfully. -./azure/azure_cis_v210_4_3_1.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_k8s.yaml renamed successfully. -./azure/azure_container_registry_uses_private_link.yaml renamed successfully. -./azure/azure_cis_v150_8_2.yaml renamed successfully. -./azure/azure_cis_v200_7_7.yaml renamed successfully. -./azure/azure_cis_v140_2_10.yaml renamed successfully. -./azure/azure_cis_v200_1_2_2.yaml renamed successfully. -./azure/azure_cis_v200_1_23.yaml renamed successfully. -./azure/azure_web_pub_sub_private_link_used.yaml renamed successfully. -./azure/azure_securitycenter_wdatp_integration.yaml renamed successfully. -./azure/azure_sql_server_azure_defender_enabled.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_udp_port_137.yaml renamed successfully. -./azure/azure_cis_v140_5_1_3.yaml renamed successfully. -./azure/azure_kusto_cluster_double_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v150_1_1_4.yaml renamed successfully. -./azure/azure_keyvault_with_rbac_key_expiration_set.yaml renamed successfully. -./azure/azure_compute_vm_guest_configuration_installed_linux.yaml renamed successfully. -./azure/azure_compute_vm_allowlist_rules_in_adaptive_application_control_policy_updated.yaml renamed successfully. -./azure/azure_cis_v210_5_2_5.yaml renamed successfully. -./azure/azure_cis_v210_2_1_7.yaml renamed successfully. -./azure/azure_cis_v140_1_16.yaml renamed successfully. -./azure/azure_postgres_sql_server_encrypted_at_rest_using_cmk.yaml renamed successfully. -./azure/azure_cis_v200_6_3.yaml renamed successfully. -./azure/azure_cis_v150_9_6.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_api_management_mandatory.yaml renamed successfully. -./azure/azure_appservice_function_app_latest_http_version.yaml renamed successfully. -./azure/azure_spring_cloud_service_network_injection_enabled.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_network_watcher_flow_log_mandatory.yaml renamed successfully. -./azure/azure_compute_vm_vulnerability_findings_resolved_for_sql_server.yaml renamed successfully. -./azure/azure_cis_v130_6_2.yaml renamed successfully. -./azure/azure_cis_v150_5_1_6.yaml renamed successfully. -./azure/azure_cis_v200_1_15.yaml renamed successfully. -./azure/azure_monitor_log_alert_for_administrative_operations.yaml renamed successfully. -./azure/azure_search_service_uses_managed_identity.yaml renamed successfully. -./azure/azure_iam_deprecated_account_with_owner_roles.yaml renamed successfully. -./azure/azure_cis_v210_1_2_7.yaml renamed successfully. -./azure/azure_compute_vm_data_and_os_disk_uses_managed_disk.yaml renamed successfully. -./azure/azure_sql_server_auditing_retention_period_90.yaml renamed successfully. -./azure/azure_cis_v150_1_25.yaml renamed successfully. -./azure/azure_cis_v150_4_5_1.yaml renamed successfully. -./azure/azure_cis_v130_2_5.yaml renamed successfully. -./azure/azure_cis_v210_2_1_21.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_server.yaml renamed successfully. -./azure/azure_cis_v140_2_2.yaml renamed successfully. -./azure/azure_eventgrid_domain_identity_provider_enabled.yaml renamed successfully. -./azure/azure_cis_v130_7_6.yaml renamed successfully. -./azure/azure_container_registry_retention_policy_enabled.yaml renamed successfully. -./azure/azure_cis_v210_8_4.yaml renamed successfully. -./azure/azure_arc_compute_machine_linux_log_analytics_agent_installed.yaml renamed successfully. -./azure/azure_cis_v140_7_1.yaml renamed successfully. -./azure/azure_cis_v210_1_7.yaml renamed successfully. -./azure/azure_bot_service_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_monitor_log_alert_delete_nsg_rule.yaml renamed successfully. -./azure/azure_storage_account_blobs_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v210_1_10.yaml renamed successfully. -./azure/azure_securitycenter_pricing_standard.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_compute_disk_encryption_set_mandatory.yaml renamed successfully. -./azure/azure_cis_v130_3_1.yaml renamed successfully. -./azure/azure_storage_account_secure_transfer_required_enabled.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_21.yaml renamed successfully. -./azure/azure_cis_v130_5_2_9.yaml renamed successfully. -./azure/azure_cis_v200_2_1_2.yaml renamed successfully. -./azure/azure_cis_v140_1_20.yaml renamed successfully. -./azure/azure_postgres_db_server_allow_access_to_azure_services_disabled.yaml renamed successfully. -./azure/azure_monitor_log_cluster_infrastructure_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v140_3_6.yaml renamed successfully. -./azure/azure_keyvault_vault_use_virtual_service_endpoint.yaml renamed successfully. -./azure/azure_securitycenter_asc_default_setting_not_disabled.yaml renamed successfully. -./azure/azure_app_configuration_private_link_used.yaml renamed successfully. -./azure/azure_cis_v150_4_3_7.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_opensource_relational_db.yaml renamed successfully. -./azure/azure_cis_v200_4_5_2.yaml renamed successfully. -./azure/azure_network_security_group_ssh_access_restricted.yaml renamed successfully. -./azure/azure_sql_server_use_virtual_service_endpoint.yaml renamed successfully. -./azure/azure_compute_vm_meet_security_options_user_account_control_requirement_windows.yaml renamed successfully. -./azure/azure_monitor_logs_storage_container_insights_activity_logs_not_public_accessible.yaml renamed successfully. -./azure/azure_compute_vm_scale_set_log_analytics_agent_installed.yaml renamed successfully. -./azure/azure_cis_v130_9_7.yaml renamed successfully. -./azure/azure_cis_v150_2_4_2.yaml renamed successfully. -./azure/azure_eventgrid_topic_private_link_used.yaml renamed successfully. -./azure/azure_cis_v200_5_1_5.yaml renamed successfully. -./azure/azure_cis_v200_3_12.yaml renamed successfully. -./azure/azure_compute_vm_azure_backup_enabled.yaml renamed successfully. -./azure/azure_cis_v210_5_2_9.yaml renamed successfully. -./azure/azure_cis_v200_2_1_16.yaml renamed successfully. -./azure/azure_cis_v210_1_1_2.yaml renamed successfully. -./azure/azure_cis_v210_3_6.yaml renamed successfully. -./azure/azure_appservice_web_app_latest_python_version.yaml renamed successfully. -./azure/azure_cis_v150_5_2_3.yaml renamed successfully. -./azure/azure_cis_v150_2_1_1.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_sqlservervm.yaml renamed successfully. -./azure/azure_cis_v140_8_4.yaml renamed successfully. -./azure/azure_cis_v210_7_1.yaml renamed successfully. -./azure/azure_cis_v140_1_7.yaml renamed successfully. -./azure/azure_cis_v130_1_11.yaml renamed successfully. -./azure/azure_cis_v130_8_3.yaml renamed successfully. -./azure/azure_compute_os_and_data_disk_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_cis_v210_3_16.yaml renamed successfully. -./azure/azure_cis_v130_1_1.yaml renamed successfully. -./azure/azure_storage_account_table_service_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v130_1_10.yaml renamed successfully. -./azure/azure_cis_v130_8_2.yaml renamed successfully. -./azure/azure_cis_v140_8_5.yaml renamed successfully. -./azure/azure_appservice_web_app_always_on.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_sql_database_mandatory.yaml renamed successfully. -./azure/azure_compute_vm_meet_security_baseline_requirements_linux.yaml renamed successfully. -./azure/azure_cosmosdb_account_virtual_network_filter_enabled.yaml renamed successfully. -./azure/azure_cis_v150_5_2_2.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_public_ip_mandatory.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_key_vault_managed_hardware_security_module_mandatory.yaml renamed successfully. -./azure/azure_keyvault_soft_delete_enabled.yaml renamed successfully. -./azure/azure_cis_v210_5_2_8.yaml renamed successfully. -./azure/azure_container_instance_container_group_secured_environment_variable.yaml renamed successfully. -./azure/azure_network_network_peering_connected.yaml renamed successfully. -./azure/azure_postgres_db_server_geo_redundant_backup_enabled.yaml renamed successfully. -./azure/azure_cis_v200_2_1_17.yaml renamed successfully. -./azure/azure_cis_v210_1_1_3.yaml renamed successfully. -./azure/azure_monitor_log_alert_sql_firewall_rule.yaml renamed successfully. -./azure/azure_cis_v210_3_7.yaml renamed successfully. -./azure/azure_cis_v130_9_6.yaml renamed successfully. -./azure/azure_cis_v200_4_1_4.yaml renamed successfully. -./azure/azure_postgres_db_server_latest_tls_version.yaml renamed successfully. -./azure/azure_cis_v140_9_1.yaml renamed successfully. -./azure/azure_cis_v210_6_4.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_compute_virtual_machine_scale_set_mandatory.yaml renamed successfully. -./azure/azure_compute_vm_uses_azure_resource_manager.yaml renamed successfully. -./azure/azure_compute_vm_adaptive_application_controls_enabled.yaml renamed successfully. -./azure/azure_cis_v200_4_5_3.yaml renamed successfully. -./azure/azure_container_instance_container_group_encrypted_using_cmk.yaml renamed successfully. -./azure/azure_storage_account_restrict_network_access.yaml renamed successfully. -./azure/azure_cis_v140_4_5.yaml renamed successfully. -./azure/azure_storage_account_uses_azure_resource_manager.yaml renamed successfully. -./azure/azure_appservice_function_app_latest_tls_version.yaml renamed successfully. -./azure/azure_cis_v140_3_7.yaml renamed successfully. -./azure/azure_cis_v200_5_2_1.yaml renamed successfully. -./azure/azure_cis_v130_5_2_8.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_20.yaml renamed successfully. -./azure/azure_cis_v200_2_1_3.yaml renamed successfully. -./azure/azure_cis_v140_1_21.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_compute_virtual_machine_mandatory.yaml renamed successfully. -./azure/azure_cis_v210_8_5.yaml renamed successfully. -./azure/azure_cis_v210_1_6.yaml renamed successfully. -./azure/azure_compute_vm_adaptive_network_hardening_recommendation_applied.yaml renamed successfully. -./azure/azure_cis_v210_1_11.yaml renamed successfully. -./azure/azure_cis_v150_2_3_1.yaml renamed successfully. -./azure/azure_hdinsight_cluster_encrypted_at_rest_with_cmk.yaml renamed successfully. -./azure/azure_cis_v130_7_7.yaml renamed successfully. -./azure/azure_network_watcher_enabled.yaml renamed successfully. -./azure/azure_postgres_server_private_link_used.yaml renamed successfully. -./azure/azure_cis_v210_2_1_20.yaml renamed successfully. -./azure/azure_cis_v140_2_3.yaml renamed successfully. -./azure/azure_app_configuration_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v200_4_3_5.yaml renamed successfully. -./azure/azure_cis_v150_1_24.yaml renamed successfully. -./azure/azure_cis_v130_2_4.yaml renamed successfully. -./azure/azure_cis_v200_1_14.yaml renamed successfully. -./azure/azure_cis_v210_1_2_6.yaml renamed successfully. -./azure/azure_keyvault_vault_recoverable.yaml renamed successfully. -./azure/azure_cis_v210_9_1.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_stream_analytics_job_mandatory.yaml renamed successfully. -./azure/azure_network_sg_flowlog_enabled.yaml renamed successfully. -./azure/azure_cis_v130_6_3.yaml renamed successfully. -./azure/azure_cis_v150_5_1_7.yaml renamed successfully. -./azure/azure_monitor_log_profile_enabled_for_all_regions.yaml renamed successfully. -./azure/azure_cis_v150_9_7.yaml renamed successfully. -./azure/azure_cis_v200_6_2.yaml renamed successfully. -./azure/azure_healthcare_fhir_uses_private_link.yaml renamed successfully. -./azure/azure_monitor_log_alert_create_update_sql_servers_firewall_rule.yaml renamed successfully. -./azure/azure_kubernetes_cluster_pods_and_containers_uses_approved_user_and_group_id.yaml renamed successfully. -./azure/azure_cis_v140_4_4_1.yaml renamed successfully. -./azure/azure_cis_v210_5_2_4.yaml renamed successfully. -./azure/azure_cis_v210_2_1_6.yaml renamed successfully. -./azure/azure_network_watcher_in_regions_with_virtual_network.yaml renamed successfully. -./azure/azure_cis_v140_1_17.yaml renamed successfully. -./azure/azure_cis_v210_9_10.yaml renamed successfully. -./azure/azure_compute_vm_ssh_key_authentication_linux.yaml renamed successfully. -./azure/azure_hdinsight_cluster_encryption_at_host_enabled.yaml renamed successfully. -./azure/azure_cis_v140_5_1_2.yaml renamed successfully. -./azure/azure_ad_guest_user_reviewed_monthly.yaml renamed successfully. -./azure/azure_cis_v140_4_1_2.yaml renamed successfully. -./azure/azure_monitor_log_alert_create_update_nsg.yaml renamed successfully. -./azure/azure_cis_v130_5_1_1.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_dns.yaml renamed successfully. -./azure/azure_cis_v200_7_6.yaml renamed successfully. -./azure/azure_cis_v150_8_3.yaml renamed successfully. -./azure/azure_securitycenter_email_configured.yaml renamed successfully. -./azure/azure_cis_v140_2_11.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_445.yaml renamed successfully. -./azure/azure_cis_v200_1_2_3.yaml renamed successfully. -./azure/azure_cis_v200_1_22.yaml renamed successfully. -./azure/azure_compute_vm_account_with_password_linux.yaml renamed successfully. -./azure/azure_cis_v150_1_12.yaml renamed successfully. -./azure/azure_compute_vm_endpoint_protection_agent_installed.yaml renamed successfully. -./azure/azure_servicebus_premium_namespace_cmk_encrypted.yaml renamed successfully. -./azure/azure_cis_v200_3_1.yaml renamed successfully. -./azure/azure_compute_vm_network_traffic_data_collection_windows_agent_installed.yaml renamed successfully. -./azure/azure_cis_v210_2_1_16.yaml renamed successfully. -./azure/azure_cis_v140_3_10.yaml renamed successfully. -./azure/azure_cis_v200_2_1_21.yaml renamed successfully. -./azure/azure_cis_v130_5_2_4.yaml renamed successfully. -./azure/azure_eventgrid_topic_local_auth_enabled.yaml renamed successfully. -./azure/azure_cis_v150_2_5.yaml renamed successfully. -./azure/azure_synapse_workspace_private_link_used.yaml renamed successfully. -./azure/azure_mysql_server_public_network_access_disabled.yaml renamed successfully. -./azure/azure_cis_v130_9_11.yaml renamed successfully. -./azure/azure_cis_v140_5_2_7.yaml renamed successfully. -./azure/azure_cis_v210_4_4_2.yaml renamed successfully. -./azure/azure_cis_v200_9_7.yaml renamed successfully. -./azure/azure_cis_v150_6_2.yaml renamed successfully. -./azure/azure_network_security_group_diagnostic_setting_deployed.yaml renamed successfully. -./azure/azure_iam_subscription_owner_more_than_1.yaml renamed successfully. -./azure/azure_kubernetes_cluster_https_enabled.yaml renamed successfully. -./azure/azure_mssql_managed_instance_encryption_at_rest_using_cmk.yaml renamed successfully. -./azure/azure_cis_v130_2_8.yaml renamed successfully. -./azure/azure_cis_v150_3_1.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_search_service_mandatory.yaml renamed successfully. -./azure/azure_cis_v150_3_15.yaml renamed successfully. -./azure/azure_cis_v150_7_6.yaml renamed successfully. -./azure/azure_cis_v200_8_3.yaml renamed successfully. -./azure/azure_cis_v210_5_1_1.yaml renamed successfully. -./azure/azure_cis_v200_1_18.yaml renamed successfully. -./azure/azure_application_gateway_waf_uses_specified_mode.yaml renamed successfully. -./azure/azure_compute_vm_guest_configuration_with_system_assigned_managed_identity.yaml renamed successfully. -./azure/azure_cis_v150_2_2_2.yaml renamed successfully. -./azure/azure_cis_v200_8_8.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_lb_mandatory.yaml renamed successfully. -./azure/azure_cis_v200_1_13.yaml renamed successfully. -./azure/azure_cis_v140_6_3.yaml renamed successfully. -./azure/azure_cis_v210_9_6.yaml renamed successfully. -./azure/azure_cis_v210_1_2_1.yaml renamed successfully. -./azure/azure_keyvault_purge_protection_enabled.yaml renamed successfully. -./azure/azure_cis_v130_2_3.yaml renamed successfully. -./azure/azure_kubernetes_cluster_add_on_azure_policy_enabled.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_udp_port_445.yaml renamed successfully. -./azure/azure_cis_v150_1_23.yaml renamed successfully. -./azure/azure_storage_account_soft_delete_enabled.yaml renamed successfully. -./azure/azure_cis_v140_4_3_8.yaml renamed successfully. -./azure/azure_mssql_managed_instance_vulnerability_assessment_enabled.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_app_service_plan_mandatory.yaml renamed successfully. -./azure/azure_cis_v140_2_4.yaml renamed successfully. -./azure/azure_monitor_log_alert_delete_nsg.yaml renamed successfully. -./azure/azure_search_service_replica_count_3.yaml renamed successfully. -./azure/azure_cis_v140_9_11.yaml renamed successfully. -./azure/azure_cis_v130_3_10.yaml renamed successfully. -./azure/azure_cis_v210_8_2.yaml renamed successfully. -./azure/azure_cis_v140_7_7.yaml renamed successfully. -./azure/azure_sql_server_auditing_on.yaml renamed successfully. -./azure/azure_cis_v210_1_16.yaml renamed successfully. -./azure/azure_cis_v150_4_4_3.yaml renamed successfully. -./azure/azure_cis_v130_3_7.yaml renamed successfully. -./azure/azure_cis_v200_2_1_4.yaml renamed successfully. -./azure/azure_cis_v200_5_2_6.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_network_watcher_mandatory.yaml renamed successfully. -./azure/azure_appservice_function_app_restrict_public_acces.yaml renamed successfully. -./azure/azure_cis_v150_1_19.yaml renamed successfully. -./azure/azure_cis_v130_2_11.yaml renamed successfully. -./azure/azure_recovery_service_vault_uses_managed_identity.yaml renamed successfully. -./azure/azure_cis_v150_4_3_1.yaml renamed successfully. -./azure/azure_network_watcher_flow_log_enabled.yaml renamed successfully. -./azure/azure_iam_user_with_owner_permission_on_subscription_mfa_enabled.yaml renamed successfully. -./azure/azure_cis_v210_6_3.yaml renamed successfully. -./azure/azure_cis_v140_9_6.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_compute_snapshot_mandatory.yaml renamed successfully. -./azure/azure_appservice_web_app_incoming_client_cert_on.yaml renamed successfully. -./azure/azure_postgresql_server_public_network_access_disabled.yaml renamed successfully. -./azure/azure_cis_v200_5_1_3.yaml renamed successfully. -./azure/azure_cis_v200_2_2_1.yaml renamed successfully. -./azure/azure_cis_v130_9_1.yaml renamed successfully. -./azure/azure_cis_v150_8_8.yaml renamed successfully. -./azure/azure_appservice_ftp_deployment_disabled.yaml renamed successfully. -./azure/azure_compute_vm_guest_configuration_installed_windows.yaml renamed successfully. -./azure/azure_cis_v200_3_14.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_5432.yaml renamed successfully. -./azure/azure_databox_job_unlock_password_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_sql_server_and_databases_va_enabled.yaml renamed successfully. -./azure/azure_monitor_log_alert_create_update_nsg_rule.yaml renamed successfully. -./azure/azure_cis_v210_1_1_4.yaml renamed successfully. -./azure/azure_sql_database_transparent_data_encryption_enabled.yaml renamed successfully. -./azure/azure_kubernetes_cluster_restrict_public_access.yaml renamed successfully. -./azure/azure_cis_v150_2_1_7.yaml renamed successfully. -./azure/azure_cis_v150_5_2_5.yaml renamed successfully. -./azure/azure_cis_v140_1_1.yaml renamed successfully. -./azure/azure_cis_v140_8_2.yaml renamed successfully. -./azure/azure_cis_v210_7_7.yaml renamed successfully. -./azure/azure_sql_server_va_setting_periodic_scan_enabled.yaml renamed successfully. -./azure/azure_container_registry_vulnerabilities_remediated.yaml renamed successfully. -./azure/azure_compute_os_and_data_disk_encrypted_with_cmk_and_platform_managed.yaml renamed successfully. -./azure/azure_cis_v210_3_11.yaml renamed successfully. -./azure/azure_iam_external_user_with_read_permission.yaml renamed successfully. -./azure/azure_cis_v130_8_5.yaml renamed successfully. -./azure/azure_cis_v130_1_6.yaml renamed successfully. -./azure/azure_cis_v130_1_17.yaml renamed successfully. -./azure/azure_search_service_logging_enabled.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_compute_image_mandatory.yaml renamed successfully. -./azure/azure_cis_v210_5_1_6.yaml renamed successfully. -./azure/azure_cis_v200_8_4.yaml renamed successfully. -./azure/azure_compute_vm_tcp_udp_access_restricted_internet.yaml renamed successfully. -./azure/azure_cis_v150_7_1.yaml renamed successfully. -./azure/azure_cis_v200_1_7.yaml renamed successfully. -./azure/azure_cis_v210_4_5_1.yaml renamed successfully. -./azure/azure_cis_v140_2_8.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_5500.yaml renamed successfully. -./azure/azure_synapse_workspace_data_exfiltration_protection_enabled.yaml renamed successfully. -./azure/azure_appservice_web_app_diagnostic_logs_enabled.yaml renamed successfully. -./azure/azure_cis_v150_3_12.yaml renamed successfully. -./azure/azure_network_virtual_network_gateway_no_basic_sku.yaml renamed successfully. -./azure/azure_appservice_web_app_slot_use_https.yaml renamed successfully. -./azure/azure_keyvault_firewall_enabled.yaml renamed successfully. -./azure/azure_cis_v150_3_6.yaml renamed successfully. -./azure/azure_cis_v130_1_21.yaml renamed successfully. -./azure/azure_datalake_store_account_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v150_2_1_12.yaml renamed successfully. -./azure/azure_storage_account_geo_redundant_enabled.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_tcp_port_5900.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_eventhub_namespace_mandatory.yaml renamed successfully. -./azure/azure_sql_server_azure_ad_authentication_enabled.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_sql_server_mandatory.yaml renamed successfully. -./azure/azure_cis_v130_5_2_3.yaml renamed successfully. -./azure/azure_cis_v200_2_1_8.yaml renamed successfully. -./azure/azure_stream_analytics_job_logging_enabled.yaml renamed successfully. -./azure/azure_network_security_group_rdp_access_restricted.yaml renamed successfully. -./azure/azure_cis_v200_1_1_1.yaml renamed successfully. -./azure/azure_network_subnet_protected_by_firewall.yaml renamed successfully. -./azure/azure_cis_v200_3_6.yaml renamed successfully. -./azure/azure_cis_v210_2_1_11.yaml renamed successfully. -./azure/azure_cis_v150_1_15.yaml renamed successfully. -./azure/azure_compute_vm_attached_with_network.yaml renamed successfully. -./azure/azure_cis_v210_4_3_7.yaml renamed successfully. -./azure/azure_cis_v150_8_4.yaml renamed successfully. -./azure/azure_cis_v200_7_1.yaml renamed successfully. -./azure/azure_cis_v150_1_7.yaml renamed successfully. -./azure/azure_cis_v200_1_2_4.yaml renamed successfully. -./azure/azure_iam_external_user_with_write_permission.yaml renamed successfully. -./azure/azure_appservice_web_app_use_https.yaml renamed successfully. -./azure/azure_cis_v200_1_25.yaml renamed successfully. -./azure/azure_compute_vm_system_updates_installed.yaml renamed successfully. -./azure/azure_cis_v140_5_1_5.yaml renamed successfully. -./azure/azure_servicebus_name_space_private_link_used.yaml renamed successfully. -./azure/azure_cis_v150_1_1_2.yaml renamed successfully. -./azure/azure_cis_v150_5_2_9.yaml renamed successfully. -./azure/azure_iam_external_user_with_owner_role.yaml renamed successfully. -./azure/azure_kubernetes_cluster_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v210_2_1_1.yaml renamed successfully. -./azure/azure_cis_v210_5_2_3.yaml renamed successfully. -./azure/azure_mandatory_sql_subscription_resource_group_mandatory.yaml renamed successfully. -./azure/azure_cis_v140_1_10.yaml renamed successfully. -./azure/azure_monitor_log_analytics_workspace_integrated_with_encrypted_storage_account.yaml renamed successfully. -./azure/azure_cis_v210_1_20.yaml renamed successfully. -./azure/azure_cis_v210_5_2_10.yaml renamed successfully. -./azure/azure_app_configuration_sku_standard.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_redis_cache_mandatory.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_virtual_network_mandatory.yaml renamed successfully. -./azure/azure_iam_user_not_allowed_to_create_tenants.yaml renamed successfully. -./azure/azure_appservice_web_app_latest_php_version.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_express_route_circuit_mandatory.yaml renamed successfully. -./azure/azure_cis_v210_1_21.yaml renamed successfully. -./azure/azure_network_security_group_restrict_inbound_icmp_port.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_key_vault_deleted_vault_mandatory.yaml renamed successfully. -./azure/azure_cis_v150_9_1.yaml renamed successfully. -./azure/azure_cis_v200_6_4.yaml renamed successfully. -./azure/azure_keyvault_vault_public_network_access_disabled.yaml renamed successfully. -./azure/azure_cis_v210_5_2_2.yaml renamed successfully. -./azure/azure_kubernetes_cluster_network_plugin_azure.yaml renamed successfully. -./azure/azure_cis_v140_1_11.yaml renamed successfully. -./azure/azure_appservice_function_app_latest_python_version.yaml renamed successfully. -./azure/azure_cis_v150_1_1_3.yaml renamed successfully. -./azure/azure_cis_v150_5_2_8.yaml renamed successfully. -./azure/azure_servicebus_namespace_azure_ad_authentication_enabled.yaml renamed successfully. -./azure/azure_kubernetes_cluster_pod_use_approved_host_network_and_port_range.yaml renamed successfully. -./azure/azure_compute_vm_jit_access_protected.yaml renamed successfully. -./azure/azure_cis_v150_8_5.yaml renamed successfully. -./azure/azure_compute_vm_monitor_missing_endpoint_protection_in_asc.yaml renamed successfully. -./azure/azure_keyvault_managed_hms_logging_enabled.yaml renamed successfully. -./azure/azure_compute_vm_restrict_remote_connection_from_accounts_without_password_linux.yaml renamed successfully. -./azure/azure_cis_v150_1_6.yaml renamed successfully. -./azure/azure_cis_v200_1_2_5.yaml renamed successfully. -./azure/azure_cis_v200_1_24.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_cosmosdb.yaml renamed successfully. -./azure/azure_iam_subscriptions_with_custom_roles_no_overly_permissive.yaml renamed successfully. -./azure/azure_cis_v150_1_14.yaml renamed successfully. -./azure/azure_monitor_log_alert_delete_sql_servers_firewall_rule.yaml renamed successfully. -./azure/azure_servicebus_namespace_logging_enabled.yaml renamed successfully. -./azure/azure_cis_v210_2_1_10.yaml renamed successfully. -./azure/azure_cis_v130_5_2_2.yaml renamed successfully. -./azure/azure_servicefabric_cluster_active_directory_authentication_enabled.yaml renamed successfully. -./azure/azure_cis_v200_2_1_9.yaml renamed successfully. -./azure/azure_sql_server_threat_detection_all_enabled.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_iothub_mandatory.yaml renamed successfully. -./azure/azure_compute_vm_meet_security_options_requirement_windows.yaml renamed successfully. -./azure/azure_storage_account_default_network_access_rule_denied.yaml renamed successfully. -./azure/azure_kubernetes_cluster_temp_disks_and_agent_node_pool_cache_encrypted_at_host.yaml renamed successfully. -./azure/azure_cis_v140_5_2_1.yaml renamed successfully. -./azure/azure_securitycenter_azure_defender_on_for_database.yaml renamed successfully. -./azure/azure_compute_vm_meet_system_audit_policies_requirement_windows.yaml renamed successfully. -./azure/azure_cis_v200_9_1.yaml renamed successfully. -./azure/azure_cis_v150_6_4.yaml renamed successfully. -./azure/azure_cis_v150_2_1_13.yaml renamed successfully. -./azure/azure_iam_no_custom_role.yaml renamed successfully. -./azure/azure_cis_v130_1_20.yaml renamed successfully. -./azure/azure_redis_cache_no_basic_sku.yaml renamed successfully. -./azure/azure_kubernetes_cluster_os_and_data_disks_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_data_factory_public_network_access_disabled.yaml renamed successfully. -./azure/azure_keyvault_secret_expiration_set.yaml renamed successfully. -./azure/azure_compute_vm_image_builder_uses_private_link.yaml renamed successfully. -./azure/azure_cis_v150_3_7.yaml renamed successfully. -./azure/azure_stream_analytics_job_encrypted_with_cmk.yaml renamed successfully. -./azure/azuread_user_should_have_mfa_enabled_with_azure_subscription_role_assignment.yaml renamed successfully. -./azure/azure_cis_v140_2_9.yaml renamed successfully. -./azure/azure_appservice_api_app_uses_managed_identity.yaml renamed successfully. -./azure/azure_cis_v150_1_2_6.yaml renamed successfully. -./azure/azure_cis_v200_8_5.yaml renamed successfully. -./azure/azure_container_registry_public_network_access_disabled.yaml renamed successfully. -./azure/azure_iam_user_with_write_permission_on_subscription_mfa_enabled.yaml renamed successfully. -./azure/azure_compute_vm_meet_firewall_properties_windows.yaml renamed successfully. -./azure/azure_compute_vm_scale_set_security_configuration_vulnerabilities_remediated.yaml renamed successfully. -./azure/azure_cis_v200_1_6.yaml renamed successfully. -./azure/azure_mysql_server_audit_logging_events_connection_set.yaml renamed successfully. -./azure/azure_mysql_server_private_link_used.yaml renamed successfully. -./azure/azure_appservice_web_app_use_virtual_service_endpoint.yaml renamed successfully. -./azure/azure_cis_v210_3_10.yaml renamed successfully. -./azure/azure_cis_v130_8_4.yaml renamed successfully. -./azure/azure_cis_v130_1_7.yaml renamed successfully. -./azure/azure_cis_v130_1_16.yaml renamed successfully. -./azure/azure_redis_cache_min_tls_1_2.yaml renamed successfully. -./azure/azure_recovery_service_vault_uses_private_link_for_backup.yaml renamed successfully. -./azure/azure_cognitive_account_restrict_public_access.yaml renamed successfully. -./azure/azure_compute_vm_min_password_length_14_windows.yaml renamed successfully. -./azure/azure_cis_v210_7_6.yaml renamed successfully. -./azure/azure_cis_v140_8_3.yaml renamed successfully. -./azure/azure_iam_user_with_read_permission_on_subscription_mfa_enabled.yaml renamed successfully. -./azure/azure_cis_v150_2_1_6.yaml renamed successfully. -./azure/azure_appservice_function_app_latest_java_version.yaml renamed successfully. -./azure/azure_cis_v150_5_2_4.yaml renamed successfully. -./azure/azure_cis_v200_4_4_1.yaml renamed successfully. -./azure/azure_kubernetes_instance_rbac_enabled.yaml renamed successfully. -./azure/azure_cis_v210_3_1.yaml renamed successfully. -./azure/azure_cis_v200_2_1_11.yaml renamed successfully. -./azure/azure_cis_v200_5_1_2.yaml renamed successfully. -./azure/azure_arc_kubernetes_cluster_azure_defender_extension_installed.yaml renamed successfully. -./azure/azure_storage_account_encryption_scopes_encrypted_at_rest_with_cmk.yaml renamed successfully. -./azure/azure_cis_v200_4_1_2.yaml renamed successfully. -./azure/azure_kubernetes_cluster_upgrade_channel.yaml renamed successfully. -./azure/azure_cis_v200_3_15.yaml renamed successfully. -./azure/azure_datalake_store_account_encryption_enabled.yaml renamed successfully. -./azure/azure_cis_v140_9_7.yaml renamed successfully. -./azure/azure_cis_v210_6_2.yaml renamed successfully. -./azure/azure_cis_v200_5_2_10.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_key_vault_secret_mandatory.yaml renamed successfully. -./azure/azure_cis_v130_4_4.yaml renamed successfully. -./azure/azure_cis_v210_10_1.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_kubernetes_cluster_mandatory.yaml renamed successfully. -./azure/azure_cis_v130_2_10.yaml renamed successfully. -./azure/azure_iam_conditional_access_mfa_enabled.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_recovery_services_vault_mandatory.yaml renamed successfully. -./azure/azure_cis_v140_3_1.yaml renamed successfully. -./azure/azure_appservice_function_app_authentication_on.yaml renamed successfully. -./azure/azure_appservice_function_app_only_https_accessible.yaml renamed successfully. -./azure/azure_appservice_web_app_health_check_enabled.yaml renamed successfully. -./azure/azure_servicefabric_cluster_protection_level_as_encrypt_and_sign.yaml renamed successfully. -./azure/azure_cis_v130_3_6.yaml renamed successfully. -./azure/azure_cis_v150_4_4_2.yaml renamed successfully. -./azure/azure_cis_v200_2_1_5.yaml renamed successfully. -./azure/azure_cis_v200_5_2_7.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_compute_disk_mandatory.yaml renamed successfully. -./azure/azure_appservice_api_app_remote_debugging_disabled.yaml renamed successfully. -./azure/azure_hpc_cache_encrypted_with_cmk.yaml renamed successfully. -./azure/azure_cis_v130_3_11.yaml renamed successfully. -./azure/azure_cis_v140_7_6.yaml renamed successfully. -./azure/azure_cis_v210_8_3.yaml renamed successfully. -./azure/azure_cis_v210_1_17.yaml renamed successfully. -./azure/azure_cis_v130_7_1.yaml renamed successfully. -./azure/azure_sql_server_atp_enabled.yaml renamed successfully. -./azure/azure_postgres_db_server_connection_throttling_on.yaml renamed successfully. -./azure/azure_cis_v140_2_5.yaml renamed successfully. -./azure/azure_compute_vm_administrators_group_with_no_specified_members_windows.yaml renamed successfully. -./azure/azure_cis_v130_2_2.yaml renamed successfully. -./azure/azure_redis_cache_in_virtual_network.yaml renamed successfully. -./azure/azure_kusto_cluster_encrypted_at_rest_with_cmk.yaml renamed successfully. -./azure/azure_cis_v150_1_22.yaml renamed successfully. -./azure/azure_mandatory_sql_resource_group_cosmosdb_sql_database_mandatory.yaml renamed successfully. -./azure/azure_cis_v200_1_12.yaml renamed successfully. -./azure/azure_mysql_db_server_geo_redundant_backup_enabled.yaml renamed successfully. -./azure/azure_cis_v210_9_7.yaml renamed successfully. -./azure/azure_cis_v140_6_2.yaml renamed successfully. -./azure/azure_container_registry_restrict_public_access.yaml renamed successfully. -./azure/azure_kubernetes_cluster_service_listen_to_allowed_ports.yaml renamed successfully. -./azure/azure_cis_v150_5_1_1.yaml renamed successfully. -./azure/azure_cis_v150_2_2_3.yaml renamed successfully. -./azure/azure_storage_account_trusted_microsoft_services_enabled.yaml renamed successfully. -./azure/azure_kubernetes_cluster_container_with_read_only_root_file_system.yaml renamed successfully. -./baseline/azure/storage_account/azure_disable_public_access_to_storage_accounts_with_blob_containers.yaml renamed successfully. -./baseline/azure/storage_account/azure_enable_trusted_microsoft_services_for_storage_account_access.yaml renamed successfully. -./baseline/azure/storage_account/azure_private_endpoint_in_use.yaml renamed successfully. -./baseline/azure/storage_account/azure_enable_blob_storage_lifecycle_management.yaml renamed successfully. -./baseline/azure/storage_account/azure_disable_anonymous_access_to_blob_containers.yaml renamed successfully. -./baseline/azure/storage_account/azure_enable_logging_for_azure_storage_table_service.yaml renamed successfully. -./baseline/azure/storage_account/azure_enable_immutable_blob_storage.yaml renamed successfully. -./baseline/azure/storage_account/azure_enable_infrastructure_encryption.yaml renamed successfully. -./baseline/azure/storage_account/azure_storage_account_encryption_using_customer_managed_keys.yaml renamed successfully. -./baseline/azure/storage_account/azure_enable_soft_delete_for_azure_blob_storage.yaml renamed successfully. -./baseline/azure/storage_account/azure_enable_logging_for_azure_storage_queue_service.yaml renamed successfully. -./baseline/azure/storage_account/azure_check_for_sufficient_soft_deleted_data_retention_period.yaml renamed successfully. -./baseline/azure/storage_account/azure_enable_secure_transfer_in_azure_storage.yaml renamed successfully. -./baseline/azure/storage_account/azure_configure_minimum_tls_version.yaml renamed successfully. -./baseline/azure/storage_account/azure_use_byok_for_storage_account_encryption.yaml renamed successfully. -./baseline/azure/storage_account/azure_check_for_publicly_accessible_web_containers.yaml renamed successfully. -./baseline/azure/storage_account/azure_enable_logging_for_azure_storage_blob_service.yaml renamed successfully. -./baseline/azure/storage_account/azure_limit_storage_account_access_by_ip_address.yaml renamed successfully. -./baseline/azure/storage_account/azure_restrict_default_network_access_for_storage_accounts.yaml renamed successfully. -./baseline/azure/monitor/azure_monitor_log_all_activities.yaml renamed successfully. -./baseline/azure/recovery_service/azure_recovery_service_vault_not_publicly_accessible_and_not_encrypted.yaml renamed successfully. -./baseline/azure/recovery_service/azure_recovery_service_vault_alert_for_job_failures_enabled.yaml renamed successfully. -./baseline/azure/KeyVault/azure_set_azure_secret_key_expiration.yaml renamed successfully. -./baseline/azure/KeyVault/azure_app_tier_customer_managed_key_in_use.yaml renamed successfully. -./baseline/azure/KeyVault/azure_enable_auditevent_logging_for_azure_key_vaults.yaml renamed successfully. -./baseline/azure/KeyVault/azure_web_tier_customer_managed_key_in_use.yaml renamed successfully. -./baseline/azure/KeyVault/azure_set_encryption_key_expiration.yaml renamed successfully. -./baseline/azure/KeyVault/azure_enable_trusted_microsoft_services_for_key_vault_access.yaml renamed successfully. -./baseline/azure/KeyVault/azure_check_for_allowed_certificate_key_types.yaml renamed successfully. -./baseline/azure/KeyVault/azure_database_tier_customer_managed_key_in_use.yaml renamed successfully. -./baseline/azure/KeyVault/azure_enable_ssl_certificate_auto_renewal.yaml renamed successfully. -./baseline/azure/KeyVault/azure_enable_certificate_transparency.yaml renamed successfully. -./baseline/azure/KeyVault/azure_restrict_default_network_access_for_azure_key_vaults.yaml renamed successfully. -./baseline/azure/KeyVault/azure_check_for_azure_key_vault_secrets_expiration_date.yaml renamed successfully. -./baseline/azure/KeyVault/azure_check_for_sufficient_certificate_auto_renewal_period.yaml renamed successfully. -./baseline/azure/KeyVault/azure_check_for_azure_key_vault_keys_expiration_date.yaml renamed successfully. -./baseline/azure/KeyVault/azure_enable_key_vault_recoverability.yaml renamed successfully. -./baseline/azure/KeyVault/azure_check_for_key_vault_full_administrator_permissions.yaml renamed successfully. -./baseline/azure/KeyVault/azure_check_for_certificate_minimum_key_size.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_accelerated_networking_for_virtual_machines.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_disk_encryption_for_boot_disk_volumes.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_backups_for_azure_virtual_machines.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_server_side_encryption_for_unattached_disk_using_cmk.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_usage_of_customer_managed_keys_for_virtual_hard_disk_encryption.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_encryption_for_web_tier_disk_volumes.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_approved_azure_machine_image_in_use.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_old_virtual_machine_disk_snapshots.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_guest_level_diagnostics_for_virtual_machines.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_usage_of_managed_disk_volumes_for_virtual_machines.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_sufficient_instant_restore_retention_period.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_usage_of_approved_extensions_only.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_installataion_for_latest_os_patches.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_autoscale_notifications.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_sufficient_daily_backup_retention_period.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_performance_diagnostics_for_azure_virtual_machines.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_ssh_authentication_type.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_disk_encryption_for_non_boot_disk_volumes.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_unattached_virtual_machine_disk_volumes.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_disks_should_use_standard_snapshots.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_virtual_machine_boot_diagnostics.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_unused_load_balancers.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_automatic_os_upgrades.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_zone_redundant_virtual_machine_scale_sets.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_associated_load_balancers.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_virtual_machine_access_using_microsoft_entra_id_authentication.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_instance_termination_notifications_for_virtual_machine_scale_sets.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_system_assigned_managed_identities.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_usage_of_byok_for_disk_volumes_encryption.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_usage_of_endpoint_protection.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_server_side_encryption_for_boot_disk_using_cmk.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_disk_encryption_for_unattached_disk_volumes.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_just_in_time_access_for_virtual_machines.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_desired_vm_sku_sizes.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_configure_health_monitoring.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_server_side_encryption_for_non_boot_disk_using_cmk.yaml renamed successfully. -./baseline/azure/virtual_machine/azure_check_for_automatic_instance_repairs.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_ssh_access.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_telnet_access.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_postgresql_database_access.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_smtp_access.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_oracle_database_access.yaml renamed successfully. -./baseline/azure/network/azure_review_network_interfaces_with_ip_forwarding_enabled.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_mysql_database_access.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_netbios_access.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_rdp_access.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_mongodb_access.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_udp_access.yaml renamed successfully. -./baseline/azure/network/azure_enable_azure_network_watcher.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_mssql_access.yaml renamed successfully. -./baseline/azure/network/azure_check_for_unrestricted_rpc_access.yaml renamed successfully. -./baseline/azure/network/azure_enable_ddos_standard_protection_for_virtual_networks.yaml renamed successfully. -./baseline/azure/aks/azure_secure_access_to_kubernetes_api_server_using_authorized_ip_address_ranges.yaml renamed successfully. -./baseline/azure/aks/azure_enable_defender_for_cloud_for_aks_clusters.yaml renamed successfully. -./baseline/azure/aks/azure_check_for_kubernetes_version.yaml renamed successfully. -./baseline/azure/aks/azure_use_azure_cni_add_on_for_managing_network_resources.yaml renamed successfully. -./baseline/azure/aks/azure_use_user_assigned_managed_identities_for_aks_clusters.yaml renamed successfully. -./baseline/azure/aks/azure_enable_kubernetes_role_based_access_control.yaml renamed successfully. -./baseline/azure/aks/azure_use_microsoft_entra_id_integration_for_aks_clusters.yaml renamed successfully. -./baseline/azure/aks/azure_kubernetes_api_version.yaml renamed successfully. -./baseline/azure/aks/azure_use_network_contributor_role_for_managing_azure_network_resources.yaml renamed successfully. -./baseline/azure/aks/azure_use_system_assigned_managed_identities_for_aks_clusters.yaml renamed successfully. -./baseline/azure/cosmosdb/azure_enable_automatic_failover.yaml renamed successfully. -./baseline/azure/app_services/azure_disable_plain_ftp_deployment.yaml renamed successfully. -./baseline/azure/sql/azure_enable_auditing_for_sql_servers.yaml renamed successfully. -./baseline/azure/sql/azure_check_for_unrestricted_sql_database_access.yaml renamed successfully. -./baseline/azure/sql/azure_enable_vulnerability_assessment_email_notifications_for_admins_and_subscription_owners.yaml renamed successfully. -./baseline/azure/sql/azure_check_for_sufficient_point_in_time_restore_pitr_backup_retention_period.yaml renamed successfully. -./baseline/azure/sql/azure_enable_in_transit_encryption_for_mysql_servers.yaml renamed successfully. -./baseline/azure/sql/azure_enable_auto_failover_groups.yaml renamed successfully. -./baseline/azure/sql/azure_enable_transparent_data_encryption_for_sql_managed_instance_using_customer_managed_keys.yaml renamed successfully. -./baseline/azure/sql/azure_enable_all_types_of_threat_detection_on_sql_servers.yaml renamed successfully. -./baseline/azure/sql/azure_sql_auditing_retention.yaml renamed successfully. -./baseline/azure/sql/azure_enable_vulnerability_assessment_periodic_recurring_scans.yaml renamed successfully. -./baseline/azure/sql/azure_enable_automatic_tuning_for_sql_database_servers.yaml renamed successfully. -./baseline/azure/sql/azure_configure_emails_for_vulnerability_assessment_scan_reports_and_alerts.yaml renamed successfully. -./baseline/azure/sql/azure_check_for_publicly_accessible_sql_servers.yaml renamed successfully. -./baseline/azure/sql/azure_use_microsoft_entra_admin_for_sql_authentication.yaml renamed successfully. -./baseline/azure/sql/azure_use_byok_for_transparent_data_encryption.yaml renamed successfully. -./baseline/azure/sql/azure_enable_vulnerability_assessment_for_microsoft_sql_servers.yaml renamed successfully. -./baseline/azure/sql/azure_restrict_default_network_access_for_azure_cosmos_db_accounts.yaml renamed successfully. -./baseline/azure/sql/azure_configure_audit_action_group_for_sql_server_auditing.yaml renamed successfully. -./baseline/azure/sql/azure_advanced_data_security_for_sql_servers.yaml renamed successfully. -./baseline/shared/cost/kaytu_mom_cost_growth_15.yaml renamed successfully. -./baseline/shared/cost/kaytu_connection_mom_cost_growth.yaml renamed successfully. -./baseline/aws/acm_certificate/aws_acm_certificates_with_wildcard_domain_names.yaml renamed successfully. -./baseline/aws/acm_certificate/aws_acm_certificates_renewal_7_days_before_expiration.yaml renamed successfully. -./baseline/aws/acm_certificate/aws_acm_certificates_validity.yaml renamed successfully. -./baseline/aws/acm_certificate/aws_acm_certificate_expired.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elbv2_glb_minimum_number_of_ec2_target_instances.yaml renamed successfully. -./baseline/aws/load_balancer/aws_unused_elastic_load_balancers.yaml renamed successfully. -./baseline/aws/load_balancer/aws_internet_facing_elbs.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elbv2_alb_security_group.yaml renamed successfully. -./baseline/aws/load_balancer/aws_enable_amazon_waf_integration_for_application_load_balancers.yaml renamed successfully. -./baseline/aws/load_balancer/aws_enable_support_for_grpc_protocol.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elbv2_access_log.yaml renamed successfully. -./baseline/aws/load_balancer/aws_configure_multiple_availability_zones_for_load_balancers.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elbv2_alb_security_policy.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elb_access_log.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elb_cross_zone_load_balancing_enabled.yaml renamed successfully. -./baseline/aws/load_balancer/aws_enable_cross_zone_load_balancing.yaml renamed successfully. -./baseline/aws/load_balancer/aws_internet_facing_elbv2s.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elbv2_alb_listener_security.yaml renamed successfully. -./baseline/aws/load_balancer/aws_unused_application_load_balancers.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elbv2_elastic_load_balancing_deletion_protection.yaml renamed successfully. -./baseline/aws/load_balancer/aws_enable_http_to_https_redirect_for_application_load_balancers.yaml renamed successfully. -./baseline/aws/load_balancer/aws_unused_gateway_load_balancers.yaml renamed successfully. -./baseline/aws/load_balancer/aws_configure_http_desync_mitigation_mode_for_application_load_balancers.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elb_connection_draining_enabled.yaml renamed successfully. -./baseline/aws/load_balancer/aws_enable_deletion_protection.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elbv2_nlb_listener_security.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elbv2_alb_minimum_number_of_ec2_target_instances.yaml renamed successfully. -./baseline/aws/load_balancer/aws_elb_insecure_ssl_protocols.yaml renamed successfully. -./baseline/aws/opensearch/aws_encryption_at_rest.yaml renamed successfully. -./baseline/aws/opensearch/aws_enable_audit_logs.yaml renamed successfully. -./baseline/aws/opensearch/aws_opensearch_version.yaml renamed successfully. -./baseline/aws/opensearch/aws_opensearch_domain_in_vpc.yaml renamed successfully. -./baseline/aws/opensearch/aws_opensearch_domain_encrypted_with_kms_cmks.yaml renamed successfully. -./baseline/aws/opensearch/aws_enable_in_transit_encryption.yaml renamed successfully. -./baseline/aws/opensearch/aws_tls_security_policy_version.yaml renamed successfully. -./baseline/aws/opensearch/aws_opensearch_slow_logs.yaml renamed successfully. -./baseline/aws/opensearch/aws_opensearch_node_to_node_encryption.yaml renamed successfully. -./baseline/aws/opensearch/aws_opensearch_zone_awareness_enabled.yaml renamed successfully. -./baseline/aws/opensearch/aws_opensearch_dedicated_master_enabled.yaml renamed successfully. -./baseline/aws/opensearch/aws_opensearch_domain_exposed.yaml renamed successfully. -./baseline/aws/opensearch/aws_opensearch_accessible_only_from_safelisted_ip_addresses.yaml renamed successfully. -./baseline/aws/ecr/aws_ecr_repository_exposed.yaml renamed successfully. -./baseline/aws/ecr/aws_lifecycle_policy_in_use.yaml renamed successfully. -./baseline/aws/ecr/aws_enable_scan_on_push_for_ecr_container_images.yaml renamed successfully. -./baseline/aws/ecr/aws_enable_cross_region_replication.yaml renamed successfully. -./baseline/aws/dynamoDb/aws_unused_dynamodb_table.yaml renamed successfully. -./baseline/aws/ecs/aws_ecs_task_log_driver_in_use.yaml renamed successfully. -./baseline/aws/ecs/aws_enable_cloudwatch_container_insights.yaml renamed successfully. -./baseline/aws/ecs/aws_check_for_amazon_ecs_service_placement_strategy.yaml renamed successfully. -./baseline/aws/ecs/aws_check_for_ecs_container_instance_agent_version.yaml renamed successfully. -./baseline/aws/ecs/aws_check_for_fargate_platform_version.yaml renamed successfully. -./baseline/aws/fsx/aws_use_kms_customer_master_keys_for_fsx_windows_file_server_file_systems.yaml renamed successfully. -./baseline/aws/ebs/aws_use_io2_not_io1.yaml renamed successfully. -./baseline/aws/ebs/aws_ebs_encrypted.yaml renamed successfully. -./baseline/aws/ebs/aws_ebs_snapshot_encrypted.yaml renamed successfully. -./baseline/aws/ebs/aws_ebs_volume_unused.yaml renamed successfully. -./baseline/aws/ebs/aws_ebs_public_snapshots.yaml renamed successfully. -./baseline/aws/ebs/aws_use_gp3_not_gp2.yaml renamed successfully. -./baseline/aws/ebs/aws_ebs_volumes_too_old_snapshots.yaml renamed successfully. -./baseline/aws/ebs/aws_ebs_volumes_attached_to_stopped_ec2_instances.yaml renamed successfully. -./baseline/aws/ebs/aws_ebs_encrypted_with_kms_customer_master_keys.yaml renamed successfully. -./baseline/aws/IAM/aws_ssh_public_keys_rotated_45_days.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_user_policies.yaml renamed successfully. -./baseline/aws/IAM/aws_root_mfa_enabled.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_policies_with_effect_set_to_allow_and_notaction.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_users_with_administrative_privileges.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_group_with_inline_policies.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_access_analyzer_in_use.yaml renamed successfully. -./baseline/aws/IAM/aws_mfa_device_deactivated.yaml renamed successfully. -./baseline/aws/IAM/aws_inactive_iam_console_user.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_users_unauthorized_to_edit_access_policies.yaml renamed successfully. -./baseline/aws/IAM/aws_root_account_access_keys_present.yaml renamed successfully. -./baseline/aws/IAM/aws_check_for_overly_permissive_iam_group_policies.yaml renamed successfully. -./baseline/aws/IAM/aws_enforce_infrastructure_as_code_using_iam_policies.yaml renamed successfully. -./baseline/aws/IAM/aws_credentials_last_used.yaml renamed successfully. -./baseline/aws/IAM/aws_allow_iam_users_to_change_their_own_password.yaml renamed successfully. -./baseline/aws/IAM/aws_check_for_individual_iam_users.yaml renamed successfully. -./baseline/aws/IAM/aws_unnecessary_ssh_public_keys.yaml renamed successfully. -./baseline/aws/IAM/aws_unnecessary_access_keys.yaml renamed successfully. -./baseline/aws/IAM/aws_expired_ssl_tls_certificate.yaml renamed successfully. -./baseline/aws/IAM/aws_access_keys_during_initial_iam_user_setup.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_user_password_expiry_30_days.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_password_policy.yaml renamed successfully. -./baseline/aws/IAM/aws_approved_ecs_execute_command_access.yaml renamed successfully. -./baseline/aws/IAM/aws_ssl_tls_certificate_expiry_30_days.yaml renamed successfully. -./baseline/aws/IAM/aws_unapproved_iam_policy_in_use.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_support_role.yaml renamed successfully. -./baseline/aws/IAM/aws_enable_mfa_for_iam_users_with_console_password.yaml renamed successfully. -./baseline/aws/IAM/aws_ssl_tls_certificate_expiry_x_days.yaml renamed successfully. -./baseline/aws/IAM/aws_unused_iam_group.yaml renamed successfully. -./baseline/aws/IAM/aws_canary_access_token.yaml renamed successfully. -./baseline/aws/IAM/aws_check_for_untrusted_cross_account_iam_roles.yaml renamed successfully. -./baseline/aws/IAM/aws_multi_account_centralized_management.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_user_with_password_and_access_keys.yaml renamed successfully. -./baseline/aws/IAM/aws_root_account_credentials_usage.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_groups_with_administrative_privileges.yaml renamed successfully. -./baseline/aws/IAM/aws_ec2_purchase_restriction.yaml renamed successfully. -./baseline/aws/IAM/aws_pre_heartbleed_server_certificates.yaml renamed successfully. -./baseline/aws/IAM/aws_cross_account_access_lacks_external_id_and_mfa.yaml renamed successfully. -./baseline/aws/IAM/aws_access_keys_rotated_x_days.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_server_certificate_size.yaml renamed successfully. -./baseline/aws/IAM/aws_check_for_iam_user_group_membership.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_access_analyzer_findings.yaml renamed successfully. -./baseline/aws/IAM/aws_valid_iam_identity_providers.yaml renamed successfully. -./baseline/aws/IAM/aws_access_keys_rotated_45_days.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_user_password_expiry_x_days.yaml renamed successfully. -./baseline/aws/IAM/aws_root_account_active_signing_certificates.yaml renamed successfully. -./baseline/aws/IAM/aws_check_that_only_safelisted_iam_users_exist.yaml renamed successfully. -./baseline/aws/IAM/aws_account_alternate_contacts.yaml renamed successfully. -./baseline/aws/IAM/aws_hardware_mfa_for_aws_root_account.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_role_policy_too_permissive.yaml renamed successfully. -./baseline/aws/IAM/aws_ssh_public_keys_rotated_x_days.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_policies_with_full_administrative_privileges.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_user_password_expiry_7_days.yaml renamed successfully. -./baseline/aws/IAM/aws_attach_policy_to_iam_roles_associated_with_app_tier_ec2_instances.yaml renamed successfully. -./baseline/aws/IAM/aws_ssh_public_keys_rotated_90_days.yaml renamed successfully. -./baseline/aws/IAM/aws_iam_user_no_policies.yaml renamed successfully. -./baseline/aws/eks/aws_enable_envelope_encryption_for_eks_kubernetes_secrets.yaml renamed successfully. -./baseline/aws/eks/aws_eks_cluster_endpoint_public_access.yaml renamed successfully. -./baseline/aws/eks/aws_enable_cloudtrail_logging_for_kubernetes_api_calls.yaml renamed successfully. -./baseline/aws/eks/aws_kubernetes_cluster_version.yaml renamed successfully. -./baseline/aws/eks/aws_use_aws_managed_policy_to_manage_networking_resources.yaml renamed successfully. -./baseline/aws/eks/aws_kubernetes_cluster_logging.yaml renamed successfully. -./baseline/aws/eks/aws_disable_remote_access_to_eks_cluster_node_groups.yaml renamed successfully. -./baseline/aws/eks/aws_eks_security_groups.yaml renamed successfully. -./baseline/aws/eks/aws_eks_cluster_node_group_iam_role_policies.yaml renamed successfully. -./baseline/aws/eks/aws_use_aws_managed_policy_to_access_amazon_ecr_repositories.yaml renamed successfully. -./baseline/aws/eks/aws_use_oidc_provider_for_authenticating_kubernetes_api_calls.yaml renamed successfully. -./baseline/aws/eks/aws_use_aws_managed_policy_to_manage_aws_resources.yaml renamed successfully. -./baseline/aws/vpc/aws_managed_nat_gateway_in_use.yaml renamed successfully. -./baseline/aws/vpc/aws_unrestricted_network_acl_outbound_traffic.yaml renamed successfully. -./baseline/aws/vpc/aws_vpc_endpoint_cross_account_access.yaml renamed successfully. -./baseline/aws/vpc/aws_unrestricted_network_acl_inbound_traffic.yaml renamed successfully. -./baseline/aws/vpc/aws_vpc_flow_logs_enabled.yaml renamed successfully. -./baseline/aws/vpc/aws_vpc_peering_connections_to_accounts_outside_aws_organization.yaml renamed successfully. -./baseline/aws/vpc/aws_unrestricted_inbound_traffic_on_remote_server_administration_ports.yaml renamed successfully. -./baseline/aws/vpc/aws_vpc_endpoints_in_use.yaml renamed successfully. -./baseline/aws/vpc/aws_vpc_endpoint_exposed.yaml renamed successfully. -./baseline/aws/backup/aws_dynamodb_instances_have_backup_withing_48_hours.yaml renamed successfully. -./baseline/aws/backup/aws_ec2_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml renamed successfully. -./baseline/aws/backup/aws_check_for_protected_amazon_backup_resource_types.yaml renamed successfully. -./baseline/aws/backup/aws_efs_files_have_backup_with_lifecyclepolicy_above_35_days.yaml renamed successfully. -./baseline/aws/backup/aws_efs_files_have_backup_withing_48_hours.yaml renamed successfully. -./baseline/aws/backup/aws_use_kms_customer_master_keys_for_aws_backup.yaml renamed successfully. -./baseline/aws/backup/aws_enable_alert_notifications_for_failed_backup_jobs.yaml renamed successfully. -./baseline/aws/backup/aws_backup_service_lifecycle_configuration.yaml renamed successfully. -./baseline/aws/backup/aws_rds_database_instances_must_have_a_minimum_acceptable_restore_time.yaml renamed successfully. -./baseline/aws/backup/aws_configure_aws_backup_vault_access_policy.yaml renamed successfully. -./baseline/aws/backup/aws_ebs_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml renamed successfully. -./baseline/aws/backup/aws_ec2_instances_have_backup_withing_48_hours.yaml renamed successfully. -./baseline/aws/backup/aws_dynamodb_instances_have_backup_with_lifecyclepolicy_above_35_days.yaml renamed successfully. -./baseline/aws/backup/aws_rds_database_instances_have_a_minimum_acceptable_backup_policy.yaml renamed successfully. -./baseline/aws/backup/aws_ebs_instances_have_backup_withing_rpo_period.yaml renamed successfully. -./baseline/aws/rds/aws_rds_default_port.yaml renamed successfully. -./baseline/aws/rds/aws_rds_instance_counts.yaml renamed successfully. -./baseline/aws/rds/aws_rds_public_snapshots.yaml renamed successfully. -./baseline/aws/rds/aws_instance_deletion_protection.yaml renamed successfully. -./baseline/aws/rds/aws_rds_desired_instance_type.yaml renamed successfully. -./baseline/aws/rds/aws_rds_encrypted_with_kms_customer_master_keys.yaml renamed successfully. -./baseline/aws/rds/aws_rotate_ssltls_certificates_for_database_instances.yaml renamed successfully. -./baseline/aws/rds/aws_rds_encryption_enabled.yaml renamed successfully. -./baseline/aws/rds/aws_aurora_database_cluster_activity_streams.yaml renamed successfully. -./baseline/aws/rds/aws_enable_rds_snapshot_encryption.yaml renamed successfully. -./baseline/aws/rds/aws_enable_aurora_cluster_copy_tags_to_snapshots.yaml renamed successfully. -./baseline/aws/rds/aws_db_instance_generation.yaml renamed successfully. -./baseline/aws/rds/aws_aurora_database_instance_accessibility.yaml renamed successfully. -./baseline/aws/rds/aws_log_exports.yaml renamed successfully. -./baseline/aws/rds/aws_instance_level_events_subscriptions.yaml renamed successfully. -./baseline/aws/rds/aws_rds_db_instance_no_public_subnet.yaml renamed successfully. -./baseline/aws/rds/aws_rds_multi_az.yaml renamed successfully. -./baseline/aws/rds/aws_security_groups_events_subscriptions.yaml renamed successfully. -./baseline/aws/rds/aws_backtrack.yaml renamed successfully. -./baseline/aws/rds/aws_enable_instance_storage_auto_scaling.yaml renamed successfully. -./baseline/aws/rds/aws_enable_serverless_log_exports.yaml renamed successfully. -./baseline/aws/rds/aws_rds_publicly_accessible.yaml renamed successfully. -./baseline/aws/rds/aws_cluster_deletion_protection.yaml renamed successfully. -./baseline/aws/rds/aws_performance_insights.yaml renamed successfully. -./baseline/aws/rds/aws_rds_automated_backups_enabled.yaml renamed successfully. -./baseline/aws/rds/aws_use_aws_backup_service_in_use_for_amazon_rds.yaml renamed successfully. -./baseline/aws/rds/aws_enable_aws_rds_transport_encryption.yaml renamed successfully. -./baseline/aws/rds/aws_rds_event_notifications.yaml renamed successfully. -./baseline/aws/efs/aws_kms_customer_master_keys_for_efs_encryption.yaml renamed successfully. -./baseline/aws/efs/aws_efs_encryption_enabled.yaml renamed successfully. -./baseline/aws/ec2/aws_unused_aws_ec2_key_pairs.yaml renamed successfully. -./baseline/aws/ec2/aws_ec2_instance_in_vpc.yaml renamed successfully. -./baseline/aws/ec2/aws_default_security_group_unrestricted.yaml renamed successfully. -./baseline/aws/ec2/aws_ec2_ami_too_old.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_ssh_access.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_oracle_access.yaml renamed successfully. -./baseline/aws/ec2/aws_require_imdsv2_for_ec2_instances.yaml renamed successfully. -./baseline/aws/ec2/aws_disable_public_ip_address_assignment_for_ec2_instances.yaml renamed successfully. -./baseline/aws/ec2/aws_unused_elastic_network_interfaces.yaml renamed successfully. -./baseline/aws/ec2/aws_ami_encryption.yaml renamed successfully. -./baseline/aws/ec2/aws_ec2_desired_instance_type.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_mongodb_access.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_cifs_access.yaml renamed successfully. -./baseline/aws/ec2/aws_security_group_name_prefixed_with_launch_wizard.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_icmp_access.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_opensearch_access.yaml renamed successfully. -./baseline/aws/ec2/aws_security_group_port_range.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_netbios_access.yaml renamed successfully. -./baseline/aws/ec2/aws_ec2_instance_not_in_public_subnet.yaml renamed successfully. -./baseline/aws/ec2/aws_unused_ami.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_mysql_access.yaml renamed successfully. -./baseline/aws/ec2/aws_ec2_instances_with_multiple_elastic_network_interfaces.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_mssql_access.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_security_group_ingress_on_uncommon_ports.yaml renamed successfully. -./baseline/aws/ec2/aws_ec2_instance_naming_conventions.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_rpc_access.yaml renamed successfully. -./baseline/aws/ec2/aws_default_security_groups_in_use.yaml renamed successfully. -./baseline/aws/ec2/aws_unrestricted_smtp_access.yaml renamed successfully. -./baseline/aws/ec2/aws_ec2_instance_termination_protection.yaml renamed successfully. -./baseline/aws/ec2/aws_ec2_instance_too_old.yaml renamed successfully. -./baseline/aws/ec2/aws_unassociated_elastic_ip_addresses.yaml renamed successfully. -./baseline/aws/ec2/aws_publicly_shared_ami.yaml renamed successfully. -./aws/aws_foundational_security_opensearch_1.yaml renamed successfully. -./aws/aws_cis_v140_3_9.yaml renamed successfully. -./aws/aws_foundational_security_cloudfront_8.yaml renamed successfully. -./aws/aws_cis_v200_2_1_2.yaml renamed successfully. -./aws/aws_ec2_instance_in_vpc.yaml renamed successfully. -./aws/aws_foundational_security_dynamodb_1.yaml renamed successfully. -./aws/aws_autoscaling_use_multiple_instance_types_in_multiple_az.yaml renamed successfully. -./aws/aws_cis_v130_3_11.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_2_1.yaml renamed successfully. -./aws/aws_cis_v300_1_7.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_8.yaml renamed successfully. -./aws/aws_ec2_network_interface_unused.yaml renamed successfully. -./aws/aws_foundational_security_s3_19.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_write_permission_on_critical_s3_configuration.yaml renamed successfully. -./aws/aws_opensearch_domain_audit_logging_enabled.yaml renamed successfully. -./aws/aws_redshift_cluster_no_default_admin_name.yaml renamed successfully. -./aws/aws_iam_account_password_policy_min_length_14.yaml renamed successfully. -./aws/aws_secretsmanager_secret_encrypted_with_kms_cmk.yaml renamed successfully. -./aws/aws_mandatory_sql_ebs_volume_mandatory.yaml renamed successfully. -./aws/aws_iam_user_console_access_mfa_enabled.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_10.yaml renamed successfully. -./aws/aws_cis_v200_5_5.yaml renamed successfully. -./aws/aws_es_domain_dedicated_master_nodes_min_3.yaml renamed successfully. -./aws/aws_cis_v150_3_3.yaml renamed successfully. -./aws/aws_iam_access_analyzer_enabled.yaml renamed successfully. -./aws/aws_cis_v200_1_12.yaml renamed successfully. -./aws/aws_account_part_of_organizations.yaml renamed successfully. -./aws/aws_vpc_security_group_restrict_ingress_redis_port.yaml renamed successfully. -./aws/aws_cis_v120_3_14.yaml renamed successfully. -./aws/aws_cis_v300_1_21.yaml renamed successfully. -./aws/aws_cis_v200_2_4_1.yaml renamed successfully. -./aws/aws_lambda_function_dead_letter_queue_configured.yaml renamed successfully. -./aws/aws_backup_vault_region_configured.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_cloud_log_tampering_access.yaml renamed successfully. -./aws/aws_iam_user_unused_credentials_45.yaml renamed successfully. -./aws/aws_cis_v200_1_2.yaml renamed successfully. -./aws/aws_foundational_security_ecs_4.yaml renamed successfully. -./aws/aws_cis_v200_2_3_3.yaml renamed successfully. -./aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_full_packets.yaml renamed successfully. -./aws/aws_iam_account_password_policy_strong_min_reuse_24.yaml renamed successfully. -./aws/aws_elb_application_lb_waf_enabled.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_11.yaml renamed successfully. -./aws/aws_cis_v130_1_16.yaml renamed successfully. -./aws/aws_foundational_security_docdb_1.yaml renamed successfully. -./aws/aws_kinesis_stream_server_side_encryption_enabled.yaml renamed successfully. -./aws/aws_cis_v150_2_1_1.yaml renamed successfully. -./aws/aws_cis_v300_3_6.yaml renamed successfully. -./aws/aws_s3_bucket_lifecycle_policy_enabled.yaml renamed successfully. -./aws/aws_foundational_security_s3_6.yaml renamed successfully. -./aws/aws_lambda_function_cloudtrail_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_iam_21.yaml renamed successfully. -./aws/aws_ebs_volume_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_cis_v120_1_13.yaml renamed successfully. -./aws/aws_foundational_security_redshift_2.yaml renamed successfully. -./aws/aws_cis_v150_1_2.yaml renamed successfully. -./aws/aws_mandatory_sql_accessanalyzer_analyzer_mandatory.yaml renamed successfully. -./aws/aws_vpc_security_group_allows_ingress_authorized_ports.yaml renamed successfully. -./aws/aws_athena_workgroup_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_iam_user_group_role_cloudshell_fullaccess_restricted.yaml renamed successfully. -./aws/aws_config_enabled_all_regions.yaml renamed successfully. -./aws/aws_iam_user_unused_credentials_90.yaml renamed successfully. -./aws/aws_foundational_security_redshift_10.yaml renamed successfully. -./aws/aws_mandatory_sql_ssm_parameter_mandatory.yaml renamed successfully. -./aws/aws_s3_bucket_default_encryption_enabled_kms.yaml renamed successfully. -./aws/aws_cis_v150_5_5.yaml renamed successfully. -./aws/aws_s3_bucket_event_notifications_enabled.yaml renamed successfully. -./aws/aws_cis_v200_3_3.yaml renamed successfully. -./aws/aws_ec2_instance_publicly_accessible_iam_profile_attached.yaml renamed successfully. -./aws/aws_foundational_security_rds_10.yaml renamed successfully. -./aws/aws_cloudfront_distribution_use_secure_cipher.yaml renamed successfully. -./aws/aws_cis_v150_1_18.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_1_4.yaml renamed successfully. -./aws/aws_cis_v130_3_2.yaml renamed successfully. -./aws/aws_foundational_security_elb_2.yaml renamed successfully. -./aws/aws_autoscaling_ec2_launch_configuration_no_sensitive_data.yaml renamed successfully. -./aws/aws_foundational_security_iam_2.yaml renamed successfully. -./aws/aws_cis_v140_3_5.yaml renamed successfully. -./aws/aws_cloudformation_stack_output_no_secrets.yaml renamed successfully. -./aws/aws_cis_v140_2_1_4.yaml renamed successfully. -./aws/aws_foundational_security_cloudfront_4.yaml renamed successfully. -./aws/aws_mandatory_sql_codecommit_repository_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_es_6.yaml renamed successfully. -./aws/aws_ec2_instance_uses_imdsv2.yaml renamed successfully. -./aws/aws_mandatory_sql_eventbridge_rule_mandatory.yaml renamed successfully. -./aws/aws_mandatory_sql_cloudfront_distribution_mandatory.yaml renamed successfully. -./aws/aws_cis_v130_1_20.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_new_group_creation_with_attached_policy_access.yaml renamed successfully. -./aws/aws_foundational_security_neptune_3.yaml renamed successfully. -./aws/aws_cis_v300_4_14.yaml renamed successfully. -./aws/aws_opensearch_domain_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_foundational_security_rds_8.yaml renamed successfully. -./aws/aws_cloudtrail_trail_logs_encrypted_with_kms_cmk.yaml renamed successfully. -./aws/aws_elb_application_lb_redirect_http_request_to_https.yaml renamed successfully. -./aws/aws_cis_v300_2_1_3.yaml renamed successfully. -./aws/aws_mandatory_sql_redshift_cluster_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_ecs_8.yaml renamed successfully. -./aws/aws_foundational_security_codebuild_1.yaml renamed successfully. -./aws/aws_foundational_security_sns_2.yaml renamed successfully. -./aws/aws_ec2_classic_lb_connection_draining_enabled.yaml renamed successfully. -./aws/aws_vpc_in_more_than_one_region.yaml renamed successfully. -./aws/aws_cloudtrail_trail_integrated_with_logs.yaml renamed successfully. -./aws/aws_sagemaker_endpoint_configuration_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_cloudfront_distribution_custom_origins_encryption_in_transit_enabled.yaml renamed successfully. -./aws/aws_foundational_security_elasticbeanstalk_1.yaml renamed successfully. -./aws/aws_cis_v140_1_4.yaml renamed successfully. -./aws/aws_docdb_cluster_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_redshift_cluster_maintenance_settings_check.yaml renamed successfully. -./aws/aws_mandatory_sql_eks_cluster_mandatory.yaml renamed successfully. -./aws/aws_opensearch_domain_updated_with_latest_service_software_version.yaml renamed successfully. -./aws/aws_rds_db_instance_postgres_not_exposed_to_local_file_read_vulnerability.yaml renamed successfully. -./aws/aws_es_domain_error_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_autoscaling_3.yaml renamed successfully. -./aws/aws_mandatory_sql_kinesis_firehose_delivery_stream_mandatory.yaml renamed successfully. -./aws/aws_cis_v130_1_3.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_5_2.yaml renamed successfully. -./aws/aws_gatewayv2_stage_access_logging_enabled.yaml renamed successfully. -./aws/aws_cis_v140_1_11.yaml renamed successfully. -./aws/aws_elasticache_cluster_auto_minor_version_upgrade_enabled.yaml renamed successfully. -./aws/aws_s3_bucket_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_elasticache_6.yaml renamed successfully. -./aws/aws_cis_v130_5_4.yaml renamed successfully. -./aws/aws_iam_policy_no_full_access_to_cloudtrail.yaml renamed successfully. -./aws/aws_backup_plan_region_configured.yaml renamed successfully. -./aws/aws_cis_v140_2_2_1.yaml renamed successfully. -./aws/aws_cis_v300_2_3_2.yaml renamed successfully. -./aws/aws_rds_db_cluster_multiple_az_enabled.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_6.yaml renamed successfully. -./aws/aws_cis_v300_1_17.yaml renamed successfully. -./aws/aws_glue_job_bookmarks_encryption_enabled.yaml renamed successfully. -./aws/aws_cis_v140_4_7.yaml renamed successfully. -./aws/aws_cis_v150_1_14.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_data_destruction_access.yaml renamed successfully. -./aws/aws_mandatory_sql_vpc_network_acl_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_waf_1.yaml renamed successfully. -./aws/aws_iam_policy_no_star_star.yaml renamed successfully. -./aws/aws_cloudfront_distribution_sni_enabled.yaml renamed successfully. -./aws/aws_vpc_subnet_auto_assign_public_ip_disabled.yaml renamed successfully. -./aws/aws_codebuild_project_environment_privileged_mode_disabled.yaml renamed successfully. -./aws/aws_lambda_function_restrict_public_access.yaml renamed successfully. -./aws/aws_foundational_security_ecs_12.yaml renamed successfully. -./aws/aws_cis_v150_1_15.yaml renamed successfully. -./aws/aws_cloudfront_distribution_logging_enabled.yaml renamed successfully. -./aws/aws_mandatory_sql_codebuild_project_mandatory.yaml renamed successfully. -./aws/aws_vpc_security_group_allows_ingress_to_cassandra_ports.yaml renamed successfully. -./aws/aws_efs_access_point_enforce_root_directory.yaml renamed successfully. -./aws/aws_cis_v300_1_16.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_7.yaml renamed successfully. -./aws/aws_log_metric_filter_iam_policy.yaml renamed successfully. -./aws/aws_ecr_repository_prohibit_public_access.yaml renamed successfully. -./aws/aws_foundational_security_acm_1.yaml renamed successfully. -./aws/aws_log_metric_filter_route_table.yaml renamed successfully. -./aws/aws_cis_v120_1_8.yaml renamed successfully. -./aws/aws_cis_v300_2_3_3.yaml renamed successfully. -./aws/aws_mandatory_sql_kms_key_mandatory.yaml renamed successfully. -./aws/aws_redshift_cluster_enhanced_vpc_routing_enabled.yaml renamed successfully. -./aws/aws_s3_bucket_restrict_public_read_access.yaml renamed successfully. -./aws/aws_ecs_cluster_no_registered_container_instance.yaml renamed successfully. -./aws/aws_foundational_security_kms_3.yaml renamed successfully. -./aws/aws_elb_application_classic_network_lb_prohibit_public_access.yaml renamed successfully. -./aws/aws_foundational_security_elasticache_7.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_passrole_and_lambda_invoke_function_access.yaml renamed successfully. -./aws/aws_sns_topic_policy_prohibit_subscription_access.yaml renamed successfully. -./aws/aws_emr_cluster_kerberos_enabled.yaml renamed successfully. -./aws/aws_cis_v140_5_2.yaml renamed successfully. -./aws/aws_cis_v140_1_10.yaml renamed successfully. -./aws/aws_foundational_security_autoscaling_2.yaml renamed successfully. -./aws/aws_cloudformation_stack_termination_protection_enabled.yaml renamed successfully. -./aws/aws_dms_endpoint_ssl_configured.yaml renamed successfully. -./aws/aws_s3_bucket_restrict_public_write_access.yaml renamed successfully. -./aws/aws_elasticache_replication_group_encryption_in_transit_enabled.yaml renamed successfully. -./aws/aws_cis_v130_1_2.yaml renamed successfully. -./aws/aws_log_metric_filter_root_login.yaml renamed successfully. -./aws/aws_foundational_security_ec2_7.yaml renamed successfully. -./aws/aws_mandatory_sql_cloudwatch_alarm_mandatory.yaml renamed successfully. -./aws/aws_elasticache_cluster_no_default_subnet_group.yaml renamed successfully. -./aws/aws_rds_db_cluster_iam_authentication_enabled.yaml renamed successfully. -./aws/aws_elb_application_gateway_network_lb_multiple_az_configured.yaml renamed successfully. -./aws/aws_cis_v140_1_5.yaml renamed successfully. -./aws/aws_foundational_security_secretsmanager_4.yaml renamed successfully. -./aws/aws_ec2_instance_not_use_multiple_enis.yaml renamed successfully. -./aws/aws_cis_v150_4_16.yaml renamed successfully. -./aws/aws_ec2_instance_attached_ebs_volume_delete_on_termination_enabled.yaml renamed successfully. -./aws/aws_elb_network_lb_tls_listener_security_policy_configured.yaml renamed successfully. -./aws/aws_neptune_db_cluster_automated_backup_enabled.yaml renamed successfully. -./aws/aws_foundational_security_ecs_9.yaml renamed successfully. -./aws/aws_foundational_security_rds_9.yaml renamed successfully. -./aws/aws_dynamodb_table_encrypted_with_kms.yaml renamed successfully. -./aws/aws_api_gateway_method_request_parameter_validated.yaml renamed successfully. -./aws/aws_ec2_instance_not_older_than_180_days.yaml renamed successfully. -./aws/aws_wafv2_web_acl_rule_attached.yaml renamed successfully. -./aws/aws_mandatory_sql_wafv2_ip_set_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_rds_27.yaml renamed successfully. -./aws/aws_foundational_security_elb_12.yaml renamed successfully. -./aws/aws_cis_v300_2_1_2.yaml renamed successfully. -./aws/aws_foundational_security_ec2_51.yaml renamed successfully. -./aws/aws_directory_service_certificate_expires_90_days.yaml renamed successfully. -./aws/aws_vpc_network_acl_unused.yaml renamed successfully. -./aws/aws_cis_v130_1_21.yaml renamed successfully. -./aws/aws_sagemaker_notebook_instance_in_vpc.yaml renamed successfully. -./aws/aws_cis_v300_2_4_1.yaml renamed successfully. -./aws/aws_foundational_security_neptune_2.yaml renamed successfully. -./aws/aws_foundational_security_fsx_1.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_5.yaml renamed successfully. -./aws/aws_elb_classic_lb_cross_zone_load_balancing_enabled.yaml renamed successfully. -./aws/aws_foundational_security_es_7.yaml renamed successfully. -./aws/aws_opensearch_domain_node_to_node_encryption_enabled.yaml renamed successfully. -./aws/aws_redshift_cluster_encryption_in_transit_enabled.yaml renamed successfully. -./aws/aws_apigateway_stage_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_iam_3.yaml renamed successfully. -./aws/aws_cis_v140_3_4.yaml renamed successfully. -./aws/aws_ecs_service_load_balancer_attached.yaml renamed successfully. -./aws/aws_foundational_security_cloudfront_5.yaml renamed successfully. -./aws/aws_cis_v130_3_3.yaml renamed successfully. -./aws/aws_neptune_db_cluster_snapshot_prohibit_public_access.yaml renamed successfully. -./aws/aws_foundational_security_dms_1.yaml renamed successfully. -./aws/aws_rds_db_instance_backup_retention_period_less_than_7.yaml renamed successfully. -./aws/aws_foundational_security_eks_8.yaml renamed successfully. -./aws/aws_sns_topic_policy_prohibit_public_access.yaml renamed successfully. -./aws/aws_iam_user_in_group.yaml renamed successfully. -./aws/aws_cis_v150_1_19.yaml renamed successfully. -./aws/aws_rds_db_cluster_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_rds_db_cluster_aurora_postgres_not_exposed_to_local_file_read_vulnerability.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_10_1.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_1_5.yaml renamed successfully. -./aws/aws_cloudfront_distribution_use_custom_ssl_certificate.yaml renamed successfully. -./aws/aws_cis_v150_5_4.yaml renamed successfully. -./aws/aws_cis_v200_3_2.yaml renamed successfully. -./aws/aws_iam_policy_unused.yaml renamed successfully. -./aws/aws_foundational_security_rds_11.yaml renamed successfully. -./aws/aws_vpc_gateway_endpoint_restrict_public_access.yaml renamed successfully. -./aws/aws_neptune_db_cluster_copy_tags_to_snapshot_enabled.yaml renamed successfully. -./aws/aws_acm_certificate_no_wildcard_domain_name.yaml renamed successfully. -./aws/aws_cis_v120_1_4.yaml renamed successfully. -./aws/aws_foundational_security_ssm_4.yaml renamed successfully. -./aws/aws_elb_application_classic_lb_logging_enabled.yaml renamed successfully. -./aws/aws_ecr_repository_image_scan_on_push_enabled.yaml renamed successfully. -./aws/aws_cis_v120_1_12.yaml renamed successfully. -./aws/aws_foundational_security_redshift_3.yaml renamed successfully. -./aws/aws_cis_v150_1_3.yaml renamed successfully. -./aws/aws_glacier_vault_restrict_public_access.yaml renamed successfully. -./aws/aws_mandatory_sql_ec2_classic_load_balancer_mandatory.yaml renamed successfully. -./aws/aws_ec2_instance_no_amazon_key_pair.yaml renamed successfully. -./aws/aws_efs_file_system_enforces_ssl.yaml renamed successfully. -./aws/aws_codebuild_project_source_repo_oauth_configured.yaml renamed successfully. -./aws/aws_ecs_task_definition_logging_enabled.yaml renamed successfully. -./aws/aws_eks_cluster_with_latest_kubernetes_version.yaml renamed successfully. -./aws/aws_foundational_security_networkfirewall_6.yaml renamed successfully. -./aws/aws_ec2_stopped_instance_30_days.yaml renamed successfully. -./aws/aws_kms_cmk_rotation_enabled.yaml renamed successfully. -./aws/aws_ec2_ami_restrict_public_access.yaml renamed successfully. -./aws/aws_mandatory_sql_inspector_assessment_template_mandatory.yaml renamed successfully. -./aws/aws_fsx_file_system_copy_tags_to_backup_and_volume_enabled.yaml renamed successfully. -./aws/aws_cloudfront_distribution_default_root_object_configured.yaml renamed successfully. -./aws/aws_sns_topic_policy_prohibit_publishing_access.yaml renamed successfully. -./aws/aws_organizational_tag_policies_enabled.yaml renamed successfully. -./aws/aws_vpc_security_group_restrict_ingress_rdp_all.yaml renamed successfully. -./aws/aws_mandatory_sql_wafv2_web_acl_mandatory.yaml renamed successfully. -./aws/aws_cis_v200_2_3_2.yaml renamed successfully. -./aws/aws_cloudwatch_log_group_retention_period_365.yaml renamed successfully. -./aws/aws_es_domain_audit_logging_enabled.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_10.yaml renamed successfully. -./aws/aws_cis_v130_1_17.yaml renamed successfully. -./aws/aws_kms_key_not_pending_deletion.yaml renamed successfully. -./aws/aws_elb_classic_lb_with_inbound_rule.yaml renamed successfully. -./aws/aws_cis_v200_1_3.yaml renamed successfully. -./aws/aws_foundational_security_ecs_5.yaml renamed successfully. -./aws/aws_cis_v200_1_13.yaml renamed successfully. -./aws/aws_acm_certificate_no_failed_certificate.yaml renamed successfully. -./aws/aws_vpc_security_group_allows_ingress_to_memcached_port.yaml renamed successfully. -./aws/aws_cis_v300_1_20.yaml renamed successfully. -./aws/aws_foundational_security_account_1.yaml renamed successfully. -./aws/aws_elb_listener_use_secure_ssl_cipher.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_11.yaml renamed successfully. -./aws/aws_cis_v200_5_4.yaml renamed successfully. -./aws/aws_foundational_security_sfn_1.yaml renamed successfully. -./aws/aws_dms_replication_instance_not_publicly_accessible.yaml renamed successfully. -./aws/aws_s3_bucket_policy_restricts_cross_account_permission_changes.yaml renamed successfully. -./aws/aws_cis_v150_3_2.yaml renamed successfully. -./aws/aws_elb_application_network_lb_use_listeners.yaml renamed successfully. -./aws/aws_route53_domain_privacy_protection_enabled.yaml renamed successfully. -./aws/aws_foundational_security_rds_5.yaml renamed successfully. -./aws/aws_log_metric_filter_disable_or_delete_cmk.yaml renamed successfully. -./aws/aws_cis_v120_3_5.yaml renamed successfully. -./aws/aws_foundational_security_ecr_1.yaml renamed successfully. -./aws/aws_cis_v300_1_6.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_9.yaml renamed successfully. -./aws/aws_secretsmanager_secret_unused_90_day.yaml renamed successfully. -./aws/aws_cis_v150_2_3_1.yaml renamed successfully. -./aws/aws_api_gatewayv2_route_authorization_type_configured.yaml renamed successfully. -./aws/aws_networkfirewall_stateless_rule_group_not_empty.yaml renamed successfully. -./aws/aws_cis_v130_3_10.yaml renamed successfully. -./aws/aws_mandatory_sql_rds_db_parameter_group_mandatory.yaml renamed successfully. -./aws/aws_cis_v200_2_1_3.yaml renamed successfully. -./aws/aws_docdb_cluster_instance_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_kms_key_decryption_restricted_in_iam_inline_policy.yaml renamed successfully. -./aws/aws_foundational_security_waf_10.yaml renamed successfully. -./aws/aws_rds_db_instance_events_subscription.yaml renamed successfully. -./aws/aws_cis_v140_3_8.yaml renamed successfully. -./aws/aws_cis_v140_3_10.yaml renamed successfully. -./aws/aws_cis_v130_3_4.yaml renamed successfully. -./aws/aws_autoscaling_launch_config_hop_limit.yaml renamed successfully. -./aws/aws_cloudfront_distribution_waf_enabled.yaml renamed successfully. -./aws/aws_lambda_function_use_latest_runtime.yaml renamed successfully. -./aws/aws_foundational_security_dms_6.yaml renamed successfully. -./aws/aws_appstream_fleet_idle_disconnect_timeout_600_seconds.yaml renamed successfully. -./aws/aws_cis_v130_2_1_1.yaml renamed successfully. -./aws/aws_foundational_security_ec2_17.yaml renamed successfully. -./aws/aws_foundational_security_elb_4.yaml renamed successfully. -./aws/aws_sns_topic_encrypted_at_rest.yaml renamed successfully. -./aws/aws_cloudtrail_trail_enabled.yaml renamed successfully. -./aws/aws_cis_v140_2_1_2.yaml renamed successfully. -./aws/aws_cis_v140_3_3.yaml renamed successfully. -./aws/aws_foundational_security_iam_4.yaml renamed successfully. -./aws/aws_cloudformation_stack_notifications_enabled.yaml renamed successfully. -./aws/aws_foundational_security_s3_13.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_2.yaml renamed successfully. -./aws/aws_foundational_security_config_1.yaml renamed successfully. -./aws/aws_mandatory_sql_elastic_beanstalk_application_mandatory.yaml renamed successfully. -./aws/aws_s3_bucket_enforces_ssl.yaml renamed successfully. -./aws/aws_cis_v140_4_14.yaml renamed successfully. -./aws/aws_rds_db_instance_multiple_az_enabled.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_management_level_access.yaml renamed successfully. -./aws/aws_vpc_security_group_restrict_ingress_kibana_port.yaml renamed successfully. -./aws/aws_dax_cluster_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_foundational_security_sagemaker_3.yaml renamed successfully. -./aws/aws_rds_db_instance_in_vpc.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_privilege_escalation_risk_access.yaml renamed successfully. -./aws/aws_foundational_security_neptune_5.yaml renamed successfully. -./aws/aws_foundational_security_emr_2.yaml renamed successfully. -./aws/aws_cis_v300_4_12.yaml renamed successfully. -./aws/aws_cis_v150_3_9.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_6_1.yaml renamed successfully. -./aws/aws_foundational_security_rds_20.yaml renamed successfully. -./aws/aws_emr_account_public_access_blocked.yaml renamed successfully. -./aws/aws_s3_bucket_protected_by_macie.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_6.yaml renamed successfully. -./aws/aws_rds_db_security_group_events_subscription.yaml renamed successfully. -./aws/aws_cis_v200_1_8.yaml renamed successfully. -./aws/aws_cis_v200_1_18.yaml renamed successfully. -./aws/aws_foundational_security_secretsmanager_3.yaml renamed successfully. -./aws/aws_cis_v140_1_2.yaml renamed successfully. -./aws/aws_foundational_security_autoscaling_5.yaml renamed successfully. -./aws/aws_acm_certificate_transparency_logging_enabled.yaml renamed successfully. -./aws/aws_es_domain_internal_user_database_enabled.yaml renamed successfully. -./aws/aws_foundational_security_apigateway_1.yaml renamed successfully. -./aws/aws_ecr_repository_lifecycle_policy_configured.yaml renamed successfully. -./aws/aws_cis_v130_1_5.yaml renamed successfully. -./aws/aws_foundational_security_cloudformation_1.yaml renamed successfully. -./aws/aws_efs_file_system_encrypted_with_cmk.yaml renamed successfully. -./aws/aws_eks_cluster_control_plane_audit_logging_enabled.yaml renamed successfully. -./aws/aws_route53_domain_expires_30_days.yaml renamed successfully. -./aws/aws_vpc_security_group_restrict_ingress_ssh_all.yaml renamed successfully. -./aws/aws_cis_v140_1_17.yaml renamed successfully. -./aws/aws_cis_v130_5_2.yaml renamed successfully. -./aws/aws_redshift_cluster_kms_enabled.yaml renamed successfully. -./aws/aws_iam_users_with_console_access_are_requried_to_have_MFA.yaml renamed successfully. -./aws/aws_cis_v120_1_19.yaml renamed successfully. -./aws/aws_foundational_security_redshift_8.yaml renamed successfully. -./aws/aws_cis_v150_1_8.yaml renamed successfully. -./aws/aws_cis_v300_1_11.yaml renamed successfully. -./aws/aws_rds_db_cluster_deletion_protection_enabled.yaml renamed successfully. -./aws/aws_ssm_managed_instance_compliance_association_compliant.yaml renamed successfully. -./aws/aws_cloudtrail_security_trail_enabled.yaml renamed successfully. -./aws/aws_cis_v150_1_12.yaml renamed successfully. -./aws/aws_rds_db_instance_backup_enabled.yaml renamed successfully. -./aws/aws_foundational_security_waf_7.yaml renamed successfully. -./aws/aws_iam_user_with_administrator_access_mfa_enabled.yaml renamed successfully. -./aws/aws_iam_managed_policy_attached_to_role.yaml renamed successfully. -./aws/aws_securityhub_enabled.yaml renamed successfully. -./aws/aws_cloudtrail_s3_data_events_enabled.yaml renamed successfully. -./aws/aws_log_metric_filter_network_acl.yaml renamed successfully. -./aws/aws_cis_v200_3_9.yaml renamed successfully. -./aws/aws_kinesis_firehose_delivery_stream_server_side_encryption_enabled.yaml renamed successfully. -./aws/aws_ec2_transit_gateway_auto_cross_account_attachment_disabled.yaml renamed successfully. -./aws/aws_foundational_security_opensearch_7.yaml renamed successfully. -./aws/aws_cloudtrail_multi_region_read_write_enabled.yaml renamed successfully. -./aws/aws_cis_v120_2_6.yaml renamed successfully. -./aws/aws_log_metric_filter_unauthorized_api.yaml renamed successfully. -./aws/aws_foundational_security_iam_8.yaml renamed successfully. -./aws/aws_mandatory_sql_route53_domain_mandatory.yaml renamed successfully. -./aws/aws_rds_db_instance_ca_certificate_expires_7_days.yaml renamed successfully. -./aws/aws_vpc_configured_to_use_vpc_endpoints.yaml renamed successfully. -./aws/aws_s3_bucket_mfa_delete_enabled.yaml renamed successfully. -./aws/aws_cis_v130_4_13.yaml renamed successfully. -./aws/aws_cis_v300_5_6.yaml renamed successfully. -./aws/aws_cis_v130_3_8.yaml renamed successfully. -./aws/aws_cis_v140_1_21.yaml renamed successfully. -./aws/aws_autoscaling_group_multiple_az_configured.yaml renamed successfully. -./aws/aws_cis_v200_2_1_4.yaml renamed successfully. -./aws/aws_rds_db_instance_cloudwatch_logs_enabled.yaml renamed successfully. -./aws/aws_rds_db_cluster_aurora_mysql_audit_logging_enabled.yaml renamed successfully. -./aws/aws_cis_v300_1_1.yaml renamed successfully. -./aws/aws_foundational_security_rds_2.yaml renamed successfully. -./aws/aws_mandatory_sql_vpc_vpn_connection_mandatory.yaml renamed successfully. -./aws/aws_kinesis_stream_encrypted_with_kms_cmk.yaml renamed successfully. -./aws/aws_cloudfront_distribution_origin_access_identity_enabled.yaml renamed successfully. -./aws/aws_guardduty_enabled.yaml renamed successfully. -./aws/aws_cis_v150_3_5.yaml renamed successfully. -./aws/aws_eks_cluster_endpoint_restrict_public_access.yaml renamed successfully. -./aws/aws_cis_v200_5_3.yaml renamed successfully. -./aws/aws_vpc_security_group_restricted_common_ports.yaml renamed successfully. -./aws/aws_cis_v200_1_14.yaml renamed successfully. -./aws/aws_cis_v120_3_12.yaml renamed successfully. -./aws/aws_foundational_security_ecs_2.yaml renamed successfully. -./aws/aws_cis_v200_1_4.yaml renamed successfully. -./aws/aws_sagemaker_model_in_vpc.yaml renamed successfully. -./aws/aws_iam_support_role.yaml renamed successfully. -./aws/aws_foundational_security_autoscaling_9.yaml renamed successfully. -./aws/aws_cis_v130_1_10.yaml renamed successfully. -./aws/aws_foundational_security_route53_2.yaml renamed successfully. -./aws/aws_ebs_snapshot_encryption_enabled.yaml renamed successfully. -./aws/aws_iam_policy_no_full_access_to_kms.yaml renamed successfully. -./aws/aws_ec2_launch_template_not_publicly_accessible.yaml renamed successfully. -./aws/aws_foundational_security_cloudtrail_1.yaml renamed successfully. -./aws/aws_sagemaker_training_job_in_vpc.yaml renamed successfully. -./aws/aws_appstream_fleet_max_user_duration_36000_seconds.yaml renamed successfully. -./aws/aws_networkfirewall_firewall_deletion_protection_enabled.yaml renamed successfully. -./aws/aws_cis_v150_4_7.yaml renamed successfully. -./aws/aws_dms_replication_instance_automatic_minor_version_upgrade_enabled.yaml renamed successfully. -./aws/aws_vpc_security_group_restrict_ingress_common_ports_all.yaml renamed successfully. -./aws/aws_efs_file_system_restrict_public_access.yaml renamed successfully. -./aws/aws_emr_cluster_local_disk_encrypted_with_cmk.yaml renamed successfully. -./aws/aws_elastic_beanstalk_environment_logs_to_cloudwatch.yaml renamed successfully. -./aws/aws_cis_v150_1_4.yaml renamed successfully. -./aws/aws_dynamodb_table_point_in_time_recovery_enabled.yaml renamed successfully. -./aws/aws_cis_v120_1_15.yaml renamed successfully. -./aws/aws_foundational_security_redshift_4.yaml renamed successfully. -./aws/aws_cis_v200_2_2_1.yaml renamed successfully. -./aws/aws_s3_bucket_acls_should_prohibit_user_access.yaml renamed successfully. -./aws/aws_ebs_volume_unused.yaml renamed successfully. -./aws/aws_foundational_security_ssm_3.yaml renamed successfully. -./aws/aws_es_domain_node_to_node_encryption_enabled.yaml renamed successfully. -./aws/aws_cis_v120_1_3.yaml renamed successfully. -./aws/aws_foundational_security_efs_1.yaml renamed successfully. -./aws/aws_cis_v200_3_5.yaml renamed successfully. -./aws/aws_cis_v150_5_3.yaml renamed successfully. -./aws/aws_ebs_attached_volume_encryption_enabled.yaml renamed successfully. -./aws/aws_foundational_security_rds_16.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_1_2.yaml renamed successfully. -./aws/aws_ec2_stopped_instance_90_days.yaml renamed successfully. -./aws/aws_lambda_function_encryption_enabled.yaml renamed successfully. -./aws/aws_sqs_queue_encrypted_at_rest.yaml renamed successfully. -./aws/aws_iam_user_access_keys_and_password_at_setup.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_1_3.yaml renamed successfully. -./aws/aws_rds_db_cluster_events_subscription.yaml renamed successfully. -./aws/aws_cis_v200_3_4.yaml renamed successfully. -./aws/aws_cis_v150_5_2.yaml renamed successfully. -./aws/aws_foundational_security_rds_17.yaml renamed successfully. -./aws/aws_s3_bucket_versioning_and_lifecycle_policy_enabled.yaml renamed successfully. -./aws/aws_log_metric_filter_cloudtrail_configuration.yaml renamed successfully. -./aws/aws_foundational_security_ssm_2.yaml renamed successfully. -./aws/aws_cis_v120_1_2.yaml renamed successfully. -./aws/aws_ebs_volume_in_backup_plan.yaml renamed successfully. -./aws/aws_api_gateway_rest_api_public_endpoint_with_authorizer.yaml renamed successfully. -./aws/aws_cis_v150_1_5.yaml renamed successfully. -./aws/aws_fsx_file_system_protected_by_backup_plan.yaml renamed successfully. -./aws/aws_directory_service_directory_sns_notifications_enabled.yaml renamed successfully. -./aws/aws_iam_root_last_used.yaml renamed successfully. -./aws/aws_codebuild_project_artifact_encryption_enabled.yaml renamed successfully. -./aws/aws_foundational_security_ec2_20.yaml renamed successfully. -./aws/aws_foundational_security_s3_1.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_12.yaml renamed successfully. -./aws/aws_cis_v120_4_1.yaml renamed successfully. -./aws/aws_sfn_state_machine_logging_enabled.yaml renamed successfully. -./aws/aws_s3_bucket_policy_restrict_public_access.yaml renamed successfully. -./aws/aws_route53_domain_auto_renew_enabled.yaml renamed successfully. -./aws/aws_es_domain_in_vpc.yaml renamed successfully. -./aws/aws_cis_v130_1_11.yaml renamed successfully. -./aws/aws_cis_v130_1_8.yaml renamed successfully. -./aws/aws_rds_db_cluster_automatic_minor_version_upgrade_enabled.yaml renamed successfully. -./aws/aws_vpc_security_group_allows_ingress_to_oracle_ports.yaml renamed successfully. -./aws/aws_drs_job_enabled.yaml renamed successfully. -./aws/aws_foundational_security_ecs_3.yaml renamed successfully. -./aws/aws_cis_v200_1_5.yaml renamed successfully. -./aws/aws_cis_v200_1_15.yaml renamed successfully. -./aws/aws_cloudtrail_s3_logging_enabled.yaml renamed successfully. -./aws/aws_cis_v120_3_13.yaml renamed successfully. -./aws/aws_mandatory_sql_wafv2_rule_group_mandatory.yaml renamed successfully. -./aws/aws_networkfirewall_firewall_policy_default_stateless_action_check_fragmented_packets.yaml renamed successfully. -./aws/aws_cis_v150_3_4.yaml renamed successfully. -./aws/aws_elasticache_redis_cluster_automatic_backup_retention_15_days.yaml renamed successfully. -./aws/aws_cis_v200_5_2.yaml renamed successfully. -./aws/aws_foundational_security_rds_3.yaml renamed successfully. -./aws/aws_es_domain_logs_to_cloudwatch.yaml renamed successfully. -./aws/aws_rds_db_instance_connections_encryption_enabled.yaml renamed successfully. -./aws/aws_apigateway_rest_api_stage_use_ssl_certificate.yaml renamed successfully. -./aws/aws_docdb_cluster_instance_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_neptune_8.yaml renamed successfully. -./aws/aws_foundational_security_cloudfront_12.yaml renamed successfully. -./aws/aws_cis_v200_4_6.yaml renamed successfully. -./aws/aws_cis_v140_1_20.yaml renamed successfully. -./aws/aws_foundational_security_elb_9.yaml renamed successfully. -./aws/aws_foundational_security_dynamodb_6.yaml renamed successfully. -./aws/aws_foundational_security_opensearch_6.yaml renamed successfully. -./aws/aws_cis_v120_2_7.yaml renamed successfully. -./aws/aws_mandatory_sql_efs_file_system_mandatory.yaml renamed successfully. -./aws/aws_eks_cluster_no_multiple_security_groups.yaml renamed successfully. -./aws/aws_vpc_security_group_remote_administration.yaml renamed successfully. -./aws/aws_codebuild_project_plaintext_env_variables_no_sensitive_aws_values.yaml renamed successfully. -./aws/aws_cis_v200_3_8.yaml renamed successfully. -./aws/aws_ec2_client_vpn_endpoint_client_connection_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_eks_2.yaml renamed successfully. -./aws/aws_cis_v150_1_13.yaml renamed successfully. -./aws/aws_log_metric_filter_network_gateway.yaml renamed successfully. -./aws/aws_foundational_security_waf_6.yaml renamed successfully. -./aws/aws_dynamodb_table_protected_by_backup_plan.yaml renamed successfully. -./aws/aws_cis_v120_1_18.yaml renamed successfully. -./aws/aws_foundational_security_redshift_9.yaml renamed successfully. -./aws/aws_networkfirewall_firewall_logging_enabled.yaml renamed successfully. -./aws/aws_cis_v150_1_9.yaml renamed successfully. -./aws/aws_cis_v300_1_10.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_1.yaml renamed successfully. -./aws/aws_iam_server_certificate_not_expired.yaml renamed successfully. -./aws/aws_iam_user_console_access_unused_45.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_destruction_kms_access.yaml renamed successfully. -./aws/aws_mandatory_sql_sagemaker_model_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_elasticache_1.yaml renamed successfully. -./aws/aws_rds_db_cluster_aurora_backtracking_enabled.yaml renamed successfully. -./aws/aws_apigateway_rest_api_authorizers_configured.yaml renamed successfully. -./aws/aws_mandatory_sql_vpc_security_group_mandatory.yaml renamed successfully. -./aws/aws_mandatory_sql_lambda_function_mandatory.yaml renamed successfully. -./aws/aws_cis_v140_1_16.yaml renamed successfully. -./aws/aws_cis_v140_5_4.yaml renamed successfully. -./aws/aws_autoscaling_group_propagate_tags_to_ec2_instance_enabled.yaml renamed successfully. -./aws/aws_sagemaker_notebook_instance_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_appstream_fleet_default_internet_access_disabled.yaml renamed successfully. -./aws/aws_foundational_security_autoscaling_4.yaml renamed successfully. -./aws/aws_cis_v130_1_4.yaml renamed successfully. -./aws/aws_rds_db_instance_deletion_protection_enabled.yaml renamed successfully. -./aws/aws_rds_db_instance_in_backup_plan.yaml renamed successfully. -./aws/aws_ebs_snapshot_not_publicly_restorable.yaml renamed successfully. -./aws/aws_elb_classic_lb_no_registered_instance.yaml renamed successfully. -./aws/aws_sagemaker_training_job_inter_container_traffic_encryption_enabled.yaml renamed successfully. -./aws/aws_foundational_security_ec2_1.yaml renamed successfully. -./aws/aws_iam_user_no_inline_attached_policies.yaml renamed successfully. -./aws/aws_foundational_security_opensearch_10.yaml renamed successfully. -./aws/aws_elb_application_lb_desync_mitigation_mode.yaml renamed successfully. -./aws/aws_cis_v140_1_3.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_destruction_rds_access.yaml renamed successfully. -./aws/aws_cis_v300_2_2_1.yaml renamed successfully. -./aws/aws_foundational_security_secretsmanager_2.yaml renamed successfully. -./aws/aws_cis_v200_1_19.yaml renamed successfully. -./aws/aws_cis_v120_1_22.yaml renamed successfully. -./aws/aws_opensearch_domain_in_vpc.yaml renamed successfully. -./aws/aws_cis_v150_4_10.yaml renamed successfully. -./aws/aws_s3_bucket_not_accessible_to_all_authenticated_user.yaml renamed successfully. -./aws/aws_mandatory_sql_cloudtrail_trail_mandatory.yaml renamed successfully. -./aws/aws_opensearch_domain_data_node_fault_tolerance.yaml renamed successfully. -./aws/aws_foundational_security_rds_21.yaml renamed successfully. -./aws/aws_eks_cluster_secrets_encrypted.yaml renamed successfully. -./aws/aws_foundational_security_elb_14.yaml renamed successfully. -./aws/aws_vpc_security_group_remote_administration_ipv4.yaml renamed successfully. -./aws/aws_msk_cluster_encryption_in_transit_with_tls_enabled.yaml renamed successfully. -./aws/aws_mandatory_sql_eks_addon_mandatory.yaml renamed successfully. -./aws/aws_mandatory_sql_elastic_beanstalk_environment_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_kinesis_1.yaml renamed successfully. -./aws/aws_s3_bucket_cross_region_replication_enabled.yaml renamed successfully. -./aws/aws_redshift_cluster_encryption_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_lambda_1.yaml renamed successfully. -./aws/aws_cis_v150_3_8.yaml renamed successfully. -./aws/aws_cloudformation_stack_drift_detection_check.yaml renamed successfully. -./aws/aws_appsync_graphql_api_field_level_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_sagemaker_2.yaml renamed successfully. -./aws/aws_mandatory_sql_iam_server_certificate_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_neptune_4.yaml renamed successfully. -./aws/aws_ecs_task_definition_no_host_pid_mode.yaml renamed successfully. -./aws/aws_dynamodb_table_encryption_enabled.yaml renamed successfully. -./aws/aws_vpc_flow_logs_enabled.yaml renamed successfully. -./aws/aws_eventbridge_custom_bus_resource_based_policy_attached.yaml renamed successfully. -./aws/aws_elasticache_cluster_no_public_subnet.yaml renamed successfully. -./aws/aws_iam_role_no_administrator_access_policy_attached.yaml renamed successfully. -./aws/aws_foundational_security_s3_12.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_3.yaml renamed successfully. -./aws/aws_rds_db_instance_prohibit_public_access.yaml renamed successfully. -./aws/aws_docdb_cluster_deletion_protection_enabled.yaml renamed successfully. -./aws/aws_foundational_security_es_1.yaml renamed successfully. -./aws/aws_apigateway_stage_cache_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_cis_v140_2_1_3.yaml renamed successfully. -./aws/aws_cis_v140_3_2.yaml renamed successfully. -./aws/aws_foundational_security_iam_5.yaml renamed successfully. -./aws/aws_foundational_security_cloudfront_3.yaml renamed successfully. -./aws/aws_cis_v140_3_11.yaml renamed successfully. -./aws/aws_cis_v130_3_5.yaml renamed successfully. -./aws/aws_rds_db_cluster_copy_tags_to_snapshot_enabled.yaml renamed successfully. -./aws/aws_foundational_security_ec2_16.yaml renamed successfully. -./aws/aws_mandatory_sql_ec2_instance_mandatory.yaml renamed successfully. -./aws/aws_cloudfront_distribution_configured_with_origin_failover.yaml renamed successfully. -./aws/aws_foundational_security_rds_18.yaml renamed successfully. -./aws/aws_sagemaker_training_job_network_isolation_enabled.yaml renamed successfully. -./aws/aws_cis_v150_1_10.yaml renamed successfully. -./aws/aws_foundational_security_eks_1.yaml renamed successfully. -./aws/aws_cis_v200_1_20.yaml renamed successfully. -./aws/aws_ecr_repository_tag_immutability_enabled.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_2.yaml renamed successfully. -./aws/aws_rds_db_parameter_group_events_subscription.yaml renamed successfully. -./aws/aws_cloudtrail_bucket_not_public.yaml renamed successfully. -./aws/aws_foundational_security_elasticache_2.yaml renamed successfully. -./aws/aws_iam_role_unused_60.yaml renamed successfully. -./aws/aws_cis_v140_1_15.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_security_group_write_access.yaml renamed successfully. -./aws/aws_rds_db_instance_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_apigateway_3.yaml renamed successfully. -./aws/aws_sso_users_with_permission_assignments_are_required_to_have_MFA_on_AzureAD.yaml renamed successfully. -./aws/aws_cis_v130_1_7.yaml renamed successfully. -./aws/aws_lambda_function_tracing_enabled.yaml renamed successfully. -./aws/aws_ecs_cluster_container_instance_agent_connected.yaml renamed successfully. -./aws/aws_cloudtrail_trail_bucket_mfa_enabled.yaml renamed successfully. -./aws/aws_neptune_db_cluster_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_cis_v140_2_3_1.yaml renamed successfully. -./aws/aws_s3_bucket_static_website_hosting_disabled.yaml renamed successfully. -./aws/aws_waf_regional_web_acl_rule_attached.yaml renamed successfully. -./aws/aws_mandatory_sql_rds_db_cluster_parameter_group_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_ec2_2.yaml renamed successfully. -./aws/aws_cis_v120_1_21.yaml renamed successfully. -./aws/aws_mandatory_sql_dms_replication_instance_mandatory.yaml renamed successfully. -./aws/aws_vpc_endpoint_service_acceptance_required_enabled.yaml renamed successfully. -./aws/aws_foundational_security_secretsmanager_1.yaml renamed successfully. -./aws/aws_mandatory_sql_ecs_service_mandatory.yaml renamed successfully. -./aws/aws_cloudfront_distribution_no_non_existent_s3_origin.yaml renamed successfully. -./aws/aws_iam_root_user_no_access_keys.yaml renamed successfully. -./aws/aws_foundational_security_codebuild_5.yaml renamed successfully. -./aws/aws_iam_user_access_key_age_90.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_4.yaml renamed successfully. -./aws/aws_api_gatewayv2_route_authorizer_configured.yaml renamed successfully. -./aws/aws_rds_db_instance_protected_by_backup_plan.yaml renamed successfully. -./aws/aws_vpc_route_table_restrict_public_access_to_igw.yaml renamed successfully. -./aws/aws_foundational_security_rds_22.yaml renamed successfully. -./aws/aws_foundational_security_lambda_2.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_6_3.yaml renamed successfully. -./aws/aws_vpc_network_acl_remote_administration.yaml renamed successfully. -./aws/aws_s3_public_access_block_account.yaml renamed successfully. -./aws/aws_redshift_cluster_no_default_database_name.yaml renamed successfully. -./aws/aws_foundational_security_sagemaker_1.yaml renamed successfully. -./aws/aws_foundational_security_neptune_7.yaml renamed successfully. -./aws/aws_ec2_instance_termination_protection_enabled.yaml renamed successfully. -./aws/aws_foundational_security_rds_34.yaml renamed successfully. -./aws/aws_ec2_instance_user_data_no_secrets.yaml renamed successfully. -./aws/aws_foundational_security_es_2.yaml renamed successfully. -./aws/aws_mandatory_sql_rds_db_cluster_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_s3_11.yaml renamed successfully. -./aws/aws_neptune_db_cluster_snapshot_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_cloudfront_distribution_geo_restrictions_enabled.yaml renamed successfully. -./aws/aws_dynamodb_table_deletion_protection_enabled.yaml renamed successfully. -./aws/aws_cis_v120_2_8.yaml renamed successfully. -./aws/aws_foundational_security_elb_6.yaml renamed successfully. -./aws/aws_rds_db_instance_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_foundational_security_ec2_15.yaml renamed successfully. -./aws/aws_vpc_security_group_allows_ingress_to_mongodb_ports.yaml renamed successfully. -./aws/aws_s3_bucket_versioning_enabled.yaml renamed successfully. -./aws/aws_iam_policy_all_attached_no_star_star.yaml renamed successfully. -./aws/aws_cis_v130_3_6.yaml renamed successfully. -./aws/aws_autoscaling_group_with_lb_use_health_check.yaml renamed successfully. -./aws/aws_dynamodb_table_auto_scaling_enabled.yaml renamed successfully. -./aws/aws_codebuild_project_with_user_controlled_buildspec.yaml renamed successfully. -./aws/aws_neptune_db_cluster_iam_authentication_enabled.yaml renamed successfully. -./aws/aws_foundational_security_rds_14.yaml renamed successfully. -./aws/aws_acm_certificate_not_expired.yaml renamed successfully. -./aws/aws_lightsail_instance_ipv6_networking_disabled.yaml renamed successfully. -./aws/aws_vpc_default_security_group_restricts_all_traffic.yaml renamed successfully. -./aws/aws_cis_v130_4_8.yaml renamed successfully. -./aws/aws_foundational_security_efs_3.yaml renamed successfully. -./aws/aws_cis_v200_3_7.yaml renamed successfully. -./aws/aws_mandatory_sql_rds_db_subnet_group_mandatory.yaml renamed successfully. -./aws/aws_mandatory_sql_config_rule_mandatory.yaml renamed successfully. -./aws/aws_iam_root_user_mfa_enabled.yaml renamed successfully. -./aws/aws_foundational_security_ssm_1.yaml renamed successfully. -./aws/aws_cis_v120_1_1.yaml renamed successfully. -./aws/aws_waf_rule_group_rule_attached.yaml renamed successfully. -./aws/aws_cis_v200_3_11.yaml renamed successfully. -./aws/aws_foundational_security_redshift_6.yaml renamed successfully. -./aws/aws_neptune_db_cluster_deletion_protection_enabled.yaml renamed successfully. -./aws/aws_cis_v120_1_17.yaml renamed successfully. -./aws/aws_ecs_cluster_container_insights_enabled.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_11.yaml renamed successfully. -./aws/aws_cis_v140_1_19.yaml renamed successfully. -./aws/aws_cis_v120_4_2.yaml renamed successfully. -./aws/aws_foundational_security_networkfirewall_3.yaml renamed successfully. -./aws/aws_log_group_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_ecs_task_definition_container_non_privileged.yaml renamed successfully. -./aws/aws_es_domain_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_foundational_security_ec2_23.yaml renamed successfully. -./aws/aws_cis_v300_3_2.yaml renamed successfully. -./aws/aws_cis_v150_4_5.yaml renamed successfully. -./aws/aws_mandatory_sql_ecs_container_instance_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_appsync_2.yaml renamed successfully. -./aws/aws_iam_account_password_policy_one_symbol.yaml renamed successfully. -./aws/aws_mandatory_sql_directory_service_directory_mandatory.yaml renamed successfully. -./aws/aws_iam_account_password_policy_one_lowercase_letter.yaml renamed successfully. -./aws/aws_foundational_security_docdb_5.yaml renamed successfully. -./aws/aws_vpc_security_group_restrict_ingress_kafka_port.yaml renamed successfully. -./aws/aws_cis_v130_1_12.yaml renamed successfully. -./aws/aws_elb_tls_listener_protocol_version.yaml renamed successfully. -./aws/aws_cloudwatch_alarm_action_enabled_check.yaml renamed successfully. -./aws/aws_mandatory_sql_dax_cluster_mandatory.yaml renamed successfully. -./aws/aws_cloudtrail_multi_region_trail_enabled.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_8.yaml renamed successfully. -./aws/aws_iam_user_one_active_key.yaml renamed successfully. -./aws/aws_waf_regional_rule_group_rule_attached.yaml renamed successfully. -./aws/aws_rds_db_instance_iam_authentication_enabled.yaml renamed successfully. -./aws/aws_log_metric_filter_vpc.yaml renamed successfully. -./aws/aws_vpc_security_group_restrict_ingress_tcp_udp_all.yaml renamed successfully. -./aws/aws_mandatory_sql_sagemaker_notebook_instance_mandatory.yaml renamed successfully. -./aws/aws_mandatory_sql_dynamodb_table_mandatory.yaml renamed successfully. -./aws/aws_sagemaker_training_job_volume_and_data_encryption_enabled.yaml renamed successfully. -./aws/aws_iam_role_should_not_have_trust_to_cognito_full_access.yaml renamed successfully. -./aws/aws_wafv2_rule_group_logging_enabled.yaml renamed successfully. -./aws/aws_cis_v200_1_16.yaml renamed successfully. -./aws/aws_mandatory_sql_iam_user_mandatory.yaml renamed successfully. -./aws/aws_cis_v150_3_7.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_14.yaml renamed successfully. -./aws/aws_es_domain_cognito_authentication_enabled.yaml renamed successfully. -./aws/aws_secretsmanager_secret_last_used_1_day.yaml renamed successfully. -./aws/aws_log_metric_filter_security_group.yaml renamed successfully. -./aws/aws_iam_group_not_empty.yaml renamed successfully. -./aws/aws_cis_v300_1_3.yaml renamed successfully. -./aws/aws_iam_users_with_api_keys_should_have_keys_rotated_every_x_days.yaml renamed successfully. -./aws/aws_backup_recovery_point_min_retention_35_days.yaml renamed successfully. -./aws/aws_foundational_security_dms_8.yaml renamed successfully. -./aws/aws_foundational_security_ec2_19.yaml renamed successfully. -./aws/aws_ec2_instance_ssm_managed.yaml renamed successfully. -./aws/aws_sagemaker_notebook_instance_direct_internet_access_disabled.yaml renamed successfully. -./aws/aws_es_domain_encrypted_using_tls_1_2.yaml renamed successfully. -./aws/aws_redshift_cluster_automatic_upgrade_major_versions_enabled.yaml renamed successfully. -./aws/aws_foundational_security_opensearch_5.yaml renamed successfully. -./aws/aws_eks_cluster_endpoint_public_access_restricted.yaml renamed successfully. -./aws/aws_cis_v120_2_4.yaml renamed successfully. -./aws/aws_iam_custom_policy_unattached_no_star_star.yaml renamed successfully. -./aws/aws_route53_zone_query_logging_enabled.yaml renamed successfully. -./aws/aws_apigateway_rest_api_endpoint_restrict_public_access.yaml renamed successfully. -./aws/aws_ec2_instance_detailed_monitoring_enabled.yaml renamed successfully. -./aws/aws_s3_bucket_default_encryption_enabled.yaml renamed successfully. -./aws/aws_foundational_security_opensearch_4.yaml renamed successfully. -./aws/aws_cis_v120_2_5.yaml renamed successfully. -./aws/aws_foundational_security_dms_9.yaml renamed successfully. -./aws/aws_foundational_security_ec2_18.yaml renamed successfully. -./aws/aws_foundational_security_sqs_1.yaml renamed successfully. -./aws/aws_elastic_beanstalk_enhanced_health_reporting_enabled.yaml renamed successfully. -./aws/aws_ssm_managed_instance_compliance_patch_compliant.yaml renamed successfully. -./aws/aws_foundational_security_cloudfront_10.yaml renamed successfully. -./aws/aws_mandatory_sql_ec2_network_load_balancer_mandatory.yaml renamed successfully. -./aws/aws_rds_db_snapshot_encrypted_at_rest.yaml renamed successfully. -./aws/aws_cis_v300_5_5.yaml renamed successfully. -./aws/aws_sagemaker_model_network_isolation_enabled.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_2_4.yaml renamed successfully. -./aws/aws_autoscaling_group_no_suspended_process.yaml renamed successfully. -./aws/aws_rds_db_instance_and_cluster_no_default_port.yaml renamed successfully. -./aws/aws_mandatory_sql_rds_db_cluster_snapshot_mandatory.yaml renamed successfully. -./aws/aws_cis_v300_1_2.yaml renamed successfully. -./aws/aws_iam_inline_policy_no_administrative_privileges.yaml renamed successfully. -./aws/aws_ssm_document_prohibit_public_access.yaml renamed successfully. -./aws/aws_appstream_fleet_session_disconnect_timeout_300_seconds.yaml renamed successfully. -./aws/aws_opensearch_domain_cognito_authentication_enabled_for_kibana.yaml renamed successfully. -./aws/aws_cis_v150_3_6.yaml renamed successfully. -./aws/aws_mandatory_sql_secretsmanager_secret_mandatory.yaml renamed successfully. -./aws/aws_cis_v120_3_11.yaml renamed successfully. -./aws/aws_neptune_db_cluster_audit_logging_enabled.yaml renamed successfully. -./aws/aws_cis_v200_1_17.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_9.yaml renamed successfully. -./aws/aws_elb_application_lb_drop_http_headers.yaml renamed successfully. -./aws/aws_ssm_parameter_encryption_enabled.yaml renamed successfully. -./aws/aws_cis_v200_1_7.yaml renamed successfully. -./aws/aws_foundational_security_ecs_1.yaml renamed successfully. -./aws/aws_cis_v150_2_2_1.yaml renamed successfully. -./aws/aws_ebs_volume_protected_by_backup_plan.yaml renamed successfully. -./aws/aws_iam_user_access_key_unused_45.yaml renamed successfully. -./aws/aws_cis_v130_1_13.yaml renamed successfully. -./aws/aws_guardduty_finding_archived.yaml renamed successfully. -./aws/aws_cloudtrail_trail_insight_selectors_and_logging_enabled.yaml renamed successfully. -./aws/aws_ec2_instance_no_launch_wizard_security_group.yaml renamed successfully. -./aws/aws_foundational_security_docdb_4.yaml renamed successfully. -./aws/aws_cis_v300_3_3.yaml renamed successfully. -./aws/aws_cis_v150_2_1_4.yaml renamed successfully. -./aws/aws_elasticache_replication_group_auto_failover_enabled.yaml renamed successfully. -./aws/aws_foundational_security_cloudtrail_2.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_10.yaml renamed successfully. -./aws/aws_foundational_security_networkfirewall_2.yaml renamed successfully. -./aws/aws_cis_v140_1_18.yaml renamed successfully. -./aws/aws_mandatory_sql_rds_db_instance_mandatory.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_11_1.yaml renamed successfully. -./aws/aws_cis_v200_3_10.yaml renamed successfully. -./aws/aws_foundational_security_redshift_7.yaml renamed successfully. -./aws/aws_cis_v120_1_16.yaml renamed successfully. -./aws/aws_cis_v150_1_7.yaml renamed successfully. -./aws/aws_log_metric_filter_console_login_mfa.yaml renamed successfully. -./aws/aws_cloudwatch_alarm_action_enabled.yaml renamed successfully. -./aws/aws_ebs_volume_snapshot_exists.yaml renamed successfully. -./aws/aws_cloudtrail_multi_region_trail_integrated_with_logs.yaml renamed successfully. -./aws/aws_foundational_security_rds_15.yaml renamed successfully. -./aws/aws_log_metric_filter_organization.yaml renamed successfully. -./aws/aws_foundational_security_efs_2.yaml renamed successfully. -./aws/aws_cis_v200_3_6.yaml renamed successfully. -./aws/aws_foundational_security_waf_8.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_1_1.yaml renamed successfully. -./aws/aws_foundational_security_elb_7.yaml renamed successfully. -./aws/aws_root_accounts_needs_to_have_mfa.yaml renamed successfully. -./aws/aws_cis_v130_2_1_2.yaml renamed successfully. -./aws/aws_cis_v130_3_7.yaml renamed successfully. -./aws/aws_foundational_security_cloudfront_1.yaml renamed successfully. -./aws/aws_mandatory_sql_wafv2_regex_pattern_set_mandatory.yaml renamed successfully. -./aws/aws_cis_v120_2_9.yaml renamed successfully. -./aws/aws_foundational_security_opensearch_8.yaml renamed successfully. -./aws/aws_iam_security_audit_role.yaml renamed successfully. -./aws/aws_iam_policy_custom_no_assume_role.yaml renamed successfully. -./aws/aws_cis_v140_2_1_1.yaml renamed successfully. -./aws/aws_acm_certificate_no_pending_validation_certificate.yaml renamed successfully. -./aws/aws_foundational_security_es_3.yaml renamed successfully. -./aws/aws_foundational_security_s3_10.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_1.yaml renamed successfully. -./aws/aws_foundational_security_neptune_6.yaml renamed successfully. -./aws/aws_foundational_security_rds_35.yaml renamed successfully. -./aws/aws_codebuild_project_logging_enabled.yaml renamed successfully. -./aws/aws_mandatory_sql_ec2_gateway_load_balancer_mandatory.yaml renamed successfully. -./aws/aws_cis_v300_4_11.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_6_2.yaml renamed successfully. -./aws/aws_elb_classic_lb_multiple_az_configured.yaml renamed successfully. -./aws/aws_foundational_security_emr_1.yaml renamed successfully. -./aws/aws_vpc_security_group_remote_administration_ipv6.yaml renamed successfully. -./aws/aws_foundational_security_codebuild_4.yaml renamed successfully. -./aws/aws_vpc_security_group_associated_to_eni.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_5.yaml renamed successfully. -./aws/aws_mandatory_sql_vpc_nat_gateway_mandatory.yaml renamed successfully. -./aws/aws_opensearch_domain_logs_to_cloudwatch.yaml renamed successfully. -./aws/aws_cloudfront_distribution_no_deprecated_ssl_protocol.yaml renamed successfully. -./aws/aws_cis_v120_1_20.yaml renamed successfully. -./aws/aws_cloudformation_stack_rollback_enabled.yaml renamed successfully. -./aws/aws_vpc_security_group_unused.yaml renamed successfully. -./aws/aws_iam_account_password_policy_one_number.yaml renamed successfully. -./aws/aws_cis_v140_1_1.yaml renamed successfully. -./aws/aws_foundational_security_ec2_3.yaml renamed successfully. -./aws/aws_backup_recovery_point_manual_deletion_disabled.yaml renamed successfully. -./aws/aws_foundational_security_apigateway_2.yaml renamed successfully. -./aws/aws_vpc_peering_connection_no_cross_account_access.yaml renamed successfully. -./aws/aws_foundational_security_autoscaling_6.yaml renamed successfully. -./aws/aws_ec2_ebs_default_encryption_enabled.yaml renamed successfully. -./aws/aws_vpc_peering_connection_route_table_least_privilege.yaml renamed successfully. -./aws/aws_cis_v140_1_14.yaml renamed successfully. -./aws/aws_rds_db_instance_no_default_admin_name.yaml renamed successfully. -./aws/aws_ecs_task_definition_no_root_user.yaml renamed successfully. -./aws/aws_foundational_security_elasticache_3.yaml renamed successfully. -./aws/aws_cis_v150_4_8.yaml renamed successfully. -./aws/aws_rds_db_snapshot_prohibit_public_access.yaml renamed successfully. -./aws/aws_apigateway_stage_use_waf_web_acl.yaml renamed successfully. -./aws/aws_autoscaling_group_uses_ec2_launch_template.yaml renamed successfully. -./aws/aws_networkfirewall_firewall_in_vpc.yaml renamed successfully. -./aws/aws_cis_v200_1_21.yaml renamed successfully. -./aws/aws_guardduty_no_high_severity_findings.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_3.yaml renamed successfully. -./aws/aws_cis_v300_1_12.yaml renamed successfully. -./aws/aws_iam_account_password_policy_reuse_24.yaml renamed successfully. -./aws/aws_foundational_security_waf_4.yaml renamed successfully. -./aws/aws_cis_v150_1_11.yaml renamed successfully. -./aws/aws_vpc_not_in_use.yaml renamed successfully. -./aws/aws_ec2_instance_virtualization_type_no_paravirtual.yaml renamed successfully. -./aws/aws_foundational_security_rds_19.yaml renamed successfully. -./aws/aws_kms_cmk_policy_prohibit_public_access.yaml renamed successfully. -./aws/aws_directory_service_directory_snapshots_limit_2.yaml renamed successfully. -./aws/aws_waf_web_acl_logging_enabled.yaml renamed successfully. -./aws/aws_elb_classic_lb_with_outbound_rule.yaml renamed successfully. -./aws/aws_foundational_security_rds_12.yaml renamed successfully. -./aws/aws_s3_public_access_block_bucket_account.yaml renamed successfully. -./aws/aws_efs_file_system_protected_by_backup_plan.yaml renamed successfully. -./aws/aws_cloudfront_distribution_latest_tls_version.yaml renamed successfully. -./aws/aws_apigateway_rest_api_stage_xray_tracing_enabled.yaml renamed successfully. -./aws/aws_elb_classic_lb_use_tls_https_listeners.yaml renamed successfully. -./aws/aws_acmpca_root_certificate_authority_disabled.yaml renamed successfully. -./aws/aws_elb_classic_lb_desync_mitigation_mode.yaml renamed successfully. -./aws/aws_elasticache_replication_group_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_8.yaml renamed successfully. -./aws/aws_cis_v300_1_19.yaml renamed successfully. -./aws/aws_cis_v120_1_11.yaml renamed successfully. -./aws/aws_kms_cmk_unused.yaml renamed successfully. -./aws/aws_vpc_vpn_tunnel_up.yaml renamed successfully. -./aws/aws_mandatory_sql_s3_bucket_mandatory.yaml renamed successfully. -./aws/aws_ecs_cluster_no_active_services_count.yaml renamed successfully. -./aws/aws_cis_v120_4_4.yaml renamed successfully. -./aws/aws_foundational_security_networkfirewall_5.yaml renamed successfully. -./aws/aws_ec2_instance_ebs_optimized.yaml renamed successfully. -./aws/aws_ec2_instance_protected_by_backup_plan.yaml renamed successfully. -./aws/aws_cis_v150_4_3.yaml renamed successfully. -./aws/aws_cis_v300_3_4.yaml renamed successfully. -./aws/aws_sns_topic_notification_delivery_status_enabled.yaml renamed successfully. -./aws/aws_foundational_security_cloudtrail_5.yaml renamed successfully. -./aws/aws_mandatory_sql_ec2_application_load_balancer_mandatory.yaml renamed successfully. -./aws/aws_cis_v150_2_1_3.yaml renamed successfully. -./aws/aws_backup_recovery_point_encryption_enabled.yaml renamed successfully. -./aws/aws_route53_domain_not_expired.yaml renamed successfully. -./aws/aws_mandatory_sql_elasticache_cluster_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_ec2_8.yaml renamed successfully. -./aws/aws_cis_v130_1_14.yaml renamed successfully. -./aws/aws_foundational_security_apigateway_9.yaml renamed successfully. -./aws/aws_cis_v200_2_3_1.yaml renamed successfully. -./aws/aws_glue_connection_ssl_enabled.yaml renamed successfully. -./aws/aws_iam_policy_custom_attached_no_star_star.yaml renamed successfully. -./aws/aws_codebuild_project_build_greater_then_90_days.yaml renamed successfully. -./aws/aws_rds_db_cluster_aurora_protected_by_backup_plan.yaml renamed successfully. -./aws/aws_cis_v200_1_10.yaml renamed successfully. -./aws/aws_s3_public_access_block_bucket.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_12.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_elastic_ip_hijacking_access.yaml renamed successfully. -./aws/aws_backup_plan_min_retention_35_days.yaml renamed successfully. -./aws/aws_es_domain_data_nodes_min_3.yaml renamed successfully. -./aws/aws_mandatory_sql_ecr_repository_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_es_8.yaml renamed successfully. -./aws/aws_elb_application_lb_with_outbound_rule.yaml renamed successfully. -./aws/aws_cis_v150_2_3_2.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_attached_with_credentials_exposure_access.yaml renamed successfully. -./aws/aws_elb_application_network_lb_use_ssl_certificate.yaml renamed successfully. -./aws/aws_foundational_security_ecr_2.yaml renamed successfully. -./aws/aws_cis_v300_1_5.yaml renamed successfully. -./aws/aws_mandatory_sql_sagemaker_endpoint_configuration_mandatory.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_2_3.yaml renamed successfully. -./aws/aws_ebs_attached_volume_delete_on_termination_enabled.yaml renamed successfully. -./aws/aws_iam_account_password_policy_strong_min_length_8.yaml renamed successfully. -./aws/aws_efs_file_system_encrypt_data_at_rest.yaml renamed successfully. -./aws/aws_foundational_security_dynamodb_3.yaml renamed successfully. -./aws/aws_networkfirewall_firewall_policy_rule_group_not_empty.yaml renamed successfully. -./aws/aws_mandatory_sql_guardduty_detector_mandatory.yaml renamed successfully. -./aws/aws_cis_v200_4_3.yaml renamed successfully. -./aws/aws_cis_v300_5_2.yaml renamed successfully. -./aws/aws_lambda_function_concurrent_execution_limit_configured.yaml renamed successfully. -./aws/aws_foundational_security_opensearch_3.yaml renamed successfully. -./aws/aws_waf_web_acl_rule_attached.yaml renamed successfully. -./aws/aws_cis_v120_2_2.yaml renamed successfully. -./aws/aws_foundational_security_backup_1.yaml renamed successfully. -./aws/aws_mandatory_sql_elasticsearch_domain_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_waf_3.yaml renamed successfully. -./aws/aws_mandatory_sql_codepipeline_pipeline_mandatory.yaml renamed successfully. -./aws/aws_cis_v140_4_5.yaml renamed successfully. -./aws/aws_cis_v150_1_16.yaml renamed successfully. -./aws/aws_mandatory_sql_rds_db_snapshot_mandatory.yaml renamed successfully. -./aws/aws_sagemaker_notebook_instance_root_access_disabled.yaml renamed successfully. -./aws/aws_foundational_security_acm_2.yaml renamed successfully. -./aws/aws_cis_v300_1_15.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_4.yaml renamed successfully. -./aws/aws_rds_db_cluster_no_default_admin_name.yaml renamed successfully. -./aws/aws_efs_file_system_in_backup_plan.yaml renamed successfully. -./aws/aws_cis_v300_3_8.yaml renamed successfully. -./aws/aws_foundational_security_elasticache_4.yaml renamed successfully. -./aws/aws_kms_key_decryption_restricted_in_iam_customer_managed_policy.yaml renamed successfully. -./aws/aws_emr_cluster_encryption_at_rest_with_sse_kms.yaml renamed successfully. -./aws/aws_s3_bucket_object_lock_enabled.yaml renamed successfully. -./aws/aws_cloudfront_distribution_field_level_encryption_enabled.yaml renamed successfully. -./aws/aws_rds_db_instance_copy_tags_to_snapshot_enabled.yaml renamed successfully. -./aws/aws_cis_v140_5_1.yaml renamed successfully. -./aws/aws_foundational_security_networkfirewall_9.yaml renamed successfully. -./aws/aws_cis_v140_1_13.yaml renamed successfully. -./aws/aws_wafv2_web_acl_logging_enabled.yaml renamed successfully. -./aws/aws_waf_regional_rule_condition_attached.yaml renamed successfully. -./aws/aws_elastic_beanstalk_environment_managed_updates_enabled.yaml renamed successfully. -./aws/aws_foundational_security_s3_8.yaml renamed successfully. -./aws/aws_foundational_security_apigateway_5.yaml renamed successfully. -./aws/aws_cis_v130_1_1.yaml renamed successfully. -./aws/aws_sagemaker_notebook_instance_encrypted_with_kms_cmk.yaml renamed successfully. -./aws/aws_cis_v130_1_18.yaml renamed successfully. -./aws/aws_foundational_security_autoscaling_1.yaml renamed successfully. -./aws/aws_dms_certificate_not_expired.yaml renamed successfully. -./aws/aws_foundational_security_elasticbeanstalk_3.yaml renamed successfully. -./aws/aws_foundational_security_ec2_4.yaml renamed successfully. -./aws/aws_iam_account_password_policy_one_uppercase_letter.yaml renamed successfully. -./aws/aws_cloudfront_distribution_encryption_in_transit_enabled.yaml renamed successfully. -./aws/aws_foundational_security_codebuild_3.yaml renamed successfully. -./aws/aws_mandatory_sql_cloudwatch_log_group_mandatory.yaml renamed successfully. -./aws/aws_route53_domain_transfer_lock_enabled.yaml renamed successfully. -./aws/aws_cloudwatch_cross_account_sharing.yaml renamed successfully. -./aws/aws_foundational_security_pca_1.yaml renamed successfully. -./aws/aws_redshift_cluster_automatic_snapshots_min_7_days.yaml renamed successfully. -./aws/aws_secretsmanager_secret_rotated_as_scheduled.yaml renamed successfully. -./aws/aws_cis_v300_2_1_1.yaml renamed successfully. -./aws/aws_foundational_security_rds_24.yaml renamed successfully. -./aws/aws_elb_application_lb_deletion_protection_enabled.yaml renamed successfully. -./aws/aws_log_metric_filter_console_authentication_failure.yaml renamed successfully. -./aws/aws_api_gateway_method_authorization_type_configured.yaml renamed successfully. -./aws/aws_iam_policy_inline_no_blocked_kms_actions.yaml renamed successfully. -./aws/aws_log_metric_filter_config_configuration.yaml renamed successfully. -./aws/aws_cis_v150_3_11.yaml renamed successfully. -./aws/aws_redshift_cluster_audit_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_neptune_1.yaml renamed successfully. -./aws/aws_workspaces_workspace_volume_encryption_enabled.yaml renamed successfully. -./aws/aws_mandatory_sql_rds_db_option_group_mandatory.yaml renamed successfully. -./aws/aws_emr_cluster_master_nodes_no_public_ip.yaml renamed successfully. -./aws/aws_autoscaling_launch_config_public_ip_disabled.yaml renamed successfully. -./aws/aws_cis_v130_1_22.yaml renamed successfully. -./aws/aws_foundational_security_es_4.yaml renamed successfully. -./aws/aws_lambda_function_cloudwatch_insights_enabled.yaml renamed successfully. -./aws/aws_dynamodb_table_in_backup_plan.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_6.yaml renamed successfully. -./aws/aws_dms_replication_task_source_database_logging_enabled.yaml renamed successfully. -./aws/aws_foundational_security_cloudfront_6.yaml renamed successfully. -./aws/aws_iam_user_mfa_enabled.yaml renamed successfully. -./aws/aws_cis_v140_3_7.yaml renamed successfully. -./aws/aws_lambda_function_in_vpc.yaml renamed successfully. -./aws/aws_foundational_security_elb_1.yaml renamed successfully. -./aws/aws_mandatory_sql_vpc_eip_mandatory.yaml renamed successfully. -./aws/aws_cloudtrail_s3_object_read_events_audit_enabled.yaml renamed successfully. -./aws/aws_iam_all_policy_no_service_wild_card.yaml renamed successfully. -./aws/aws_foundational_security_cloudfront_7.yaml renamed successfully. -./aws/aws_foundational_security_athena_1.yaml renamed successfully. -./aws/aws_cis_v140_3_6.yaml renamed successfully. -./aws/aws_foundational_security_iam_1.yaml renamed successfully. -./aws/aws_foundational_security_es_5.yaml renamed successfully. -./aws/aws_route53_domain_expires_7_days.yaml renamed successfully. -./aws/aws_cis_v300_1_8.yaml renamed successfully. -./aws/aws_sqs_queue_dead_letter_queue_configured.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_7.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_org_write_access.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_6_4.yaml renamed successfully. -./aws/aws_cis_v150_3_10.yaml renamed successfully. -./aws/aws_foundational_security_elb_10.yaml renamed successfully. -./aws/aws_codebuild_project_s3_logs_encryption_enabled.yaml renamed successfully. -./aws/aws_foundational_security_rds_25.yaml renamed successfully. -./aws/aws_secretsmanager_secret_automatic_rotation_enabled.yaml renamed successfully. -./aws/aws_waf_web_acl_resource_associated.yaml renamed successfully. -./aws/aws_neptune_db_cluster_no_public_subnet.yaml renamed successfully. -./aws/aws_lambda_function_variables_no_sensitive_data.yaml renamed successfully. -./aws/aws_foundational_security_codebuild_2.yaml renamed successfully. -./aws/aws_ec2_instance_not_publicly_accessible.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_3.yaml renamed successfully. -./aws/aws_mandatory_sql_vpc_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_eventbridge_3.yaml renamed successfully. -./aws/aws_cis_v150_4_14.yaml renamed successfully. -./aws/aws_iam_policy_custom_no_permissive_role_assumption.yaml renamed successfully. -./aws/aws_foundational_security_sns_1.yaml renamed successfully. -./aws/aws_cis_v140_1_7.yaml renamed successfully. -./aws/aws_opensearch_domain_internal_user_database_disabled.yaml renamed successfully. -./aws/aws_foundational_security_apigateway_4.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_5_1.yaml renamed successfully. -./aws/aws_ecs_service_not_publicly_accessible.yaml renamed successfully. -./aws/aws_cis_v130_1_19.yaml renamed successfully. -./aws/aws_ecs_cluster_encryption_at_rest_enabled.yaml renamed successfully. -./aws/aws_sqs_queue_policy_prohibit_public_access.yaml renamed successfully. -./aws/aws_ecs_task_definition_container_readonly_root_filesystem.yaml renamed successfully. -./aws/aws_cis_v140_1_12.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_alter_critical_s3_permissions_configuration.yaml renamed successfully. -./aws/aws_iam_root_user_hardware_mfa_enabled.yaml renamed successfully. -./aws/aws_foundational_security_s3_9.yaml renamed successfully. -./aws/aws_cis_v300_3_9.yaml renamed successfully. -./aws/aws_foundational_security_elasticache_5.yaml renamed successfully. -./aws/aws_ec2_instance_iam_profile_attached.yaml renamed successfully. -./aws/aws_account_alternate_contact_security_registered.yaml renamed successfully. -./aws/aws_acm_certificate_expires_30_days.yaml renamed successfully. -./aws/aws_foundational_security_kms_1.yaml renamed successfully. -./aws/aws_cis_v300_2_3_1.yaml renamed successfully. -./aws/aws_mandatory_sql_ec2_reserved_instance_mandatory.yaml renamed successfully. -./aws/aws_elasticache_replication_group_redis_auth_enabled.yaml renamed successfully. -./aws/aws_autoscaling_launch_config_requires_imdsv2.yaml renamed successfully. -./aws/aws_cis_v130_2_2_1.yaml renamed successfully. -./aws/aws_glue_data_catalog_encryption_settings_metadata_encryption_enabled.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_5.yaml renamed successfully. -./aws/aws_glue_data_catalog_encryption_settings_password_encryption_enabled.yaml renamed successfully. -./aws/aws_cis_v300_1_14.yaml renamed successfully. -./aws/aws_foundational_security_waf_2.yaml renamed successfully. -./aws/aws_vpc_igw_attached_to_authorized_vpc.yaml renamed successfully. -./aws/aws_cis_v150_1_17.yaml renamed successfully. -./aws/aws_ec2_ami_ebs_encryption_enabled.yaml renamed successfully. -./aws/aws_athena_workgroup_enforce_configuration_enabled.yaml renamed successfully. -./aws/aws_foundational_security_ecs_10.yaml renamed successfully. -./aws/aws_lambda_function_cors_configuration.yaml renamed successfully. -./aws/aws_cis_v130_4_3.yaml renamed successfully. -./aws/aws_iam_group_user_role_no_inline_policies.yaml renamed successfully. -./aws/aws_dlm_ebs_snapshot_lifecycle_policy_enabled.yaml renamed successfully. -./aws/aws_sns_topic_policy_prohibit_cross_account_access.yaml renamed successfully. -./aws/aws_foundational_security_msk_1.yaml renamed successfully. -./aws/aws_rds_db_instance_automatic_minor_version_upgrade_enabled.yaml renamed successfully. -./aws/aws_opensearch_domain_https_required.yaml renamed successfully. -./aws/aws_foundational_security_opensearch_2.yaml renamed successfully. -./aws/aws_config_configuration_recorder_no_failed_deliver_logs.yaml renamed successfully. -./aws/aws_cis_v120_2_3.yaml renamed successfully. -./aws/aws_ecs_task_definition_container_environment_no_secret.yaml renamed successfully. -./aws/aws_foundational_security_waf_12.yaml renamed successfully. -./aws/aws_elb_classic_lb_use_ssl_certificate.yaml renamed successfully. -./aws/aws_foundational_security_dynamodb_2.yaml renamed successfully. -./aws/aws_cis_v200_2_1_1.yaml renamed successfully. -./aws/aws_cis_v300_5_3.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_with_write_level_access.yaml renamed successfully. -./aws/aws_secretsmanager_secret_last_changed_90_day.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_2_2.yaml renamed successfully. -./aws/aws_vpc_eip_associated.yaml renamed successfully. -./aws/aws_ecs_service_fargate_using_latest_platform_version.yaml renamed successfully. -./aws/aws_ec2_ami_not_older_than_90_days.yaml renamed successfully. -./aws/aws_cis_v150_2_3_3.yaml renamed successfully. -./aws/aws_eks_cluster_no_default_vpc.yaml renamed successfully. -./aws/aws_foundational_security_ecr_3.yaml renamed successfully. -./aws/aws_cis_v300_1_4.yaml renamed successfully. -./aws/aws_cloudtrail_s3_object_write_events_audit_enabled.yaml renamed successfully. -./aws/aws_foundational_security_rds_7.yaml renamed successfully. -./aws/aws_cis_v150_1_21.yaml renamed successfully. -./aws/aws_cis_v200_5_6.yaml renamed successfully. -./aws/aws_acm_certificate_rsa_key_length_2048_bits_or_greater.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_2_13.yaml renamed successfully. -./aws/aws_mandatory_sql_iam_role_mandatory.yaml renamed successfully. -./aws/aws_mq_broker_restrict_public_access.yaml renamed successfully. -./aws/aws_mandatory_sql_ebs_snapshot_mandatory.yaml renamed successfully. -./aws/aws_lambda_function_multiple_az_configured.yaml renamed successfully. -./aws/aws_cis_v200_1_11.yaml renamed successfully. -./aws/aws_emr_cluster_security_configuration_enabled.yaml renamed successfully. -./aws/aws_cloudtrail_trail_validation_enabled.yaml renamed successfully. -./aws/aws_cis_v200_1_1.yaml renamed successfully. -./aws/aws_waf_rule_condition_attached.yaml renamed successfully. -./aws/aws_mandatory_sql_route53_resolver_endpoint_mandatory.yaml renamed successfully. -./aws/aws_docdb_cluster_backup_retention_period_7_days.yaml renamed successfully. -./aws/aws_opensearch_domain_fine_grained_access_enabled.yaml renamed successfully. -./aws/aws_cis_v130_1_15.yaml renamed successfully. -./aws/aws_ec2_instance_no_iam_role_with_new_role_creation_with_attached_policy_access.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_3_12.yaml renamed successfully. -./aws/aws_sqs_queue_encrypted_with_kms_cmk.yaml renamed successfully. -./aws/aws_foundational_security_apigateway_8.yaml renamed successfully. -./aws/aws_secretsmanager_secret_automatic_rotation_lambda_enabled.yaml renamed successfully. -./aws/aws_ecs_task_definition_user_for_host_mode_check.yaml renamed successfully. -./aws/aws_foundational_security_ec2_9.yaml renamed successfully. -./aws/aws_foundational_security_docdb_2.yaml renamed successfully. -./aws/aws_iam_policy_custom_no_blocked_kms_actions.yaml renamed successfully. -./aws/aws_cis_v300_3_5.yaml renamed successfully. -./aws/aws_log_metric_filter_bucket_policy.yaml renamed successfully. -./aws/aws_foundational_security_cloudtrail_4.yaml renamed successfully. -./aws/aws_cis_v150_2_1_2.yaml renamed successfully. -./aws/aws_foundational_security_networkfirewall_4.yaml renamed successfully. -./aws/aws_foundational_security_s3_5.yaml renamed successfully. -./aws/aws_foundational_security_ec2_24.yaml renamed successfully. -./aws/aws_rds_db_instance_and_cluster_enhanced_monitoring_enabled.yaml renamed successfully. -./aws/aws_cis_v150_2_4_1.yaml renamed successfully. -./aws/aws_cis_v150_1_1.yaml renamed successfully. -./aws/aws_cis_v300_1_18.yaml renamed successfully. -./aws/aws_cis_compute_service_v100_4_9.yaml renamed successfully. -./aws/aws_s3_access_point_restrict_public_access.yaml renamed successfully. -./aws/aws_foundational_security_redshift_1.yaml renamed successfully. -./aws/aws_iam_user_no_policies.yaml renamed successfully. -./aws/aws_vpc_security_group_not_uses_launch_wizard_sg.yaml renamed successfully. -./aws/aws_efs_access_point_enforce_user_identity.yaml renamed successfully. -./aws/aws_mandatory_sql_api_gateway_stage_mandatory.yaml renamed successfully. -./aws/aws_foundational_security_rds_13.yaml renamed successfully. -./aws/aws_foundational_security_efs_4.yaml renamed successfully. -./aws/aws_redshift_cluster_prohibit_public_access.yaml renamed successfully. -./aws/aws_lambda_function_restrict_public_url.yaml renamed successfully. -./aws/aws_cis_v200_4_12.yaml renamed successfully. -./aws/aws_mandatory_sql_sagemaker_training_job_mandatory.yaml renamed successfully. -./aws/aws_cis_v140_4_8.yaml renamed successfully. -./aws/aws_elasticache_replication_group_encryption_at_rest_enabled_with_kms_cmk.yaml renamed successfully. -./aws/aws_cloudtrail_trail_enabled_account.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_1_1.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_3_3.yaml renamed successfully. -./pending/azure/azure_cis_v130_3_5.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_2_4.yaml renamed successfully. -./pending/azure/azure_cis_v210_1_3.yaml renamed successfully. -./pending/azure/azure_cis_v200_1_11.yaml renamed successfully. -./pending/azure/azure_cis_v130_5_1_4.yaml renamed successfully. -./pending/azure/azure_cis_v210_4_3_5.yaml renamed successfully. -./pending/azure/azure_cis_v200_9_10.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_2_1.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_2_2.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_3_6.yaml renamed successfully. -./pending/azure/azure_cis_v210_9_9.yaml renamed successfully. -./pending/azure/azure_cis_v200_8_7.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_3_4.yaml renamed successfully. -./pending/azure/azure_cis_v150_6_6.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_2_3.yaml renamed successfully. -./pending/azure/azure_cis_v210_4_3_4.yaml renamed successfully. -./pending/azure/azure_cis_v150_8_7.yaml renamed successfully. -./pending/azure/azure_cis_v200_6_6.yaml renamed successfully. -./pending/azure/azure_cis_v150_9_3.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_1_3.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_2_5.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_3_2.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_4_3.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_1_1.yaml renamed successfully. -./pending/azure/azure_cis_v210_4_3_3.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_2_4.yaml renamed successfully. -./pending/azure/azure_mariadb_server_private_link_used.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_3_3.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_2_1.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_4_4.yaml renamed successfully. -./pending/azure/azure_cis_v210_2_1_9.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_3_5.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_6.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_2_2.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_3_6.yaml renamed successfully. -./pending/azure/azure_cis_v150_5_1_4.yaml renamed successfully. -./pending/azure/azure_cis_v150_9_10.yaml renamed successfully. -./pending/azure/azure_cis_v210_8_7.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_2_3.yaml renamed successfully. -./pending/azure/azure_cis_v140_3_5.yaml renamed successfully. -./pending/azure/azure_iot_hub_private_link_used.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_3_4.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_1_6.yaml renamed successfully. -./pending/azure/azure_application_insights_linked_to_log_analytics_workspace.yaml renamed successfully. -./pending/azure/azure_cis_v210_4_1_3.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_2_5.yaml renamed successfully. -./pending/azure/azure_cis_v210_4_3_2.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_1_3.yaml renamed successfully. -./pending/azure/azure_cis_v140_1_8.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_3_2.yaml renamed successfully. -./pending/azure/azure_cis_v130_9_10.yaml renamed successfully. -./pending/azure/azure_cis_v210_4_4_3.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_2_5.yaml renamed successfully. -./pending/azure/azure_cis_v150_1_13.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_1_3.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_1_6.yaml renamed successfully. -./pending/azure/azure_cis_v140_6_5.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_3_4.yaml renamed successfully. -./pending/azure/azure_cis_v210_6_5.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_1_5.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_2_3.yaml renamed successfully. -./pending/azure/azure_cis_v210_3_17.yaml renamed successfully. -./pending/azure/azure_cis_v140_1_6.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_2_2.yaml renamed successfully. -./pending/azure/azure_cis_v200_5_1_4.yaml renamed successfully. -./pending/azure/azure_cis_v200_3_13.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_3_6.yaml renamed successfully. -./pending/azure/azure_monitor_logs_storage_container_insights_activity_logs_encrypted_with_byok.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_4_4.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_2_1.yaml renamed successfully. -./pending/azure/azure_storage_account_queues_logging_enabled.yaml renamed successfully. -./pending/azure/azure_cis_v140_6_4.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_1_1.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_2_4.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_3_3.yaml renamed successfully. -./pending/azure/azure_storage_account_containing_vhd_os_disk_cmk_encrypted.yaml renamed successfully. -./pending/azure/azure_cis_v210_4_1_1.yaml renamed successfully. -./pending/azure/azure_cis_v130_6_4.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_3_2.yaml renamed successfully. -./pending/azure/azure_monitor_logs_storage_container_insights_operational_logs_encrypted_with_byok.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_5.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_1_3.yaml renamed successfully. -./pending/azure/azure_cis_v200_2_1_10.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_2_5.yaml renamed successfully. -./pending/azure/azure_cis_v210_4_1_6.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_3_4.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_3_7.yaml renamed successfully. -./pending/azure/azure_cis_v150_6_5.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_2_3.yaml renamed successfully. -./pending/azure/azure_cis_v200_6_5.yaml renamed successfully. -./pending/azure/azure_cis_v140_5_1_4.yaml renamed successfully. -./pending/azure/azure_cis_v210_4_3_6.yaml renamed successfully. -./pending/azure/azure_cis_v200_3_7.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_2_2.yaml renamed successfully. -./pending/azure/azure_cis_v210_4_4_4.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_2_1.yaml renamed successfully. -./pending/azure/azure_cis_v130_4_3_6.yaml renamed successfully. -./pending/azure/azure_cis_v150_3_13.yaml renamed successfully. -./pending/azure/azure_cis_v140_4_3_5.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_2_4.yaml renamed successfully. -./pending/azure/azure_cis_v150_1_18.yaml renamed successfully. -./pending/azure/azure_appservice_web_app_worker_more_than_one.yaml renamed successfully. -./pending/azure/azure_compute_windows_vm_secure_boot_enabled.yaml renamed successfully. -./pending/azure/azure_cis_v140_9_10.yaml renamed successfully. -./pending/azure/azure_cis_v200_4_3_3.yaml renamed successfully. -./pending/azure/azure_postgres_db_server_log_duration_on.yaml renamed successfully. -./pending/azure/azure_cis_v150_4_1_1.yaml renamed successfully. -./pending/azure/azure_cis_v130_6_5.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_1.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_15.yaml renamed successfully. -./pending/aws/aws_foundational_security_rds_4.yaml renamed successfully. -./pending/aws/aws_cis_v120_3_4.yaml renamed successfully. -./pending/aws/aws_emr_cluster_encryption_at_rest_enabled.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_4.yaml renamed successfully. -./pending/aws/aws_ec2_instance_no_iam_role_with_defense_evasion_impact_of_aws_security_services_access.yaml renamed successfully. -./pending/aws/aws_redshift_cluster_encrypted_with_cmk.yaml renamed successfully. -./pending/aws/aws_cis_v140_1_8.yaml renamed successfully. -./pending/aws/aws_iam_password_policy_expire_90.yaml renamed successfully. -./pending/aws/aws_cis_v150_4_1.yaml renamed successfully. -./pending/aws/aws_cis_v120_1_5.yaml renamed successfully. -./pending/aws/aws_lightsail_instance_ssh_rdp_http_ports_disabled.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_11.yaml renamed successfully. -./pending/aws/aws_cis_compute_service_v100_3_4.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_12.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_8.yaml renamed successfully. -./pending/aws/aws_foundational_security_elb_13.yaml renamed successfully. -./pending/aws/aws_cis_v120_3_8.yaml renamed successfully. -./pending/aws/aws_s3_bucket_object_logging_enabled.yaml renamed successfully. -./pending/aws/aws_foundational_security_ec2_6.yaml renamed successfully. -./pending/aws/aws_cis_v140_5_3.yaml renamed successfully. -./pending/aws/aws_foundational_security_kms_2.yaml renamed successfully. -./pending/aws/aws_cis_v120_1_9.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_1.yaml renamed successfully. -./pending/aws/aws_codedeploy_deployment_group_lambda_allatonce_traffic_shift_disabled.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_6.yaml renamed successfully. -./pending/aws/aws_glue_dev_endpoint_cloudwatch_logs_encryption_enabled.yaml renamed successfully. -./pending/aws/aws_cis_v120_3_9.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_15.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_9.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_13.yaml renamed successfully. -./pending/aws/aws_cis_v140_2_1_5.yaml renamed successfully. -./pending/aws/aws_foundational_security_elb_3.yaml renamed successfully. -./pending/aws/aws_foundational_security_ec2_10.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_10.yaml renamed successfully. -./pending/aws/aws_cis_v300_3_7.yaml renamed successfully. -./pending/aws/aws_cis_v140_1_9.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_5.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_14.yaml renamed successfully. -./pending/aws/aws_cis_v300_5_1.yaml renamed successfully. -./pending/aws/aws_cis_v120_2_1.yaml renamed successfully. -./pending/aws/aws_foundational_security_cloudfront_9.yaml renamed successfully. -./pending/aws/aws_emr_cluster_local_disk_encryption_enabled.yaml renamed successfully. -./pending/aws/aws_cis_v150_4_11.yaml renamed successfully. -./pending/aws/aws_docdb_cluster_snapshot_restrict_public_access.yaml renamed successfully. -./pending/aws/aws_cis_v200_1_22.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_1.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_6.yaml renamed successfully. -./pending/aws/aws_iam_role_cross_account_read_only_access_policy.yaml renamed successfully. -./pending/aws/aws_ec2_instance_no_high_level_finding_in_inspector_scan.yaml renamed successfully. -./pending/aws/aws_foundational_security_cloudfront_13.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_7.yaml renamed successfully. -./pending/aws/aws_foundational_security_guardduty_1.yaml renamed successfully. -./pending/aws/aws_cis_v120_3_2.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_2.yaml renamed successfully. -./pending/aws/aws_rds_db_cluster_encrypted_with_cmk.yaml renamed successfully. -./pending/aws/aws_cis_v130_1_9.yaml renamed successfully. -./pending/aws/aws_foundational_security_ec2_21.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_16.yaml renamed successfully. -./pending/aws/aws_dms_replication_task_target_database_logging_enabled.yaml renamed successfully. -./pending/aws/aws_cis_v120_1_14.yaml renamed successfully. -./pending/aws/aws_cis_v150_4_6.yaml renamed successfully. -./pending/aws/aws_glue_dev_endpoint_s3_encryption_enabled.yaml renamed successfully. -./pending/aws/aws_cis_v300_3_1.yaml renamed successfully. -./pending/aws/aws_lightsail_instance_rdp_restricted_ip.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_3.yaml renamed successfully. -./pending/aws/aws_iam_access_analyzer_enabled_without_findings.yaml renamed successfully. -./pending/aws/aws_emr_cluster_encryption_at_rest_with_cse_cmk.yaml renamed successfully. -./pending/aws/aws_cis_v120_3_3.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_12.yaml renamed successfully. -./pending/aws/aws_cis_v130_3_9.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_7.yaml renamed successfully. -./pending/aws/aws_cis_v130_5_3.yaml renamed successfully. -./pending/aws/aws_rds_db_instance_no_public_subnet.yaml renamed successfully. -./pending/aws/aws_vpc_subnet_multi_az_enabled.yaml renamed successfully. -./pending/aws/aws_cis_compute_service_v100_2_7.yaml renamed successfully. -./pending/aws/aws_cis_v200_1_9.yaml renamed successfully. -./pending/aws/aws_cis_v300_2_1_4.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_13.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_15.yaml renamed successfully. -./pending/aws/aws_foundational_security_dms_7.yaml renamed successfully. -./pending/aws/aws_foundational_security_elb_5.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_4.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_3.yaml renamed successfully. -./pending/aws/aws_cis_v300_1_13.yaml renamed successfully. -./pending/aws/aws_cis_v150_4_9.yaml renamed successfully. -./pending/aws/aws_ec2_instance_no_iam_role_with_new_user_creation_with_attached_policy_access.yaml renamed successfully. -./pending/aws/aws_cis_v150_4_13.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_10.yaml renamed successfully. -./pending/aws/aws_foundational_security_iam_6.yaml renamed successfully. -./pending/aws/aws_cis_v140_3_1.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_9.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_15.yaml renamed successfully. -./pending/aws/aws_cis_v150_5_1.yaml renamed successfully. -./pending/aws/aws_guardduty_centrally_configured.yaml renamed successfully. -./pending/aws/aws_elb_application_lb_listener_certificate_expire_7_days.yaml renamed successfully. -./pending/aws/aws_cis_v150_1_6.yaml renamed successfully. -./pending/aws/aws_emr_cluster_encryption_in_transit_enabled.yaml renamed successfully. -./pending/aws/aws_foundational_security_s3_2.yaml renamed successfully. -./pending/aws/aws_cis_v150_2_1_5.yaml renamed successfully. -./pending/aws/aws_cis_v200_1_6.yaml renamed successfully. -./pending/aws/aws_cis_v120_3_10.yaml renamed successfully. -./pending/aws/aws_cis_v200_5_1.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_11.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_5.yaml renamed successfully. -./pending/aws/aws_cis_v300_5_4.yaml renamed successfully. -./pending/aws/aws_vpc_subnet_public_and_private.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_10.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_4.yaml renamed successfully. -./pending/aws/aws_cis_v120_3_1.yaml renamed successfully. -./pending/aws/aws_foundational_security_rds_1.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_1.yaml renamed successfully. -./pending/aws/aws_cis_v150_4_4.yaml renamed successfully. -./pending/aws/aws_elb_application_lb_listener_certificate_expire_30_days.yaml renamed successfully. -./pending/aws/aws_cis_v120_4_3.yaml renamed successfully. -./pending/aws/aws_foundational_security_s3_3.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_9.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_14.yaml renamed successfully. -./pending/aws/aws_glue_dev_endpoint_job_bookmarks_encryption_enabled.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_8.yaml renamed successfully. -./pending/aws/aws_foundational_security_iam_7.yaml renamed successfully. -./pending/aws/aws_foundational_security_rds_23.yaml renamed successfully. -./pending/aws/aws_cis_v150_4_12.yaml renamed successfully. -./pending/aws/aws_cis_v130_1_6.yaml renamed successfully. -./pending/aws/aws_cis_v130_5_1.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_2.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_5.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_13.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_9.yaml renamed successfully. -./pending/aws/aws_cis_v200_3_1.yaml renamed successfully. -./pending/aws/aws_cloudfront_distribution_non_s3_origins_encryption_in_transit_enabled.yaml renamed successfully. -./pending/aws/aws_ec2_instance_no_iam_role_with_database_management_write_access.yaml renamed successfully. -./pending/aws/aws_cis_v120_1_7.yaml renamed successfully. -./pending/aws/aws_foundational_security_ec2_25.yaml renamed successfully. -./pending/aws/aws_foundational_security_docdb_3.yaml renamed successfully. -./pending/aws/aws_cis_v150_1_20.yaml renamed successfully. -./pending/aws/aws_cis_v150_3_1.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_6.yaml renamed successfully. -./pending/aws/aws_cis_v120_3_6.yaml renamed successfully. -./pending/aws/aws_foundational_security_rds_6.yaml renamed successfully. -./pending/aws/aws_cis_v130_4_2.yaml renamed successfully. -./pending/aws/aws_backup_report_plan_configured.yaml renamed successfully. -./pending/aws/aws_ec2_instance_no_iam_role_with_write_access_to_resource_based_policies.yaml renamed successfully. -./pending/aws/aws_ecs_cluster_instance_in_vpc.yaml renamed successfully. -./pending/aws/aws_cis_v140_1_6.yaml renamed successfully. -./pending/aws/aws_cis_v150_4_15.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_16.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_10.yaml renamed successfully. -./pending/aws/aws_cis_v300_1_9.yaml renamed successfully. -./pending/aws/aws_lightsail_instance_ssh_restricted_ip.yaml renamed successfully. -./pending/aws/aws_cis_v130_3_1.yaml renamed successfully. -./pending/aws/aws_glue_job_cloudwatch_logs_encryption_enabled.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_11.yaml renamed successfully. -./pending/aws/aws_foundational_security_lambda_5.yaml renamed successfully. -./pending/aws/aws_cis_v140_4_4.yaml renamed successfully. -./pending/aws/aws_glue_job_s3_encryption_enabled.yaml renamed successfully. -./pending/aws/aws_cis_v200_4_2.yaml renamed successfully. -./pending/aws/aws_iam_user_hardware_mfa_enabled.yaml renamed successfully. -./pending/aws/aws_cis_v120_3_7.yaml renamed successfully. -./pending/aws/aws_cis_v300_4_7.yaml renamed successfully. -./pending/aws/aws_cis_v300_1_22.yaml renamed successfully. -./pending/aws/aws_cis_v150_4_2.yaml renamed successfully. -./pending/aws/aws_cis_v120_1_10.yaml renamed successfully. -./pending/aws/aws_cis_v120_1_6.yaml renamed successfully.